From a5dcc723f3634e7cc0b333798475140960581b01 Mon Sep 17 00:00:00 2001 From: Corbin McNeely-Smith <58151731+restingbull@users.noreply.github.com> Date: Sun, 13 Aug 2023 17:37:39 -0500 Subject: [PATCH 1/9] Allow bootstrap to use different versions of kotlinc. --- src/main/kotlin/bootstrap.bzl | 41 +++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/bootstrap.bzl b/src/main/kotlin/bootstrap.bzl index db7728d84..6a6bff9c9 100644 --- a/src/main/kotlin/bootstrap.bzl +++ b/src/main/kotlin/bootstrap.bzl @@ -30,7 +30,14 @@ def _resolve_dep_label(d): else: return d -def kt_bootstrap_library(name, srcs, visibility = [], deps = [], neverlink_deps = [], runtime_deps = []): +def kt_bootstrap_library( + name, + srcs, + visibility = [], + deps = [], + neverlink_deps = [], + runtime_deps = [], + kotlinc_repository_name = "com_github_jetbrains_kotlin"): """ Simple compilation of a kotlin library using a non-persistent worker. The target is a JavaInfo provider. @@ -41,6 +48,7 @@ def kt_bootstrap_library(name, srcs, visibility = [], deps = [], neverlink_deps deps: the dependenices, the are setup as runtime_deps of the library. neverlink_deps: deps that won't be linked. These deps are added to the `"for_ide"` target. """ + kotlinc_repository = "@" + kotlinc_repository_name jar_label = name + "_jar" dep_label = name + "_deps" native.filegroup( @@ -50,7 +58,7 @@ def kt_bootstrap_library(name, srcs, visibility = [], deps = [], neverlink_deps visibility = ["//visibility:private"], ) command = """ -function join_by { local IFS="$$1"; shift; echo "$$*"; } +function join_by {{ local IFS="$$1"; shift; echo "$$*"; }} case "$$(uname -s)" in CYGWIN*|MINGW32*|MSYS*) SEP=";" @@ -59,14 +67,14 @@ case "$$(uname -s)" in SEP=":" ;; esac -NAME=%s -CP="%s" -ARGS="%s" +NAME={name} +CP="{classpath}" +ARGS="{args}" CMD="$(JAVA) -Xmx256M -Xms32M -noverify \ - -cp $(location @com_github_jetbrains_kotlin//:kotlin-preloader) org.jetbrains.kotlin.preloading.Preloader \ - -cp $(location @com_github_jetbrains_kotlin//:kotlin-compiler) org.jetbrains.kotlin.cli.jvm.K2JVMCompiler \ - $$CP -d $(@D)/$${NAME}_temp.jar $${ARGS} $(SRCS)" + -cp $(location {kotlinc_repository}//:kotlin-preloader) org.jetbrains.kotlin.preloading.Preloader \ + -cp $(location {kotlinc_repository}//:kotlin-compiler) org.jetbrains.kotlin.cli.jvm.K2JVMCompiler \ + $$CP -d $(@D)/$${{NAME}}_temp.jar $${{ARGS}} $(SRCS)" $$CMD @@ -82,17 +90,22 @@ esac $$SJ \ --normalize \ --compression \ - --sources $(@D)/$${NAME}_temp.jar \ + --sources $(@D)/$${{NAME}}_temp.jar \ --output $(OUTS) -rm $(@D)/$${NAME}_temp.jar -""" % (name, "-cp $$(join_by $$SEP $(locations :%s)) " % dep_label if deps + neverlink_deps else "", " ".join(_BOOTSTRAP_LIB_ARGS)) +rm $(@D)/$${{NAME}}_temp.jar +""".format( + name = name, + classpath = "-cp $$(join_by $$SEP $(locations :%s)) " % dep_label if deps + neverlink_deps else "", + args = " ".join(_BOOTSTRAP_LIB_ARGS), + kotlinc_repository = kotlinc_repository, + ) native.genrule( name = jar_label, tools = [ - "@com_github_jetbrains_kotlin//:home", - "@com_github_jetbrains_kotlin//:kotlin-preloader", - "@com_github_jetbrains_kotlin//:kotlin-compiler", + "%s//:home" % kotlinc_repository, + "%s//:kotlin-preloader" % kotlinc_repository, + "%s//:kotlin-compiler" % kotlinc_repository, "@bazel_tools//tools/jdk:singlejar", dep_label, ], From afb962987ba73ddf076c0412fdecebb999599f18 Mon Sep 17 00:00:00 2001 From: Corbin McNeely-Smith <58151731+restingbull@users.noreply.github.com> Date: Sun, 13 Aug 2023 17:41:19 -0500 Subject: [PATCH 2/9] Move kotlinc_version and ksp_version to versions Allows reuse when defining kotlinc versions. Supporting multiple plugin apis will require supporting multiple kotlincs. --- .../core/repositories/initialize.release.bzl | 29 +++++++------------ .../starlark/core/repositories/versions.bzl | 25 ++++++++++++---- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/main/starlark/core/repositories/initialize.release.bzl b/src/main/starlark/core/repositories/initialize.release.bzl index dccdfb492..ea57175e9 100644 --- a/src/main/starlark/core/repositories/initialize.release.bzl +++ b/src/main/starlark/core/repositories/initialize.release.bzl @@ -27,7 +27,16 @@ load( load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") load("//src/main/starlark/core/repositories/kotlin:compiler.bzl", "kotlin_compiler_repository") load(":ksp.bzl", "ksp_compiler_plugin_repository") -load(":versions.bzl", "version", _versions = "versions") +load( + ":versions.bzl", + "version", + _kotlinc_version = "kotlinc_version", + _ksp_version = "ksp_version", + _versions = "versions", +) + +kotlinc_version = _kotlinc_version +ksp_version = _ksp_version versions = _versions @@ -102,21 +111,3 @@ def kotlin_repositories( urls = ["https://github.com/bazelbuild/bazel-skylib/releases/download/%s/bazel-skylib-%s.tar.gz" % (versions.SKYLIB_VERSION, versions.SKYLIB_VERSION)], sha256 = versions.SKYLIB_SHA, ) - -def kotlinc_version(release, sha256): - return version( - version = release, - url_templates = [ - "https://github.com/JetBrains/kotlin/releases/download/v{version}/kotlin-compiler-{version}.zip", - ], - sha256 = sha256, - ) - -def ksp_version(release, sha256): - return version( - version = release, - url_templates = [ - "https://github.com/google/ksp/releases/download/{version}/artifacts.zip", - ], - sha256 = sha256, - ) diff --git a/src/main/starlark/core/repositories/versions.bzl b/src/main/starlark/core/repositories/versions.bzl index 5ee0999de..c4ce5b054 100644 --- a/src/main/starlark/core/repositories/versions.bzl +++ b/src/main/starlark/core/repositories/versions.bzl @@ -10,6 +10,24 @@ version = provider( }, ) +def kotlinc_version(release, sha256): + return version( + version = release, + url_templates = [ + "https://github.com/JetBrains/kotlin/releases/download/v{version}/kotlin-compiler-{version}.zip", + ], + sha256 = sha256, + ) + +def ksp_version(release, sha256): + return version( + version = release, + url_templates = [ + "https://github.com/google/ksp/releases/download/{version}/artifacts.zip", + ], + sha256 = sha256, + ) + def _use_repository(name, version, rule, **kwargs): http_archive_arguments = dict(kwargs) http_archive_arguments["sha256"] = version.sha256 @@ -61,11 +79,8 @@ versions = struct( ], sha256 = "2b3f6f674a944d25bb8d283c3539947bbe86074793012909a55de4b771f74bcc", ), - KOTLIN_CURRENT_COMPILER_RELEASE = version( - version = "1.8.21", - url_templates = [ - "https://github.com/JetBrains/kotlin/releases/download/v{version}/kotlin-compiler-{version}.zip", - ], + KOTLIN_CURRENT_COMPILER_RELEASE = kotlinc_version( + release = "1.8.21", sha256 = "6e43c5569ad067492d04d92c28cdf8095673699d81ce460bd7270443297e8fd7", ), KSP_CURRENT_COMPILER_PLUGIN_RELEASE = version( From 1977ce4245dc40ef2c1acf214074a9cb3d23f5ea Mon Sep 17 00:00:00 2001 From: Corbin McNeely-Smith <58151731+restingbull@users.noreply.github.com> Date: Sun, 13 Aug 2023 17:45:19 -0500 Subject: [PATCH 3/9] Create KOTLINC_INDEX, major version to kotlinc metadata Managing multiple kotlinc version increases toil. To simplify things, introduce a centralized list of the support versions of kotlinc. Success for this is predicated on the plugin api remaining stable on point releases, which is anecdotally true. --- .../starlark/core/repositories/initialize.bzl | 15 +++++++ .../core/repositories/kotlin/compiler.bzl | 43 ++++++++++++++----- .../starlark/core/repositories/versions.bzl | 19 ++++++++ 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src/main/starlark/core/repositories/initialize.bzl b/src/main/starlark/core/repositories/initialize.bzl index 902d6004e..ecaead690 100644 --- a/src/main/starlark/core/repositories/initialize.bzl +++ b/src/main/starlark/core/repositories/initialize.bzl @@ -17,10 +17,12 @@ load(":setup.bzl", "kt_configure") load( ":initialize.release.bzl", + _RULES_KOTLIN = "RULES_KOTLIN", _kotlinc_version = "kotlinc_version", _ksp_version = "ksp_version", _release_kotlin_repositories = "kotlin_repositories", ) +load("//src/main/starlark/core/repositories/kotlin:compiler.bzl", "KOTLINC_INDEX", "kotlin_compiler_repository") load(":versions.bzl", _versions = "versions") #exports @@ -39,3 +41,16 @@ def kotlin_repositories( """ _release_kotlin_repositories(compiler_release = compiler_release, ksp_compiler_release = ksp_compiler_release) kt_configure() + + # Provide versioned kotlinc repositories. These are used for compiling plugins. + for versioned_kotlinc in KOTLINC_INDEX.values(): + kotlin_compiler_repository( + name = versioned_kotlinc.repository_name, + urls = [ + url.format(version = versioned_kotlinc.release.version) + for url in versioned_kotlinc.release.url_templates + ], + sha256 = versioned_kotlinc.release.sha256, + kotlin_rules = _RULES_KOTLIN.workspace_name, + compiler_version = versioned_kotlinc.release.version, + ) diff --git a/src/main/starlark/core/repositories/kotlin/compiler.bzl b/src/main/starlark/core/repositories/kotlin/compiler.bzl index ab03814bb..21c6b1cdc 100644 --- a/src/main/starlark/core/repositories/kotlin/compiler.bzl +++ b/src/main/starlark/core/repositories/kotlin/compiler.bzl @@ -1,3 +1,23 @@ +load("//src/main/starlark/core/repositories:versions.bzl", "versions") + +_CAPABILITIES_TEMPLATES = { + "legacy": "capabilities_legacy.bzl.com_github_jetbrains_kotlin.bazel", # keep first + "1.4": "capabilities_1.4.bzl.com_github_jetbrains_kotlin.bazel", + "1.5": "capabilities_1.5.bzl.com_github_jetbrains_kotlin.bazel", + "1.6": "capabilities_1.6.bzl.com_github_jetbrains_kotlin.bazel", + "1.7": "capabilities_1.7.bzl.com_github_jetbrains_kotlin.bazel", + "1.8": "capabilities_1.8.bzl.com_github_jetbrains_kotlin.bazel", +} + +# Index of major kotlinc revision to calculated repository name and release. +KOTLINC_INDEX = { + versions.get_major(compiler_release.version): struct( + repository_name = "com_github_jetbrains_kotlin_%s" % versions.get_major(compiler_release.version).replace(".", "_"), + release = compiler_release, + ) + for compiler_release in versions.KOTLIN_COMPILER_RELEASES +} + def _kotlin_compiler_impl(repository_ctx): """Creates the kotlinc repository.""" attr = repository_ctx.attr @@ -25,27 +45,28 @@ def _kotlin_compiler_impl(repository_ctx): executable = False, ) + repository_ctx.file( + "version.bzl", + """ + MAJOR_VERSION="%s" + """.strip() % versions.get_major(attr.compiler_version), + executable = False, + ) + def _get_capability_template(compiler_version, templates): + major_version = versions.get_major(compiler_version) + for ver, template in zip(_CAPABILITIES_TEMPLATES.keys(), templates): - if compiler_version.startswith(ver): + if ver == major_version: return template # After latest version - if compiler_version > _CAPABILITIES_TEMPLATES.keys()[-1]: + if major_version > _CAPABILITIES_TEMPLATES.keys()[-1]: templates[-1] # Legacy return templates[0] -_CAPABILITIES_TEMPLATES = { - "legacy": "capabilities_legacy.bzl.com_github_jetbrains_kotlin.bazel", # keep first - "1.4": "capabilities_1.4.bzl.com_github_jetbrains_kotlin.bazel", - "1.5": "capabilities_1.5.bzl.com_github_jetbrains_kotlin.bazel", - "1.6": "capabilities_1.6.bzl.com_github_jetbrains_kotlin.bazel", - "1.7": "capabilities_1.7.bzl.com_github_jetbrains_kotlin.bazel", - "1.8": "capabilities_1.8.bzl.com_github_jetbrains_kotlin.bazel", -} - kotlin_compiler_repository = repository_rule( implementation = _kotlin_compiler_impl, attrs = { diff --git a/src/main/starlark/core/repositories/versions.bzl b/src/main/starlark/core/repositories/versions.bzl index c4ce5b054..9c7347b79 100644 --- a/src/main/starlark/core/repositories/versions.bzl +++ b/src/main/starlark/core/repositories/versions.bzl @@ -37,6 +37,10 @@ def _use_repository(name, version, rule, **kwargs): maybe(rule, name = name, **http_archive_arguments) +def _get_major(version): + parts = version.split(".") + return ".".join(parts[:2]) + versions = struct( RULES_NODEJS_VERSION = "5.5.3", RULES_NODEJS_SHA = "f10a3a12894fc3c9bf578ee5a5691769f6805c4be84359681a785a0c12e8d2b6", @@ -83,6 +87,20 @@ versions = struct( release = "1.8.21", sha256 = "6e43c5569ad067492d04d92c28cdf8095673699d81ce460bd7270443297e8fd7", ), + KOTLIN_COMPILER_RELEASES = [ + kotlinc_version( + release = "1.8.21", + sha256 = "6e43c5569ad067492d04d92c28cdf8095673699d81ce460bd7270443297e8fd7", + ), + kotlinc_version( + release = "1.7.22", + sha256 = "9db4b467743c1aea8a21c08e1c286bc2aeb93f14c7ba2037dbd8f48adc357d83", + ), + kotlinc_version( + release = "1.6.21", + sha256 = "632166fed89f3f430482f5aa07f2e20b923b72ef688c8f5a7df3aa1502c6d8ba", + ), + ], KSP_CURRENT_COMPILER_PLUGIN_RELEASE = version( version = "1.8.21-1.0.11", url_templates = [ @@ -126,4 +144,5 @@ versions = struct( sha256 = None, ), use_repository = _use_repository, + get_major = _get_major, ) From c53234aad6712194877e3872a2d06a5dbd6d7687 Mon Sep 17 00:00:00 2001 From: Corbin McNeely-Smith <58151731+restingbull@users.noreply.github.com> Date: Sun, 13 Aug 2023 17:48:59 -0500 Subject: [PATCH 4/9] Split plugin compilation by major kotlinc version. This provides a separate plugin for each major kotlinc release. Still requires wiring into the toolchain system (follow up PR), but simplifies using older versions of kotlin with less effort. --- src/main/kotlin/BUILD | 2 +- .../kotlin/builder/toolchain/BUILD.bazel | 2 +- .../kotlin/builder/utils/jars/BUILD.bazel | 3 + .../kotlin/io/bazel/kotlin/plugin/BUILD.bazel | 101 ++++- .../SkipCodeGen.kt | 83 ++++ .../jdeps/JdepsGenCommandLineProcessor.kt | 37 ++ .../jdeps/JdepsGenComponentRegistrar.kt | 23 + .../jdeps/JdepsGenConfigurationKeys.kt | 29 ++ .../jdeps/JdepsGenExtension.kt | 357 ++++++++++++++++ .../SkipCodeGen.kt | 83 ++++ .../jdeps/JdepsGenCommandLineProcessor.kt | 3 +- .../jdeps/JdepsGenComponentRegistrar.kt | 3 +- .../jdeps/JdepsGenConfigurationKeys.kt | 2 +- .../jdeps/JdepsGenExtension.kt | 2 +- .../SkipCodeGen.kt | 2 +- .../jdeps/JdepsGenCommandLineProcessor.kt | 78 ++++ .../jdeps/JdepsGenComponentRegistrar.kt | 19 + .../jdeps/JdepsGenConfigurationKeys.kt | 35 ++ .../jdeps/JdepsGenExtension.kt | 402 ++++++++++++++++++ .../io/bazel/kotlin/plugin/jdeps/BUILD.bazel | 49 --- 20 files changed, 1240 insertions(+), 75 deletions(-) create mode 100644 src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/SkipCodeGen.kt create mode 100644 src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenCommandLineProcessor.kt create mode 100644 src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenComponentRegistrar.kt create mode 100644 src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenConfigurationKeys.kt create mode 100644 src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenExtension.kt create mode 100644 src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/SkipCodeGen.kt rename src/main/kotlin/io/bazel/kotlin/plugin/{ => com_github_jetbrains_kotlin_1_7}/jdeps/JdepsGenCommandLineProcessor.kt (95%) rename src/main/kotlin/io/bazel/kotlin/plugin/{ => com_github_jetbrains_kotlin_1_7}/jdeps/JdepsGenComponentRegistrar.kt (87%) rename src/main/kotlin/io/bazel/kotlin/plugin/{ => com_github_jetbrains_kotlin_1_7}/jdeps/JdepsGenConfigurationKeys.kt (93%) rename src/main/kotlin/io/bazel/kotlin/plugin/{ => com_github_jetbrains_kotlin_1_7}/jdeps/JdepsGenExtension.kt (99%) rename src/main/kotlin/io/bazel/kotlin/plugin/{ => com_github_jetbrains_kotlin_1_8}/SkipCodeGen.kt (97%) create mode 100644 src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenCommandLineProcessor.kt create mode 100644 src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenComponentRegistrar.kt create mode 100644 src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenConfigurationKeys.kt create mode 100644 src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenExtension.kt delete mode 100644 src/main/kotlin/io/bazel/kotlin/plugin/jdeps/BUILD.bazel diff --git a/src/main/kotlin/BUILD b/src/main/kotlin/BUILD index db305906f..1d56e8d13 100644 --- a/src/main/kotlin/BUILD +++ b/src/main/kotlin/BUILD @@ -15,7 +15,7 @@ jar_jar( jar_jar( name = "jdeps-gen", - input_jar = "//src/main/kotlin/io/bazel/kotlin/plugin/jdeps:jdeps-gen_deploy.jar", + input_jar = "//src/main/kotlin/io/bazel/kotlin/plugin:jdeps-gen_deploy.jar", rules = "shade.jarjar", visibility = ["//visibility:public"], ) diff --git a/src/main/kotlin/io/bazel/kotlin/builder/toolchain/BUILD.bazel b/src/main/kotlin/io/bazel/kotlin/builder/toolchain/BUILD.bazel index 4cda9aeeb..c1e1c58a9 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/toolchain/BUILD.bazel +++ b/src/main/kotlin/io/bazel/kotlin/builder/toolchain/BUILD.bazel @@ -27,8 +27,8 @@ kt_bootstrap_library( visibility = ["//src:__subpackages__"], deps = [ "//src/main/kotlin/io/bazel/kotlin/builder/utils", + "//src/main/kotlin/io/bazel/kotlin/plugin:jdeps-gen-lib", "//src/main/kotlin/io/bazel/kotlin/plugin:skip-code-gen-lib", - "//src/main/kotlin/io/bazel/kotlin/plugin/jdeps:jdeps-gen-lib", "//src/main/protobuf:kotlin_model_java_proto", "@com_github_jetbrains_kotlin//:kotlin-preloader", "@kotlin_rules_maven//:com_google_protobuf_protobuf_java", diff --git a/src/main/kotlin/io/bazel/kotlin/builder/utils/jars/BUILD.bazel b/src/main/kotlin/io/bazel/kotlin/builder/utils/jars/BUILD.bazel index a7157e50b..014ad7ba8 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/utils/jars/BUILD.bazel +++ b/src/main/kotlin/io/bazel/kotlin/builder/utils/jars/BUILD.bazel @@ -1,3 +1,4 @@ +load("//src/main/starlark/core/repositories/kotlin:compiler.bzl", "KOTLINC_INDEX") load("//src/main/kotlin:bootstrap.bzl", "kt_bootstrap_library") kt_bootstrap_library( @@ -6,6 +7,8 @@ kt_bootstrap_library( "*.kt", "**/*.kt", ]), + # Need for the 1.6 jdeps-gen plugin + kotlinc_repository_name = KOTLINC_INDEX["1.6"].repository_name, visibility = ["//src:__subpackages__"], deps = [ "//src/main/protobuf:deps_java_proto", diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/BUILD.bazel b/src/main/kotlin/io/bazel/kotlin/plugin/BUILD.bazel index eaa662124..24209ee74 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/BUILD.bazel +++ b/src/main/kotlin/io/bazel/kotlin/plugin/BUILD.bazel @@ -11,35 +11,102 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +load("//src/main/starlark/core/repositories/kotlin:compiler.bzl", "KOTLINC_INDEX") load("@rules_java//java:defs.bzl", "java_binary") load("//src/main/kotlin:bootstrap.bzl", "kt_bootstrap_library") load("//kotlin/internal/utils:generate_jvm_service.bzl", "generate_jvm_service") +load("@com_github_jetbrains_kotlin//:version.bzl", KOTLINC_MAJOR_VERSION = "MAJOR_VERSION") -# The compiler binary, this is co-located in the kotlin compiler classloader. -kt_bootstrap_library( - name = "skip-code-gen-lib", - srcs = glob(["*.kt"]), +# Generate a set of plugins for each major revision of the kotlinc compiler plugin api +[ + ( + # jdeps generator plugin + kt_bootstrap_library( + name = "jdeps-gen-lib-%s" % version, + srcs = glob(["%s/jdeps/*.kt" % release.repository_name]), + kotlinc_repository_name = release.repository_name, + visibility = ["//src:__subpackages__"], + deps = [ + "//src/main/kotlin/io/bazel/kotlin/builder/utils/jars", + "//src/main/protobuf:deps_java_proto", + "@%s//:kotlin-compiler" % release.repository_name, + "@kotlin_rules_maven//:com_google_protobuf_protobuf_java", + ], + ), + + # services to integrate with the plugin. + generate_jvm_service( + name = "jdeps-gen-services-%s" % version, + services = { + "io.bazel.kotlin.plugin.%s.jdeps.JdepsGenComponentRegistrar" % release.repository_name: "org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar", + "io.bazel.kotlin.plugin.%s.jdeps.JdepsGenCommandLineProcessor" % release.repository_name: "org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor", + }, + ), + # The plugin binary. + java_binary( + name = "jdeps-gen-%s" % version, + visibility = ["//src:__subpackages__"], + runtime_deps = [ + ":jdeps-gen-lib-%s" % version, + ":jdeps-gen-services-%s" % version, + ], + ), + # SkipCodeGen utility plugin + kt_bootstrap_library( + name = "skip-code-gen-lib-%s" % version, + srcs = glob(["%s/*.kt" % release.repository_name]), + kotlinc_repository_name = release.repository_name, + visibility = ["//src:__subpackages__"], + deps = [ + "@%s//:kotlin-compiler" % release.repository_name, + ], + ), + # services to integrate with the plugin. + generate_jvm_service( + name = "skip-code-gen-services-%s" % version, + services = { + "io.bazel.kotlin.plugin.%s.SkipCodeGen" % release.repository_name: "org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar", + }, + ), + # The plugin binary. + java_binary( + name = "skip-code-gen-%s" % version, + visibility = ["//src:__subpackages__"], + runtime_deps = [ + ":skip-code-gen-lib-%s" % version, + ":skip-code-gen-services-%s" % version, + ], + ), + ) + for version, release in KOTLINC_INDEX.items() +] + +java_binary( + name = "skip-code-gen", visibility = ["//src:__subpackages__"], - deps = [ - "@com_github_jetbrains_kotlin//:kotlin-compiler", + runtime_deps = [ + ":jdeps-gen-lib-%s" % KOTLINC_MAJOR_VERSION, + ":jdeps-gen-services-%s" % KOTLINC_MAJOR_VERSION, ], ) -# services to integrate with the plugin. -generate_jvm_service( - name = "skip-code-gen-services", - services = { - "io.bazel.kotlin.plugin.SkipCodeGen": "org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar", - }, +alias( + name = "skip-code-gen-lib", + actual = "skip-code-gen-lib-%s" % KOTLINC_MAJOR_VERSION, + visibility = ["//src:__subpackages__"], ) -# The plugin binary. java_binary( - name = "skip-code-gen", + name = "jdeps-gen", visibility = ["//src:__subpackages__"], runtime_deps = [ - ":skip-code-gen-lib", - ":skip-code-gen-services", + ":jdeps-gen-lib-%s" % KOTLINC_MAJOR_VERSION, + ":jdeps-gen-services-%s" % KOTLINC_MAJOR_VERSION, ], ) + +alias( + name = "jdeps-gen-lib", + actual = "jdeps-gen-lib-%s" % KOTLINC_MAJOR_VERSION, + visibility = ["//src:__subpackages__"], +) diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/SkipCodeGen.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/SkipCodeGen.kt new file mode 100644 index 000000000..a346e038d --- /dev/null +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/SkipCodeGen.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2020 The Bazel Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_6 + +import com.google.common.base.Preconditions +import com.intellij.mock.MockProject +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.analyzer.AnalysisResult +import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.container.ComponentProvider +import org.jetbrains.kotlin.context.ProjectContext +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension + +/** + * SkipCodeGen registers an extension to skip code generation. Must be the last compiler plugin. + */ +class SkipCodeGen : ComponentRegistrar { + + companion object { + val COMPILER_PLUGIN_ID = "io.bazel.kotlin.plugin.kt_1_8.SkipCodeGen" + } + + override fun registerProjectComponents( + project: MockProject, + configuration: CompilerConfiguration, + ) { + AnalysisHandlerExtension.registerExtension( + project, + SkipCodeGen, + ) + } + + /** + * SkipCodeGen ends the compilation + */ + private object SkipCodeGen : AnalysisHandlerExtension { + + override fun doAnalysis( + project: Project, + module: ModuleDescriptor, + projectContext: ProjectContext, + files: Collection, + bindingTrace: BindingTrace, + componentProvider: ComponentProvider, + ): AnalysisResult? { + return null + } + + // analysisCompleted generates the module jvm abi and requests code generation to be skipped. + override fun analysisCompleted( + project: Project, + module: ModuleDescriptor, + bindingTrace: BindingTrace, + files: Collection, + ): AnalysisResult? { + // Ensure this is the last plugin, as it will short circuit any other plugin analysisCompleted + // calls. + Preconditions.checkState( + AnalysisHandlerExtension.getInstances(project).last() == this, + "SkipCodeGen must be the last plugin: ${AnalysisHandlerExtension.getInstances(project)}", + ) + return AnalysisResult.Companion.success(bindingTrace.bindingContext, module, false) + } + } +} diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenCommandLineProcessor.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenCommandLineProcessor.kt new file mode 100644 index 000000000..6bdc74b96 --- /dev/null +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenCommandLineProcessor.kt @@ -0,0 +1,37 @@ +package io.bazel.kotlin.plugin.jdeps + +import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption +import org.jetbrains.kotlin.compiler.plugin.CliOption +import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException +import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor +import org.jetbrains.kotlin.config.CompilerConfiguration + +class JdepsGenCommandLineProcessor : CommandLineProcessor { + companion object { + val COMPILER_PLUGIN_ID = "io.bazel.kotlin.plugin.jdeps.JDepsGen" + + val OUTPUT_JDEPS_FILE_OPTION: CliOption = + CliOption("output", "", "Output path for generated jdeps", required = true) + val TARGET_LABEL_OPTION: CliOption = + CliOption("target_label", "", "Label of target being analyzed", required = true) + val DIRECT_DEPENDENCIES_OPTION: CliOption = + CliOption("direct_dependencies", "", "List of targets direct dependencies", required = false, allowMultipleOccurrences = true) + val STRICT_KOTLIN_DEPS_OPTION: CliOption = + CliOption("strict_kotlin_deps", "", "Report strict deps violations", required = true) + } + + override val pluginId: String + get() = COMPILER_PLUGIN_ID + override val pluginOptions: Collection + get() = listOf(OUTPUT_JDEPS_FILE_OPTION, TARGET_LABEL_OPTION, DIRECT_DEPENDENCIES_OPTION, STRICT_KOTLIN_DEPS_OPTION) + + override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) { + when (option) { + OUTPUT_JDEPS_FILE_OPTION -> configuration.put(JdepsGenConfigurationKeys.OUTPUT_JDEPS, value) + TARGET_LABEL_OPTION -> configuration.put(JdepsGenConfigurationKeys.TARGET_LABEL, value) + DIRECT_DEPENDENCIES_OPTION -> configuration.appendList(JdepsGenConfigurationKeys.DIRECT_DEPENDENCIES, value) + STRICT_KOTLIN_DEPS_OPTION -> configuration.put(JdepsGenConfigurationKeys.STRICT_KOTLIN_DEPS, value) + else -> throw CliOptionProcessingException("Unknown option: ${option.optionName}") + } + } +} diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenComponentRegistrar.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenComponentRegistrar.kt new file mode 100644 index 000000000..b74642edf --- /dev/null +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenComponentRegistrar.kt @@ -0,0 +1,23 @@ +package io.bazel.kotlin.plugin.jdeps + +import com.intellij.mock.MockProject +import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension +import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor +import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension + +class JdepsGenComponentRegistrar : ComponentRegistrar { + + override fun registerProjectComponents( + project: MockProject, + configuration: CompilerConfiguration + ) { + + // Capture all types referenced by the compiler for this module and look up the jar from which + // they were loaded from + val extension = JdepsGenExtension(project, configuration) + AnalysisHandlerExtension.registerExtension(project, extension) + StorageComponentContainerContributor.registerExtension(project, extension) + } +} diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenConfigurationKeys.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenConfigurationKeys.kt new file mode 100644 index 000000000..ff7b2d8c9 --- /dev/null +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenConfigurationKeys.kt @@ -0,0 +1,29 @@ +package io.bazel.kotlin.plugin.jdeps + +import org.jetbrains.kotlin.config.CompilerConfigurationKey + +object JdepsGenConfigurationKeys { + /** + * Output path of generated Jdeps proto file. + */ + val OUTPUT_JDEPS: CompilerConfigurationKey = + CompilerConfigurationKey.create(JdepsGenCommandLineProcessor.OUTPUT_JDEPS_FILE_OPTION.description) + + /** + * Label of the Bazel target being analyzed. + */ + val TARGET_LABEL: CompilerConfigurationKey = + CompilerConfigurationKey.create(JdepsGenCommandLineProcessor.TARGET_LABEL_OPTION.description) + + /** + * Label of the Bazel target being analyzed. + */ + val STRICT_KOTLIN_DEPS: CompilerConfigurationKey = + CompilerConfigurationKey.create(JdepsGenCommandLineProcessor.STRICT_KOTLIN_DEPS_OPTION.description) + + /** + * List of direct dependencies of the target. + */ + val DIRECT_DEPENDENCIES: CompilerConfigurationKey> = + CompilerConfigurationKey.create(JdepsGenCommandLineProcessor.DIRECT_DEPENDENCIES_OPTION.description) +} diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenExtension.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenExtension.kt new file mode 100644 index 000000000..5a2f9f3ce --- /dev/null +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenExtension.kt @@ -0,0 +1,357 @@ +package io.bazel.kotlin.plugin.jdeps + +import com.google.devtools.build.lib.view.proto.Deps +import com.intellij.mock.MockProject +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import io.bazel.kotlin.builder.utils.jars.JarOwner +import org.jetbrains.kotlin.analyzer.AnalysisResult +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.container.StorageComponentContainer +import org.jetbrains.kotlin.container.useInstance +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.ParameterDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.SourceElement +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor +import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor +import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor +import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor +import org.jetbrains.kotlin.load.java.sources.JavaSourceElement +import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass +import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaField +import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement +import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass +import org.jetbrains.kotlin.load.kotlin.getContainingKotlinJvmBinaryClass +import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.FunctionImportedFromObject +import org.jetbrains.kotlin.resolve.PropertyImportedFromObject +import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker +import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject +import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker +import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext +import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeConstructor +import org.jetbrains.kotlin.types.typeUtil.supertypes +import java.io.BufferedOutputStream +import java.io.File +import java.nio.file.Paths + +/** + * Kotlin compiler extension that tracks classes (and corresponding classpath jars) needed to + * compile current kotlin target. Tracked data should include all classes whose changes could + * affect target's compilation out : direct class dependencies (i.e external classes directly + * used), but also their superclass, interfaces, etc. + * The primary use of this extension is to improve Kotlin module compilation avoidance in build + * systems (like Buck). + * + * Tracking of classes is done with a Remapper, which exposes all object types used by the class + * bytecode being generated. Tracking of the ancestor classes is done via modules and class + * descriptors that got generated during analysis/resolve phase of Kotlin compilation. + * + * Note: annotation processors dependencies may need to be tracked separatly (and may not need + * per-class ABI change tracking) + * + * @param project the current compilation project + * @param configuration the current compilation configuration + */ +class JdepsGenExtension( + val project: MockProject, + val configuration: CompilerConfiguration) : + AnalysisHandlerExtension, StorageComponentContainerContributor { + + companion object { + + /** + * Returns the path of the jar archive file corresponding to the provided descriptor. + * + * @descriptor the descriptor, typically obtained from compilation analyze phase + * @return the path corresponding to the JAR where this class was loaded from, or null. + */ + fun getClassCanonicalPath(descriptor: DeclarationDescriptorWithSource): String? { + return when (val sourceElement: SourceElement = descriptor.source) { + is JavaSourceElement -> + if (sourceElement.javaElement is BinaryJavaClass) { + (sourceElement.javaElement as BinaryJavaClass).virtualFile!!.canonicalPath + } else if (sourceElement.javaElement is BinaryJavaField) { + val containingClass = (sourceElement.javaElement as BinaryJavaField).containingClass + if (containingClass is BinaryJavaClass) { + containingClass.virtualFile!!.canonicalPath + } else { + null + } + } else { + // Ignore Java source local to this module. + null + } + is KotlinJvmBinarySourceElement -> + (sourceElement.binaryClass as VirtualFileKotlinClass).file.canonicalPath + else -> null + } + } + + fun getClassCanonicalPath(typeConstructor: TypeConstructor): String? { + return (typeConstructor.declarationDescriptor as? DeclarationDescriptorWithSource)?.let { getClassCanonicalPath(it) } + } + } + + private val explicitClassesCanonicalPaths = mutableSetOf() + private val implicitClassesCanonicalPaths = mutableSetOf() + + override fun registerModuleComponents( + container: StorageComponentContainer, + platform: TargetPlatform, + moduleDescriptor: ModuleDescriptor + ) { + container.useInstance(ClasspathCollectingChecker(explicitClassesCanonicalPaths, implicitClassesCanonicalPaths)) + } + + class ClasspathCollectingChecker( + private val explicitClassesCanonicalPaths: MutableSet, + private val implicitClassesCanonicalPaths: MutableSet + ) : CallChecker, DeclarationChecker { + + override fun check( + resolvedCall: ResolvedCall<*>, + reportOn: PsiElement, + context: CallCheckerContext + ) { + when (val resultingDescriptor = resolvedCall.resultingDescriptor) { + is FunctionImportedFromObject -> { + collectTypeReferences((resolvedCall.resultingDescriptor as FunctionImportedFromObject).containingObject.defaultType) + } + is PropertyImportedFromObject -> { + collectTypeReferences((resolvedCall.resultingDescriptor as PropertyImportedFromObject).containingObject.defaultType) + } + is JavaMethodDescriptor -> { + getClassCanonicalPath((resultingDescriptor.containingDeclaration as ClassDescriptor).typeConstructor)?.let { explicitClassesCanonicalPaths.add(it) } + } + is FunctionDescriptor -> { + resultingDescriptor.returnType?.let { addImplicitDep(it) } + resultingDescriptor.valueParameters.forEach { valueParameter -> + addImplicitDep(valueParameter.type) + } + val virtualFileClass = resultingDescriptor.getContainingKotlinJvmBinaryClass() as? VirtualFileKotlinClass + ?: return + explicitClassesCanonicalPaths.add(virtualFileClass.file.path) + } + is ParameterDescriptor -> { + getClassCanonicalPath(resultingDescriptor)?.let { explicitClassesCanonicalPaths.add(it) } + } + is FakeCallableDescriptorForObject -> { + collectTypeReferences(resultingDescriptor.type) + } + is JavaPropertyDescriptor -> { + getClassCanonicalPath(resultingDescriptor)?.let { explicitClassesCanonicalPaths.add(it) } + } + is PropertyDescriptor -> { + when (resultingDescriptor.containingDeclaration) { + is ClassDescriptor -> collectTypeReferences((resultingDescriptor.containingDeclaration as ClassDescriptor).defaultType) + else -> { + val virtualFileClass = (resultingDescriptor).getContainingKotlinJvmBinaryClass() as? VirtualFileKotlinClass ?: return + explicitClassesCanonicalPaths.add(virtualFileClass.file.path) + } + } + addImplicitDep(resultingDescriptor.type) + } + else -> return + } + } + + override fun check( + declaration: KtDeclaration, + descriptor: DeclarationDescriptor, + context: DeclarationCheckerContext + ) { + when (descriptor) { + is ClassDescriptor -> { + descriptor.typeConstructor.supertypes.forEach { + collectTypeReferences(it) + } + } + is FunctionDescriptor -> { + descriptor.returnType?.let { collectTypeReferences(it) } + descriptor.valueParameters.forEach { valueParameter -> + collectTypeReferences(valueParameter.type) + } + descriptor.annotations.forEach { annotation -> + collectTypeReferences(annotation.type) + } + } + is PropertyDescriptor -> { + collectTypeReferences(descriptor.type) + descriptor.annotations.forEach { annotation -> + collectTypeReferences(annotation.type) + } + descriptor.backingField?.annotations?.forEach { annotation -> + collectTypeReferences(annotation.type) + } + } + is LocalVariableDescriptor -> { + collectTypeReferences(descriptor.type) + } + } + } + + private fun addImplicitDep(it: KotlinType) { + getClassCanonicalPath(it.constructor)?.let { implicitClassesCanonicalPaths.add(it) } + } + + private fun addExplicitDep(it: KotlinType) { + getClassCanonicalPath(it.constructor)?.let { explicitClassesCanonicalPaths.add(it) } + } + + /** + * Records direct and indirect references for a given type. Direct references are explicitly + * used in the code, e.g: a type declaration or a generic type declaration. Indirect references + * are other types required for compilation such as supertypes and interfaces of those explicit + * types. + */ + private fun collectTypeReferences(kotlinType: KotlinType, collectSuperTypes: Boolean = true) { + addExplicitDep(kotlinType) + + if (collectSuperTypes) { + kotlinType.supertypes().forEach { + addImplicitDep(it) + } + } + + collectTypeArguments(kotlinType) + } + + fun collectTypeArguments(kotlinType: KotlinType, visitedKotlinTypes: MutableSet = mutableSetOf()) { + visitedKotlinTypes.add(kotlinType) + kotlinType.arguments.map { it.type }.forEach { typeArgument -> + addExplicitDep(typeArgument) + typeArgument.supertypes().forEach { addImplicitDep(it) } + if (!visitedKotlinTypes.contains(typeArgument)) { + collectTypeArguments(typeArgument, visitedKotlinTypes) + } + } + } + } + + override fun analysisCompleted( + project: Project, + module: ModuleDescriptor, + bindingTrace: BindingTrace, + files: Collection + ): AnalysisResult? { + val directDeps = configuration.getList(JdepsGenConfigurationKeys.DIRECT_DEPENDENCIES) + val targetLabel = configuration.getNotNull(JdepsGenConfigurationKeys.TARGET_LABEL) + val explicitDeps = createDepsMap(explicitClassesCanonicalPaths) + + doWriteJdeps(directDeps, targetLabel, explicitDeps) + + doStrictDeps(configuration, targetLabel, directDeps, explicitDeps) + + return super.analysisCompleted(project, module, bindingTrace, files) + } + + /** + * Returns a map of jars to classes loaded from those jars. + */ + private fun createDepsMap(classes: Set): Map> { + val jarsToClasses = mutableMapOf>() + classes.forEach { + val parts = it.split("!/") + val jarPath = parts[0] + if (jarPath.endsWith(".jar")) { + jarsToClasses.computeIfAbsent(jarPath) { ArrayList() }.add(parts[1]) + } + } + return jarsToClasses + } + + private fun doWriteJdeps( + directDeps: MutableList, + targetLabel: String, + explicitDeps: Map> + ) { + + val implicitDeps = createDepsMap(implicitClassesCanonicalPaths) + + // Build and write out deps.proto + val jdepsOutput = configuration.getNotNull(JdepsGenConfigurationKeys.OUTPUT_JDEPS) + + val rootBuilder = Deps.Dependencies.newBuilder() + rootBuilder.success = true + rootBuilder.ruleLabel = targetLabel + + val unusedDeps = directDeps.subtract(explicitDeps.keys) + unusedDeps.forEach { jarPath -> + val dependency = Deps.Dependency.newBuilder() + dependency.kind = Deps.Dependency.Kind.UNUSED + dependency.path = jarPath + rootBuilder.addDependency(dependency) + } + + explicitDeps.forEach { (jarPath, _) -> + val dependency = Deps.Dependency.newBuilder() + dependency.kind = Deps.Dependency.Kind.EXPLICIT + dependency.path = jarPath + rootBuilder.addDependency(dependency) + } + + implicitDeps.keys.subtract(explicitDeps.keys).forEach { + val dependency = Deps.Dependency.newBuilder() + dependency.kind = Deps.Dependency.Kind.IMPLICIT + dependency.path = it + rootBuilder.addDependency(dependency) + } + + BufferedOutputStream(File(jdepsOutput).outputStream()).use { + it.write(rootBuilder.build().toByteArray()) + } + } + + private fun doStrictDeps( + compilerConfiguration: CompilerConfiguration, + targetLabel: String, + directDeps: MutableList, + explicitDeps: Map>) { + when (compilerConfiguration.getNotNull(JdepsGenConfigurationKeys.STRICT_KOTLIN_DEPS)) { + "warn" -> checkStrictDeps(explicitDeps, directDeps, targetLabel) + "error" -> { + if (checkStrictDeps(explicitDeps, directDeps, targetLabel)) error("Strict Deps Violations - please fix") + } + } + } + + /** + * Prints strict deps warnings and returns true if violations were found. + */ + private fun checkStrictDeps( + result: Map>, + directDeps: List, + targetLabel: String + ): Boolean { + val missingStrictDeps = result.keys + .filter { !directDeps.contains(it) } + .map { JarOwner.readJarOwnerFromManifest(Paths.get(it)).label } + + if (missingStrictDeps.isNotEmpty()) { + val open = "\u001b[35m\u001b[1m" + val close = "\u001b[0m" + val command = + """ + |$open ** Please add the following dependencies:$close ${missingStrictDeps.joinToString(" ")} to $targetLabel + |$open ** You can use the following buildozer command:$close buildozer 'add deps ${missingStrictDeps.joinToString(" ")}' $targetLabel + """.trimMargin() + + println(command) + return true + } + return false + } +} diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/SkipCodeGen.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/SkipCodeGen.kt new file mode 100644 index 000000000..a5510e5d0 --- /dev/null +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/SkipCodeGen.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2020 The Bazel Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_7 + +import com.google.common.base.Preconditions +import com.intellij.mock.MockProject +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.analyzer.AnalysisResult +import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.container.ComponentProvider +import org.jetbrains.kotlin.context.ProjectContext +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension + +/** + * SkipCodeGen registers an extension to skip code generation. Must be the last compiler plugin. + */ +class SkipCodeGen : ComponentRegistrar { + + companion object { + val COMPILER_PLUGIN_ID = "io.bazel.kotlin.plugin.SkipCodeGen" + } + + override fun registerProjectComponents( + project: MockProject, + configuration: CompilerConfiguration, + ) { + AnalysisHandlerExtension.registerExtension( + project, + SkipCodeGen, + ) + } + + /** + * SkipCodeGen ends the compilation + */ + private object SkipCodeGen : AnalysisHandlerExtension { + + override fun doAnalysis( + project: Project, + module: ModuleDescriptor, + projectContext: ProjectContext, + files: Collection, + bindingTrace: BindingTrace, + componentProvider: ComponentProvider, + ): AnalysisResult? { + return null + } + + // analysisCompleted generates the module jvm abi and requests code generation to be skipped. + override fun analysisCompleted( + project: Project, + module: ModuleDescriptor, + bindingTrace: BindingTrace, + files: Collection, + ): AnalysisResult? { + // Ensure this is the last plugin, as it will short circuit any other plugin analysisCompleted + // calls. + Preconditions.checkState( + AnalysisHandlerExtension.getInstances(project).last() == this, + "SkipCodeGen must be the last plugin: ${AnalysisHandlerExtension.getInstances(project)}", + ) + return AnalysisResult.Companion.success(bindingTrace.bindingContext, module, false) + } + } +} diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/jdeps/JdepsGenCommandLineProcessor.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenCommandLineProcessor.kt similarity index 95% rename from src/main/kotlin/io/bazel/kotlin/plugin/jdeps/JdepsGenCommandLineProcessor.kt rename to src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenCommandLineProcessor.kt index 122dab2a3..1c6d1960c 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/jdeps/JdepsGenCommandLineProcessor.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenCommandLineProcessor.kt @@ -1,4 +1,4 @@ -package io.bazel.kotlin.plugin.jdeps +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_7.jdeps import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption import org.jetbrains.kotlin.compiler.plugin.CliOption @@ -7,7 +7,6 @@ import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfigurationKey -@OptIn(org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi::class) class JdepsGenCommandLineProcessor : CommandLineProcessor { companion object { val COMPILER_PLUGIN_ID = "io.bazel.kotlin.plugin.jdeps.JDepsGen" diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/jdeps/JdepsGenComponentRegistrar.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenComponentRegistrar.kt similarity index 87% rename from src/main/kotlin/io/bazel/kotlin/plugin/jdeps/JdepsGenComponentRegistrar.kt rename to src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenComponentRegistrar.kt index e4d5b5641..226e92df1 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/jdeps/JdepsGenComponentRegistrar.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenComponentRegistrar.kt @@ -1,4 +1,4 @@ -package io.bazel.kotlin.plugin.jdeps +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_7.jdeps import com.intellij.mock.MockProject import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar @@ -6,7 +6,6 @@ import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension -@OptIn(org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi::class) class JdepsGenComponentRegistrar : ComponentRegistrar { override fun registerProjectComponents( diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/jdeps/JdepsGenConfigurationKeys.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenConfigurationKeys.kt similarity index 93% rename from src/main/kotlin/io/bazel/kotlin/plugin/jdeps/JdepsGenConfigurationKeys.kt rename to src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenConfigurationKeys.kt index a4616da16..528cf1499 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/jdeps/JdepsGenConfigurationKeys.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenConfigurationKeys.kt @@ -1,4 +1,4 @@ -package io.bazel.kotlin.plugin.jdeps +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_7.jdeps import org.jetbrains.kotlin.config.CompilerConfigurationKey diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/jdeps/JdepsGenExtension.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenExtension.kt similarity index 99% rename from src/main/kotlin/io/bazel/kotlin/plugin/jdeps/JdepsGenExtension.kt rename to src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenExtension.kt index 6c5b68011..dcd819225 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/jdeps/JdepsGenExtension.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenExtension.kt @@ -1,4 +1,4 @@ -package io.bazel.kotlin.plugin.jdeps +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_7.jdeps import com.google.devtools.build.lib.view.proto.Deps import com.intellij.mock.MockProject diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/SkipCodeGen.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/SkipCodeGen.kt similarity index 97% rename from src/main/kotlin/io/bazel/kotlin/plugin/SkipCodeGen.kt rename to src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/SkipCodeGen.kt index f9eea10d1..60fe3ee5b 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/SkipCodeGen.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/SkipCodeGen.kt @@ -14,7 +14,7 @@ * limitations under the License. * */ -package io.bazel.kotlin.plugin +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8 import com.google.common.base.Preconditions import com.intellij.mock.MockProject diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenCommandLineProcessor.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenCommandLineProcessor.kt new file mode 100644 index 000000000..905f74b60 --- /dev/null +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenCommandLineProcessor.kt @@ -0,0 +1,78 @@ +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8.jdeps + +import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption +import org.jetbrains.kotlin.compiler.plugin.CliOption +import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException +import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.CompilerConfigurationKey + +@OptIn(org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi::class) +class JdepsGenCommandLineProcessor : CommandLineProcessor { + companion object { + val COMPILER_PLUGIN_ID = "io.bazel.kotlin.plugin.jdeps.JDepsGen" + + val OUTPUT_JDEPS_FILE_OPTION: CliOption = + CliOption("output", "", "Output path for generated jdeps", required = true) + val TARGET_LABEL_OPTION: CliOption = + CliOption("target_label", "", "Label of target being analyzed", required = true) + val DIRECT_DEPENDENCIES_OPTION: CliOption = + CliOption( + "direct_dependencies", + "", + "List of targets direct dependencies", + required = false, + allowMultipleOccurrences = true, + ) + val STRICT_KOTLIN_DEPS_OPTION: CliOption = + CliOption("strict_kotlin_deps", "", "Report strict deps violations", required = true) + } + + override val pluginId: String + get() = COMPILER_PLUGIN_ID + override val pluginOptions: Collection + get() = listOf( + OUTPUT_JDEPS_FILE_OPTION, + TARGET_LABEL_OPTION, + DIRECT_DEPENDENCIES_OPTION, + STRICT_KOTLIN_DEPS_OPTION, + ) + + override fun processOption( + option: AbstractCliOption, + value: String, + configuration: CompilerConfiguration, + ) { + when (option) { + OUTPUT_JDEPS_FILE_OPTION -> configuration.put(JdepsGenConfigurationKeys.OUTPUT_JDEPS, value) + TARGET_LABEL_OPTION -> configuration.put(JdepsGenConfigurationKeys.TARGET_LABEL, value) + DIRECT_DEPENDENCIES_OPTION -> configuration.appendList( + JdepsGenConfigurationKeys.DIRECT_DEPENDENCIES, + value, + ) + STRICT_KOTLIN_DEPS_OPTION -> configuration.put( + JdepsGenConfigurationKeys.STRICT_KOTLIN_DEPS, + value, + ) + else -> throw CliOptionProcessingException("Unknown option: ${option.optionName}") + } + } + + override fun CompilerConfiguration.appendList( + option: CompilerConfigurationKey>, + value: T, + ) { + val paths = getList(option).toMutableList() + paths.add(value) + put(option, paths) + } + + override fun CompilerConfiguration.appendList( + option: CompilerConfigurationKey>, + values: List, + ) { + val paths = getList(option).toMutableList() + paths.addAll(values) + put(option, paths) + } +} diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenComponentRegistrar.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenComponentRegistrar.kt new file mode 100644 index 000000000..c2d79d0a5 --- /dev/null +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenComponentRegistrar.kt @@ -0,0 +1,19 @@ +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8.jdeps + +import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor +import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension + +@OptIn(org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi::class) +class JdepsGenComponentRegistrar : CompilerPluginRegistrar() { + + override val supportsK2: Boolean = false + override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) { + // Capture all types referenced by the compiler for this module and look up the jar from which + // they were loaded from + val extension = JdepsGenExtension(configuration) + AnalysisHandlerExtension.registerExtension(extension) + StorageComponentContainerContributor.registerExtension(extension) + } +} diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenConfigurationKeys.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenConfigurationKeys.kt new file mode 100644 index 000000000..1414fabdf --- /dev/null +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenConfigurationKeys.kt @@ -0,0 +1,35 @@ +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8.jdeps + +import org.jetbrains.kotlin.config.CompilerConfigurationKey + +object JdepsGenConfigurationKeys { + /** + * Output path of generated Jdeps proto file. + */ + val OUTPUT_JDEPS: CompilerConfigurationKey = + CompilerConfigurationKey.create( + JdepsGenCommandLineProcessor.OUTPUT_JDEPS_FILE_OPTION.description, + ) + + /** + * Label of the Bazel target being analyzed. + */ + val TARGET_LABEL: CompilerConfigurationKey = + CompilerConfigurationKey.create(JdepsGenCommandLineProcessor.TARGET_LABEL_OPTION.description) + + /** + * Label of the Bazel target being analyzed. + */ + val STRICT_KOTLIN_DEPS: CompilerConfigurationKey = + CompilerConfigurationKey.create( + JdepsGenCommandLineProcessor.STRICT_KOTLIN_DEPS_OPTION.description, + ) + + /** + * List of direct dependencies of the target. + */ + val DIRECT_DEPENDENCIES: CompilerConfigurationKey> = + CompilerConfigurationKey.create( + JdepsGenCommandLineProcessor.DIRECT_DEPENDENCIES_OPTION.description, + ) +} diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenExtension.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenExtension.kt new file mode 100644 index 000000000..e12e1e7af --- /dev/null +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenExtension.kt @@ -0,0 +1,402 @@ +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8.jdeps + +import com.google.devtools.build.lib.view.proto.Deps +import com.intellij.mock.MockProject +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import io.bazel.kotlin.builder.utils.jars.JarOwner +import org.jetbrains.kotlin.analyzer.AnalysisResult +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.container.StorageComponentContainer +import org.jetbrains.kotlin.container.useInstance +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.ParameterDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.SourceElement +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor +import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor +import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor +import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor +import org.jetbrains.kotlin.load.java.sources.JavaSourceElement +import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass +import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaField +import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement +import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass +import org.jetbrains.kotlin.load.kotlin.getContainingKotlinJvmBinaryClass +import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.FunctionImportedFromObject +import org.jetbrains.kotlin.resolve.PropertyImportedFromObject +import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker +import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject +import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker +import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext +import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeConstructor +import org.jetbrains.kotlin.types.typeUtil.supertypes +import java.io.BufferedOutputStream +import java.io.File +import java.nio.file.Paths + +/** + * Kotlin compiler extension that tracks classes (and corresponding classpath jars) needed to + * compile current kotlin target. Tracked data should include all classes whose changes could + * affect target's compilation out : direct class dependencies (i.e. external classes directly + * used), but also their superclass, interfaces, etc. + * The primary use of this extension is to improve Kotlin module compilation avoidance in build + * systems (like Buck). + * + * Tracking of classes and their ancestors is done via modules and class + * descriptors that got generated during analysis/resolve phase of Kotlin compilation. + * + * Note: annotation processors dependencies may need to be tracked separately (and may not need + * per-class ABI change tracking) + * + * @param project the current compilation project + * @param configuration the current compilation configuration + */ +class JdepsGenExtension( + val configuration: CompilerConfiguration, +) : + AnalysisHandlerExtension, StorageComponentContainerContributor { + + companion object { + + /** + * Returns the path of the jar archive file corresponding to the provided descriptor. + * + * @descriptor the descriptor, typically obtained from compilation analyze phase + * @return the path corresponding to the JAR where this class was loaded from, or null. + */ + fun getClassCanonicalPath(descriptor: DeclarationDescriptorWithSource): String? { + return when (val sourceElement: SourceElement = descriptor.source) { + is JavaSourceElement -> + if (sourceElement.javaElement is BinaryJavaClass) { + (sourceElement.javaElement as BinaryJavaClass).virtualFile.canonicalPath + } else if (sourceElement.javaElement is BinaryJavaField) { + val containingClass = (sourceElement.javaElement as BinaryJavaField).containingClass + if (containingClass is BinaryJavaClass) { + containingClass.virtualFile.canonicalPath + } else { + null + } + } else { + // Ignore Java source local to this module. + null + } + is KotlinJvmBinarySourceElement -> + (sourceElement.binaryClass as VirtualFileKotlinClass).file.canonicalPath + else -> null + } + } + + fun getClassCanonicalPath(typeConstructor: TypeConstructor): String? { + return (typeConstructor.declarationDescriptor as? DeclarationDescriptorWithSource)?.let { + getClassCanonicalPath( + it, + ) + } + } + } + + private val explicitClassesCanonicalPaths = mutableSetOf() + private val implicitClassesCanonicalPaths = mutableSetOf() + + override fun registerModuleComponents( + container: StorageComponentContainer, + platform: TargetPlatform, + moduleDescriptor: ModuleDescriptor, + ) { + container.useInstance( + ClasspathCollectingChecker(explicitClassesCanonicalPaths, implicitClassesCanonicalPaths), + ) + } + + class ClasspathCollectingChecker( + private val explicitClassesCanonicalPaths: MutableSet, + private val implicitClassesCanonicalPaths: MutableSet, + ) : CallChecker, DeclarationChecker { + + override fun check( + resolvedCall: ResolvedCall<*>, + reportOn: PsiElement, + context: CallCheckerContext, + ) { + when (val resultingDescriptor = resolvedCall.resultingDescriptor) { + is FunctionImportedFromObject -> { + collectTypeReferences(resultingDescriptor.containingObject.defaultType) + } + is PropertyImportedFromObject -> { + collectTypeReferences(resultingDescriptor.containingObject.defaultType) + } + is JavaMethodDescriptor -> { + getClassCanonicalPath( + (resultingDescriptor.containingDeclaration as ClassDescriptor).typeConstructor, + )?.let { explicitClassesCanonicalPaths.add(it) } + } + is FunctionDescriptor -> { + resultingDescriptor.returnType?.let { addImplicitDep(it) } + resultingDescriptor.valueParameters.forEach { valueParameter -> + collectTypeReferences(valueParameter.type, isExplicit = false) + } + val virtualFileClass = + resultingDescriptor.getContainingKotlinJvmBinaryClass() as? VirtualFileKotlinClass + ?: return + explicitClassesCanonicalPaths.add(virtualFileClass.file.path) + } + is ParameterDescriptor -> { + getClassCanonicalPath(resultingDescriptor)?.let { explicitClassesCanonicalPaths.add(it) } + } + is FakeCallableDescriptorForObject -> { + collectTypeReferences(resultingDescriptor.type) + } + is JavaPropertyDescriptor -> { + getClassCanonicalPath(resultingDescriptor)?.let { explicitClassesCanonicalPaths.add(it) } + } + is PropertyDescriptor -> { + when (resultingDescriptor.containingDeclaration) { + is ClassDescriptor -> collectTypeReferences( + (resultingDescriptor.containingDeclaration as ClassDescriptor).defaultType, + ) + else -> { + val virtualFileClass = + (resultingDescriptor).getContainingKotlinJvmBinaryClass() as? VirtualFileKotlinClass + ?: return + explicitClassesCanonicalPaths.add(virtualFileClass.file.path) + } + } + addImplicitDep(resultingDescriptor.type) + } + else -> return + } + } + + override fun check( + declaration: KtDeclaration, + descriptor: DeclarationDescriptor, + context: DeclarationCheckerContext, + ) { + when (descriptor) { + is ClassDescriptor -> { + descriptor.typeConstructor.supertypes.forEach { + collectTypeReferences(it) + } + } + is FunctionDescriptor -> { + descriptor.returnType?.let { collectTypeReferences(it) } + descriptor.valueParameters.forEach { valueParameter -> + collectTypeReferences(valueParameter.type) + } + descriptor.annotations.forEach { annotation -> + collectTypeReferences(annotation.type) + } + descriptor.extensionReceiverParameter?.value?.type?.let { + collectTypeReferences(it) + } + } + is PropertyDescriptor -> { + collectTypeReferences(descriptor.type) + descriptor.annotations.forEach { annotation -> + collectTypeReferences(annotation.type) + } + descriptor.backingField?.annotations?.forEach { annotation -> + collectTypeReferences(annotation.type) + } + } + is LocalVariableDescriptor -> { + collectTypeReferences(descriptor.type) + } + } + } + + private fun addImplicitDep(it: KotlinType) { + getClassCanonicalPath(it.constructor)?.let { implicitClassesCanonicalPaths.add(it) } + } + + private fun addExplicitDep(it: KotlinType) { + getClassCanonicalPath(it.constructor)?.let { explicitClassesCanonicalPaths.add(it) } + } + + /** + * Records direct and indirect references for a given type. Direct references are explicitly + * used in the code, e.g: a type declaration or a generic type declaration. Indirect references + * are other types required for compilation such as supertypes and interfaces of those explicit + * types. + */ + private fun collectTypeReferences( + kotlinType: KotlinType, + isExplicit: Boolean = true, + ) { + if (isExplicit) { + addExplicitDep(kotlinType) + } else { + addImplicitDep(kotlinType) + } + + kotlinType.supertypes().forEach { + addImplicitDep(it) + } + + collectTypeArguments(kotlinType, isExplicit) + } + + private fun collectTypeArguments( + kotlinType: KotlinType, + isExplicit: Boolean, + visitedKotlinTypes: MutableSet = mutableSetOf(), + ) { + visitedKotlinTypes.add(kotlinType) + kotlinType.arguments.map { it.type }.forEach { typeArgument -> + if (isExplicit) { + addExplicitDep(typeArgument) + } else { + addImplicitDep(typeArgument) + } + typeArgument.supertypes().forEach { addImplicitDep(it) } + if (!visitedKotlinTypes.contains(typeArgument)) { + collectTypeArguments(typeArgument, isExplicit, visitedKotlinTypes) + } + } + } + } + + override fun analysisCompleted( + project: Project, + module: ModuleDescriptor, + bindingTrace: BindingTrace, + files: Collection, + ): AnalysisResult? { + val directDeps = configuration.getList(JdepsGenConfigurationKeys.DIRECT_DEPENDENCIES) + val targetLabel = configuration.getNotNull(JdepsGenConfigurationKeys.TARGET_LABEL) + val explicitDeps = createDepsMap(explicitClassesCanonicalPaths) + + doWriteJdeps(directDeps, targetLabel, explicitDeps) + + doStrictDeps(configuration, targetLabel, directDeps, explicitDeps) + + return super.analysisCompleted(project, module, bindingTrace, files) + } + + /** + * Returns a map of jars to classes loaded from those jars. + */ + private fun createDepsMap(classes: Set): Map> { + val jarsToClasses = mutableMapOf>() + classes.forEach { + val parts = it.split("!/") + val jarPath = parts[0] + if (jarPath.endsWith(".jar")) { + jarsToClasses.computeIfAbsent(jarPath) { ArrayList() }.add(parts[1]) + } + } + return jarsToClasses + } + + private fun doWriteJdeps( + directDeps: MutableList, + targetLabel: String, + explicitDeps: Map>, + ) { + val implicitDeps = createDepsMap(implicitClassesCanonicalPaths) + + // Build and write out deps.proto + val jdepsOutput = configuration.getNotNull(JdepsGenConfigurationKeys.OUTPUT_JDEPS) + + val rootBuilder = Deps.Dependencies.newBuilder() + rootBuilder.success = true + rootBuilder.ruleLabel = targetLabel + + val unusedDeps = directDeps.subtract(explicitDeps.keys) + unusedDeps.forEach { jarPath -> + val dependency = Deps.Dependency.newBuilder() + dependency.kind = Deps.Dependency.Kind.UNUSED + dependency.path = jarPath + rootBuilder.addDependency(dependency) + } + + explicitDeps.forEach { (jarPath, _) -> + val dependency = Deps.Dependency.newBuilder() + dependency.kind = Deps.Dependency.Kind.EXPLICIT + dependency.path = jarPath + rootBuilder.addDependency(dependency) + } + + implicitDeps.keys.subtract(explicitDeps.keys).forEach { + val dependency = Deps.Dependency.newBuilder() + dependency.kind = Deps.Dependency.Kind.IMPLICIT + dependency.path = it + rootBuilder.addDependency(dependency) + } + + BufferedOutputStream(File(jdepsOutput).outputStream()).use { + it.write(rootBuilder.build().toByteArray()) + } + } + + private fun doStrictDeps( + compilerConfiguration: CompilerConfiguration, + targetLabel: String, + directDeps: MutableList, + explicitDeps: Map>, + ) { + when (compilerConfiguration.getNotNull(JdepsGenConfigurationKeys.STRICT_KOTLIN_DEPS)) { + "warn" -> checkStrictDeps(explicitDeps, directDeps, targetLabel) + "error" -> { + if (checkStrictDeps(explicitDeps, directDeps, targetLabel)) { + error( + "Strict Deps Violations - please fix", + ) + } + } + } + } + + /** + * Prints strict deps warnings and returns true if violations were found. + */ + private fun checkStrictDeps( + result: Map>, + directDeps: List, + targetLabel: String, + ): Boolean { + val missingStrictDeps = result.keys + .filter { !directDeps.contains(it) } + .map { JarOwner.readJarOwnerFromManifest(Paths.get(it)) } + + if (missingStrictDeps.isNotEmpty()) { + val missingStrictLabels = missingStrictDeps.mapNotNull { it.label } + + val open = "\u001b[35m\u001b[1m" + val close = "\u001b[0m" + + var command = + """ + $open ** Please add the following dependencies:$close + ${ + missingStrictDeps.map { it.label ?: it.jar }.joinToString(" ") + } to $targetLabel + """ + + if (missingStrictLabels.isNotEmpty()) { + command += """$open ** You can use the following buildozer command:$close + buildozer 'add deps ${ + missingStrictLabels.joinToString(" ") + }' $targetLabel + """ + } + + println(command.trimIndent()) + return true + } + return false + } +} diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/jdeps/BUILD.bazel b/src/main/kotlin/io/bazel/kotlin/plugin/jdeps/BUILD.bazel deleted file mode 100644 index 60f5b07ee..000000000 --- a/src/main/kotlin/io/bazel/kotlin/plugin/jdeps/BUILD.bazel +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2020 The Bazel Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@rules_java//java:defs.bzl", "java_binary") -load("//src/main/kotlin:bootstrap.bzl", "kt_bootstrap_library") -load("//kotlin/internal/utils:generate_jvm_service.bzl", "generate_jvm_service") - -# The compiler binary, this is co-located in the kotlin compiler classloader. -kt_bootstrap_library( - name = "jdeps-gen-lib", - srcs = glob(["*.kt"]), - visibility = ["//src:__subpackages__"], - deps = [ - "//src/main/kotlin/io/bazel/kotlin/builder/utils/jars", - "//src/main/protobuf:deps_java_proto", - "@com_github_jetbrains_kotlin//:kotlin-compiler", - "@kotlin_rules_maven//:com_google_protobuf_protobuf_java", - ], -) - -# services to integrate with the plugin. -generate_jvm_service( - name = "jdeps-gen-services", - services = { - "io.bazel.kotlin.plugin.jdeps.JdepsGenComponentRegistrar": "org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar", - "io.bazel.kotlin.plugin.jdeps.JdepsGenCommandLineProcessor": "org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor", - }, -) - -# The plugin binary. -java_binary( - name = "jdeps-gen", - visibility = ["//src:__subpackages__"], - runtime_deps = [ - ":jdeps-gen-lib", - ":jdeps-gen-services", - ], -) From d6ccef20d11f3bd19a40251446567bbbcca051c0 Mon Sep 17 00:00:00 2001 From: Corbin McNeely-Smith <58151731+restingbull@users.noreply.github.com> Date: Sun, 13 Aug 2023 17:50:45 -0500 Subject: [PATCH 5/9] Fix unused --- src/main/starlark/core/repositories/initialize.release.bzl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/starlark/core/repositories/initialize.release.bzl b/src/main/starlark/core/repositories/initialize.release.bzl index ea57175e9..af9ab6ff4 100644 --- a/src/main/starlark/core/repositories/initialize.release.bzl +++ b/src/main/starlark/core/repositories/initialize.release.bzl @@ -29,7 +29,6 @@ load("//src/main/starlark/core/repositories/kotlin:compiler.bzl", "kotlin_compil load(":ksp.bzl", "ksp_compiler_plugin_repository") load( ":versions.bzl", - "version", _kotlinc_version = "kotlinc_version", _ksp_version = "ksp_version", _versions = "versions", From 67734a7b4340d63c25be26725ac653a17afb97ec Mon Sep 17 00:00:00 2001 From: Corbin McNeely-Smith <58151731+restingbull@users.noreply.github.com> Date: Sun, 13 Aug 2023 18:49:29 -0500 Subject: [PATCH 6/9] Fix broken doc generation Current stardoc cannot seem to handle dynamic key in dictionary comprehensions. The simple solution is to separate the KOTLINC_INDEX from the compiler repository definition. Has the added benefit of keeping development logic from production logic. --- .../bazel/kotlin/builder/utils/jars/BUILD.bazel | 2 +- .../kotlin/io/bazel/kotlin/plugin/BUILD.bazel | 4 +++- .../starlark/core/repositories/initialize.bzl | 3 ++- .../core/repositories/kotlin/compiler.bzl | 9 --------- .../core/repositories/kotlin/releases.bzl | 16 ++++++++++++++++ 5 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 src/main/starlark/core/repositories/kotlin/releases.bzl diff --git a/src/main/kotlin/io/bazel/kotlin/builder/utils/jars/BUILD.bazel b/src/main/kotlin/io/bazel/kotlin/builder/utils/jars/BUILD.bazel index 014ad7ba8..acc4a3cc0 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/utils/jars/BUILD.bazel +++ b/src/main/kotlin/io/bazel/kotlin/builder/utils/jars/BUILD.bazel @@ -1,4 +1,4 @@ -load("//src/main/starlark/core/repositories/kotlin:compiler.bzl", "KOTLINC_INDEX") +load("//src/main/starlark/core/repositories/kotlin:releases.bzl", "KOTLINC_INDEX") load("//src/main/kotlin:bootstrap.bzl", "kt_bootstrap_library") kt_bootstrap_library( diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/BUILD.bazel b/src/main/kotlin/io/bazel/kotlin/plugin/BUILD.bazel index 24209ee74..7e424a8fa 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/BUILD.bazel +++ b/src/main/kotlin/io/bazel/kotlin/plugin/BUILD.bazel @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -load("//src/main/starlark/core/repositories/kotlin:compiler.bzl", "KOTLINC_INDEX") +load("//src/main/starlark/core/repositories/kotlin:releases.bzl", "KOTLINC_INDEX") load("@rules_java//java:defs.bzl", "java_binary") load("//src/main/kotlin:bootstrap.bzl", "kt_bootstrap_library") load("//kotlin/internal/utils:generate_jvm_service.bzl", "generate_jvm_service") @@ -81,6 +81,7 @@ load("@com_github_jetbrains_kotlin//:version.bzl", KOTLINC_MAJOR_VERSION = "MAJO for version, release in KOTLINC_INDEX.items() ] +# Deploy jars are not aliased, so repack in a java_binary. java_binary( name = "skip-code-gen", visibility = ["//src:__subpackages__"], @@ -96,6 +97,7 @@ alias( visibility = ["//src:__subpackages__"], ) +# Deploy jars are not aliased, so repack in a java_binary. java_binary( name = "jdeps-gen", visibility = ["//src:__subpackages__"], diff --git a/src/main/starlark/core/repositories/initialize.bzl b/src/main/starlark/core/repositories/initialize.bzl index ecaead690..f7d8b01c4 100644 --- a/src/main/starlark/core/repositories/initialize.bzl +++ b/src/main/starlark/core/repositories/initialize.bzl @@ -22,7 +22,8 @@ load( _ksp_version = "ksp_version", _release_kotlin_repositories = "kotlin_repositories", ) -load("//src/main/starlark/core/repositories/kotlin:compiler.bzl", "KOTLINC_INDEX", "kotlin_compiler_repository") +load("//src/main/starlark/core/repositories/kotlin:compiler.bzl", "kotlin_compiler_repository") +load("//src/main/starlark/core/repositories/kotlin:releases.bzl", "KOTLINC_INDEX") load(":versions.bzl", _versions = "versions") #exports diff --git a/src/main/starlark/core/repositories/kotlin/compiler.bzl b/src/main/starlark/core/repositories/kotlin/compiler.bzl index 21c6b1cdc..9ff3ef9c8 100644 --- a/src/main/starlark/core/repositories/kotlin/compiler.bzl +++ b/src/main/starlark/core/repositories/kotlin/compiler.bzl @@ -9,15 +9,6 @@ _CAPABILITIES_TEMPLATES = { "1.8": "capabilities_1.8.bzl.com_github_jetbrains_kotlin.bazel", } -# Index of major kotlinc revision to calculated repository name and release. -KOTLINC_INDEX = { - versions.get_major(compiler_release.version): struct( - repository_name = "com_github_jetbrains_kotlin_%s" % versions.get_major(compiler_release.version).replace(".", "_"), - release = compiler_release, - ) - for compiler_release in versions.KOTLIN_COMPILER_RELEASES -} - def _kotlin_compiler_impl(repository_ctx): """Creates the kotlinc repository.""" attr = repository_ctx.attr diff --git a/src/main/starlark/core/repositories/kotlin/releases.bzl b/src/main/starlark/core/repositories/kotlin/releases.bzl new file mode 100644 index 000000000..73d9480e7 --- /dev/null +++ b/src/main/starlark/core/repositories/kotlin/releases.bzl @@ -0,0 +1,16 @@ +"""Kotlinc releases indexed by major versions.""" + +load("//src/main/starlark/core/repositories:versions.bzl", "versions") + +# Index of major kotlinc revision to calculated repository name and release. +KOTLINC_INDEX = { + major: struct( + # defining the expected repository name to reduce toil when updating. + repository_name = "com_github_jetbrains_kotlin_%s" % major.replace(".", "_"), + release = release, + ) + for (major, release) in [ + (versions.get_major(compiler_release.version), compiler_release) + for compiler_release in versions.KOTLIN_COMPILER_RELEASES + ] +} From a6a96ee206af272847d2c2cdf3f2bf85cd1a143b Mon Sep 17 00:00:00 2001 From: Corbin McNeely-Smith <58151731+restingbull@users.noreply.github.com> Date: Sun, 13 Aug 2023 18:50:46 -0500 Subject: [PATCH 7/9] ktlint on the plugins. This was apparently skipped on previous passes. --- .../SkipCodeGen.kt | 1 + .../jdeps/JdepsGenCommandLineProcessor.kt | 37 +++++- .../jdeps/JdepsGenComponentRegistrar.kt | 8 +- .../jdeps/JdepsGenConfigurationKeys.kt | 16 ++- .../jdeps/JdepsGenExtension.kt | 111 ++++++++++++++---- .../SkipCodeGen.kt | 1 + .../jdeps/JdepsGenCommandLineProcessor.kt | 4 + .../jdeps/JdepsGenComponentRegistrar.kt | 2 + .../jdeps/JdepsGenConfigurationKeys.kt | 2 + .../jdeps/JdepsGenExtension.kt | 16 +++ .../SkipCodeGen.kt | 2 + .../jdeps/JdepsGenCommandLineProcessor.kt | 7 +- .../jdeps/JdepsGenComponentRegistrar.kt | 1 + .../jdeps/JdepsGenConfigurationKeys.kt | 1 + .../jdeps/JdepsGenExtension.kt | 16 ++- 15 files changed, 183 insertions(+), 42 deletions(-) diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/SkipCodeGen.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/SkipCodeGen.kt index a346e038d..daf5d1ccc 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/SkipCodeGen.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/SkipCodeGen.kt @@ -14,6 +14,7 @@ * limitations under the License. * */ +@file:Suppress("ktlint:standard:package-name") package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_6 import com.google.common.base.Preconditions diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenCommandLineProcessor.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenCommandLineProcessor.kt index 6bdc74b96..327bdbf85 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenCommandLineProcessor.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenCommandLineProcessor.kt @@ -1,4 +1,6 @@ -package io.bazel.kotlin.plugin.jdeps +@file:Suppress("ktlint:standard:package-name") + +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_6.jdeps import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption import org.jetbrains.kotlin.compiler.plugin.CliOption @@ -15,7 +17,13 @@ class JdepsGenCommandLineProcessor : CommandLineProcessor { val TARGET_LABEL_OPTION: CliOption = CliOption("target_label", "", "Label of target being analyzed", required = true) val DIRECT_DEPENDENCIES_OPTION: CliOption = - CliOption("direct_dependencies", "", "List of targets direct dependencies", required = false, allowMultipleOccurrences = true) + CliOption( + "direct_dependencies", + "", + "List of targets direct dependencies", + required = false, + allowMultipleOccurrences = true, + ) val STRICT_KOTLIN_DEPS_OPTION: CliOption = CliOption("strict_kotlin_deps", "", "Report strict deps violations", required = true) } @@ -23,14 +31,31 @@ class JdepsGenCommandLineProcessor : CommandLineProcessor { override val pluginId: String get() = COMPILER_PLUGIN_ID override val pluginOptions: Collection - get() = listOf(OUTPUT_JDEPS_FILE_OPTION, TARGET_LABEL_OPTION, DIRECT_DEPENDENCIES_OPTION, STRICT_KOTLIN_DEPS_OPTION) + get() = listOf( + OUTPUT_JDEPS_FILE_OPTION, + TARGET_LABEL_OPTION, + DIRECT_DEPENDENCIES_OPTION, + STRICT_KOTLIN_DEPS_OPTION, + ) - override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) { + override fun processOption( + option: AbstractCliOption, + value: String, + configuration: CompilerConfiguration, + ) { when (option) { OUTPUT_JDEPS_FILE_OPTION -> configuration.put(JdepsGenConfigurationKeys.OUTPUT_JDEPS, value) TARGET_LABEL_OPTION -> configuration.put(JdepsGenConfigurationKeys.TARGET_LABEL, value) - DIRECT_DEPENDENCIES_OPTION -> configuration.appendList(JdepsGenConfigurationKeys.DIRECT_DEPENDENCIES, value) - STRICT_KOTLIN_DEPS_OPTION -> configuration.put(JdepsGenConfigurationKeys.STRICT_KOTLIN_DEPS, value) + DIRECT_DEPENDENCIES_OPTION -> configuration.appendList( + JdepsGenConfigurationKeys.DIRECT_DEPENDENCIES, + value, + ) + + STRICT_KOTLIN_DEPS_OPTION -> configuration.put( + JdepsGenConfigurationKeys.STRICT_KOTLIN_DEPS, + value, + ) + else -> throw CliOptionProcessingException("Unknown option: ${option.optionName}") } } diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenComponentRegistrar.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenComponentRegistrar.kt index b74642edf..55d450971 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenComponentRegistrar.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenComponentRegistrar.kt @@ -1,7 +1,8 @@ -package io.bazel.kotlin.plugin.jdeps +@file:Suppress("ktlint:standard:package-name") + +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_6.jdeps import com.intellij.mock.MockProject -import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor @@ -11,9 +12,8 @@ class JdepsGenComponentRegistrar : ComponentRegistrar { override fun registerProjectComponents( project: MockProject, - configuration: CompilerConfiguration + configuration: CompilerConfiguration, ) { - // Capture all types referenced by the compiler for this module and look up the jar from which // they were loaded from val extension = JdepsGenExtension(project, configuration) diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenConfigurationKeys.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenConfigurationKeys.kt index ff7b2d8c9..3dcfe70b4 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenConfigurationKeys.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenConfigurationKeys.kt @@ -1,4 +1,6 @@ -package io.bazel.kotlin.plugin.jdeps +@file:Suppress("ktlint:standard:package-name") + +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_6.jdeps import org.jetbrains.kotlin.config.CompilerConfigurationKey @@ -7,7 +9,9 @@ object JdepsGenConfigurationKeys { * Output path of generated Jdeps proto file. */ val OUTPUT_JDEPS: CompilerConfigurationKey = - CompilerConfigurationKey.create(JdepsGenCommandLineProcessor.OUTPUT_JDEPS_FILE_OPTION.description) + CompilerConfigurationKey.create( + JdepsGenCommandLineProcessor.OUTPUT_JDEPS_FILE_OPTION.description, + ) /** * Label of the Bazel target being analyzed. @@ -19,11 +23,15 @@ object JdepsGenConfigurationKeys { * Label of the Bazel target being analyzed. */ val STRICT_KOTLIN_DEPS: CompilerConfigurationKey = - CompilerConfigurationKey.create(JdepsGenCommandLineProcessor.STRICT_KOTLIN_DEPS_OPTION.description) + CompilerConfigurationKey.create( + JdepsGenCommandLineProcessor.STRICT_KOTLIN_DEPS_OPTION.description, + ) /** * List of direct dependencies of the target. */ val DIRECT_DEPENDENCIES: CompilerConfigurationKey> = - CompilerConfigurationKey.create(JdepsGenCommandLineProcessor.DIRECT_DEPENDENCIES_OPTION.description) + CompilerConfigurationKey.create( + JdepsGenCommandLineProcessor.DIRECT_DEPENDENCIES_OPTION.description, + ) } diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenExtension.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenExtension.kt index 5a2f9f3ce..6e08b42f7 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenExtension.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/jdeps/JdepsGenExtension.kt @@ -1,4 +1,6 @@ -package io.bazel.kotlin.plugin.jdeps +@file:Suppress("ktlint:standard:package-name") + +package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_6.jdeps import com.google.devtools.build.lib.view.proto.Deps import com.intellij.mock.MockProject @@ -67,7 +69,8 @@ import java.nio.file.Paths */ class JdepsGenExtension( val project: MockProject, - val configuration: CompilerConfiguration) : + val configuration: CompilerConfiguration, +) : AnalysisHandlerExtension, StorageComponentContainerContributor { companion object { @@ -94,14 +97,20 @@ class JdepsGenExtension( // Ignore Java source local to this module. null } + is KotlinJvmBinarySourceElement -> (sourceElement.binaryClass as VirtualFileKotlinClass).file.canonicalPath + else -> null } } fun getClassCanonicalPath(typeConstructor: TypeConstructor): String? { - return (typeConstructor.declarationDescriptor as? DeclarationDescriptorWithSource)?.let { getClassCanonicalPath(it) } + return (typeConstructor.declarationDescriptor as? DeclarationDescriptorWithSource)?.let { + getClassCanonicalPath( + it, + ) + } } } @@ -111,59 +120,90 @@ class JdepsGenExtension( override fun registerModuleComponents( container: StorageComponentContainer, platform: TargetPlatform, - moduleDescriptor: ModuleDescriptor + moduleDescriptor: ModuleDescriptor, ) { - container.useInstance(ClasspathCollectingChecker(explicitClassesCanonicalPaths, implicitClassesCanonicalPaths)) + container.useInstance( + ClasspathCollectingChecker( + explicitClassesCanonicalPaths, + implicitClassesCanonicalPaths, + ), + ) } class ClasspathCollectingChecker( private val explicitClassesCanonicalPaths: MutableSet, - private val implicitClassesCanonicalPaths: MutableSet + private val implicitClassesCanonicalPaths: MutableSet, ) : CallChecker, DeclarationChecker { override fun check( resolvedCall: ResolvedCall<*>, reportOn: PsiElement, - context: CallCheckerContext + context: CallCheckerContext, ) { when (val resultingDescriptor = resolvedCall.resultingDescriptor) { is FunctionImportedFromObject -> { - collectTypeReferences((resolvedCall.resultingDescriptor as FunctionImportedFromObject).containingObject.defaultType) + collectTypeReferences( + (resolvedCall.resultingDescriptor as FunctionImportedFromObject) + .containingObject.defaultType, + ) } + is PropertyImportedFromObject -> { - collectTypeReferences((resolvedCall.resultingDescriptor as PropertyImportedFromObject).containingObject.defaultType) + collectTypeReferences( + (resolvedCall.resultingDescriptor as PropertyImportedFromObject) + .containingObject.defaultType, + ) } + is JavaMethodDescriptor -> { - getClassCanonicalPath((resultingDescriptor.containingDeclaration as ClassDescriptor).typeConstructor)?.let { explicitClassesCanonicalPaths.add(it) } + getClassCanonicalPath( + (resultingDescriptor.containingDeclaration as ClassDescriptor).typeConstructor, + )?.let { + explicitClassesCanonicalPaths.add( + it, + ) + } } + is FunctionDescriptor -> { resultingDescriptor.returnType?.let { addImplicitDep(it) } resultingDescriptor.valueParameters.forEach { valueParameter -> addImplicitDep(valueParameter.type) } - val virtualFileClass = resultingDescriptor.getContainingKotlinJvmBinaryClass() as? VirtualFileKotlinClass - ?: return + val virtualFileClass = + resultingDescriptor.getContainingKotlinJvmBinaryClass() as? VirtualFileKotlinClass + ?: return explicitClassesCanonicalPaths.add(virtualFileClass.file.path) } + is ParameterDescriptor -> { getClassCanonicalPath(resultingDescriptor)?.let { explicitClassesCanonicalPaths.add(it) } } + is FakeCallableDescriptorForObject -> { collectTypeReferences(resultingDescriptor.type) } + is JavaPropertyDescriptor -> { getClassCanonicalPath(resultingDescriptor)?.let { explicitClassesCanonicalPaths.add(it) } } + is PropertyDescriptor -> { when (resultingDescriptor.containingDeclaration) { - is ClassDescriptor -> collectTypeReferences((resultingDescriptor.containingDeclaration as ClassDescriptor).defaultType) + is ClassDescriptor -> collectTypeReferences( + (resultingDescriptor.containingDeclaration as ClassDescriptor).defaultType, + ) + else -> { - val virtualFileClass = (resultingDescriptor).getContainingKotlinJvmBinaryClass() as? VirtualFileKotlinClass ?: return + val virtualFileClass = + (resultingDescriptor).getContainingKotlinJvmBinaryClass() as? VirtualFileKotlinClass + ?: return explicitClassesCanonicalPaths.add(virtualFileClass.file.path) } } addImplicitDep(resultingDescriptor.type) } + else -> return } } @@ -171,7 +211,7 @@ class JdepsGenExtension( override fun check( declaration: KtDeclaration, descriptor: DeclarationDescriptor, - context: DeclarationCheckerContext + context: DeclarationCheckerContext, ) { when (descriptor) { is ClassDescriptor -> { @@ -179,6 +219,7 @@ class JdepsGenExtension( collectTypeReferences(it) } } + is FunctionDescriptor -> { descriptor.returnType?.let { collectTypeReferences(it) } descriptor.valueParameters.forEach { valueParameter -> @@ -188,6 +229,7 @@ class JdepsGenExtension( collectTypeReferences(annotation.type) } } + is PropertyDescriptor -> { collectTypeReferences(descriptor.type) descriptor.annotations.forEach { annotation -> @@ -197,6 +239,7 @@ class JdepsGenExtension( collectTypeReferences(annotation.type) } } + is LocalVariableDescriptor -> { collectTypeReferences(descriptor.type) } @@ -229,7 +272,10 @@ class JdepsGenExtension( collectTypeArguments(kotlinType) } - fun collectTypeArguments(kotlinType: KotlinType, visitedKotlinTypes: MutableSet = mutableSetOf()) { + fun collectTypeArguments( + kotlinType: KotlinType, + visitedKotlinTypes: MutableSet = mutableSetOf(), + ) { visitedKotlinTypes.add(kotlinType) kotlinType.arguments.map { it.type }.forEach { typeArgument -> addExplicitDep(typeArgument) @@ -245,7 +291,7 @@ class JdepsGenExtension( project: Project, module: ModuleDescriptor, bindingTrace: BindingTrace, - files: Collection + files: Collection, ): AnalysisResult? { val directDeps = configuration.getList(JdepsGenConfigurationKeys.DIRECT_DEPENDENCIES) val targetLabel = configuration.getNotNull(JdepsGenConfigurationKeys.TARGET_LABEL) @@ -276,9 +322,8 @@ class JdepsGenExtension( private fun doWriteJdeps( directDeps: MutableList, targetLabel: String, - explicitDeps: Map> + explicitDeps: Map>, ) { - val implicitDeps = createDepsMap(implicitClassesCanonicalPaths) // Build and write out deps.proto @@ -319,11 +364,19 @@ class JdepsGenExtension( compilerConfiguration: CompilerConfiguration, targetLabel: String, directDeps: MutableList, - explicitDeps: Map>) { + explicitDeps: Map>, + ) { when (compilerConfiguration.getNotNull(JdepsGenConfigurationKeys.STRICT_KOTLIN_DEPS)) { "warn" -> checkStrictDeps(explicitDeps, directDeps, targetLabel) "error" -> { - if (checkStrictDeps(explicitDeps, directDeps, targetLabel)) error("Strict Deps Violations - please fix") + if (checkStrictDeps( + explicitDeps, + directDeps, + targetLabel, + ) + ) { + error("Strict Deps Violations - please fix") + } } } } @@ -334,7 +387,7 @@ class JdepsGenExtension( private fun checkStrictDeps( result: Map>, directDeps: List, - targetLabel: String + targetLabel: String, ): Boolean { val missingStrictDeps = result.keys .filter { !directDeps.contains(it) } @@ -345,9 +398,17 @@ class JdepsGenExtension( val close = "\u001b[0m" val command = """ - |$open ** Please add the following dependencies:$close ${missingStrictDeps.joinToString(" ")} to $targetLabel - |$open ** You can use the following buildozer command:$close buildozer 'add deps ${missingStrictDeps.joinToString(" ")}' $targetLabel - """.trimMargin() + |$open ** Please add the following dependencies:$close ${ + missingStrictDeps.joinToString( + " ", + ) + } to $targetLabel + |$open ** You can use the following buildozer command:$close buildozer 'add deps ${ + missingStrictDeps.joinToString( + " ", + ) + }' $targetLabel + """.trimMargin() println(command) return true diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/SkipCodeGen.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/SkipCodeGen.kt index a5510e5d0..7b5ac1d2b 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/SkipCodeGen.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/SkipCodeGen.kt @@ -14,6 +14,7 @@ * limitations under the License. * */ +@file:Suppress("ktlint:standard:package-name") package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_7 import com.google.common.base.Preconditions diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenCommandLineProcessor.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenCommandLineProcessor.kt index 1c6d1960c..778814b90 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenCommandLineProcessor.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenCommandLineProcessor.kt @@ -1,3 +1,5 @@ +@file:Suppress("ktlint:standard:package-name") + package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_7.jdeps import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption @@ -49,10 +51,12 @@ class JdepsGenCommandLineProcessor : CommandLineProcessor { JdepsGenConfigurationKeys.DIRECT_DEPENDENCIES, value, ) + STRICT_KOTLIN_DEPS_OPTION -> configuration.put( JdepsGenConfigurationKeys.STRICT_KOTLIN_DEPS, value, ) + else -> throw CliOptionProcessingException("Unknown option: ${option.optionName}") } } diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenComponentRegistrar.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenComponentRegistrar.kt index 226e92df1..f7dc6001e 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenComponentRegistrar.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenComponentRegistrar.kt @@ -1,3 +1,5 @@ +@file:Suppress("ktlint:standard:package-name") + package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_7.jdeps import com.intellij.mock.MockProject diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenConfigurationKeys.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenConfigurationKeys.kt index 528cf1499..b3f0afe69 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenConfigurationKeys.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenConfigurationKeys.kt @@ -1,3 +1,5 @@ +@file:Suppress("ktlint:standard:package-name") + package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_7.jdeps import org.jetbrains.kotlin.config.CompilerConfigurationKey diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenExtension.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenExtension.kt index dcd819225..f87b0f63e 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenExtension.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/jdeps/JdepsGenExtension.kt @@ -1,3 +1,5 @@ +@file:Suppress("ktlint:standard:package-name") + package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_7.jdeps import com.google.devtools.build.lib.view.proto.Deps @@ -94,8 +96,10 @@ class JdepsGenExtension( // Ignore Java source local to this module. null } + is KotlinJvmBinarySourceElement -> (sourceElement.binaryClass as VirtualFileKotlinClass).file.canonicalPath + else -> null } } @@ -136,14 +140,17 @@ class JdepsGenExtension( is FunctionImportedFromObject -> { collectTypeReferences(resultingDescriptor.containingObject.defaultType) } + is PropertyImportedFromObject -> { collectTypeReferences(resultingDescriptor.containingObject.defaultType) } + is JavaMethodDescriptor -> { getClassCanonicalPath( (resultingDescriptor.containingDeclaration as ClassDescriptor).typeConstructor, )?.let { explicitClassesCanonicalPaths.add(it) } } + is FunctionDescriptor -> { resultingDescriptor.returnType?.let { addImplicitDep(it) } resultingDescriptor.valueParameters.forEach { valueParameter -> @@ -154,20 +161,25 @@ class JdepsGenExtension( ?: return explicitClassesCanonicalPaths.add(virtualFileClass.file.path) } + is ParameterDescriptor -> { getClassCanonicalPath(resultingDescriptor)?.let { explicitClassesCanonicalPaths.add(it) } } + is FakeCallableDescriptorForObject -> { collectTypeReferences(resultingDescriptor.type) } + is JavaPropertyDescriptor -> { getClassCanonicalPath(resultingDescriptor)?.let { explicitClassesCanonicalPaths.add(it) } } + is PropertyDescriptor -> { when (resultingDescriptor.containingDeclaration) { is ClassDescriptor -> collectTypeReferences( (resultingDescriptor.containingDeclaration as ClassDescriptor).defaultType, ) + else -> { val virtualFileClass = (resultingDescriptor).getContainingKotlinJvmBinaryClass() as? VirtualFileKotlinClass @@ -177,6 +189,7 @@ class JdepsGenExtension( } addImplicitDep(resultingDescriptor.type) } + else -> return } } @@ -192,6 +205,7 @@ class JdepsGenExtension( collectTypeReferences(it) } } + is FunctionDescriptor -> { descriptor.returnType?.let { collectTypeReferences(it) } descriptor.valueParameters.forEach { valueParameter -> @@ -204,6 +218,7 @@ class JdepsGenExtension( collectTypeReferences(it) } } + is PropertyDescriptor -> { collectTypeReferences(descriptor.type) descriptor.annotations.forEach { annotation -> @@ -213,6 +228,7 @@ class JdepsGenExtension( collectTypeReferences(annotation.type) } } + is LocalVariableDescriptor -> { collectTypeReferences(descriptor.type) } diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/SkipCodeGen.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/SkipCodeGen.kt index 60fe3ee5b..1d3b78aad 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/SkipCodeGen.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/SkipCodeGen.kt @@ -14,6 +14,8 @@ * limitations under the License. * */ +@file:Suppress("ktlint:standard:package-name") + package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8 import com.google.common.base.Preconditions diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenCommandLineProcessor.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenCommandLineProcessor.kt index 905f74b60..1c7588981 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenCommandLineProcessor.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenCommandLineProcessor.kt @@ -1,3 +1,4 @@ +@file:Suppress("ktlint:standard:package-name") package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8.jdeps import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption @@ -47,13 +48,15 @@ class JdepsGenCommandLineProcessor : CommandLineProcessor { OUTPUT_JDEPS_FILE_OPTION -> configuration.put(JdepsGenConfigurationKeys.OUTPUT_JDEPS, value) TARGET_LABEL_OPTION -> configuration.put(JdepsGenConfigurationKeys.TARGET_LABEL, value) DIRECT_DEPENDENCIES_OPTION -> configuration.appendList( - JdepsGenConfigurationKeys.DIRECT_DEPENDENCIES, + JdepsGenConfigurationKeys.DIRECT_DEPENDENCIES, value, ) + STRICT_KOTLIN_DEPS_OPTION -> configuration.put( - JdepsGenConfigurationKeys.STRICT_KOTLIN_DEPS, + JdepsGenConfigurationKeys.STRICT_KOTLIN_DEPS, value, ) + else -> throw CliOptionProcessingException("Unknown option: ${option.optionName}") } } diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenComponentRegistrar.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenComponentRegistrar.kt index c2d79d0a5..d6b7b15da 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenComponentRegistrar.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenComponentRegistrar.kt @@ -1,3 +1,4 @@ +@file:Suppress("ktlint:standard:package-name") package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8.jdeps import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenConfigurationKeys.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenConfigurationKeys.kt index 1414fabdf..ef25058e6 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenConfigurationKeys.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenConfigurationKeys.kt @@ -1,3 +1,4 @@ +@file:Suppress("ktlint:standard:package-name") package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8.jdeps import org.jetbrains.kotlin.config.CompilerConfigurationKey diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenExtension.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenExtension.kt index e12e1e7af..d5e5db99d 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenExtension.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenExtension.kt @@ -1,7 +1,7 @@ +@file:Suppress("ktlint:standard:package-name") package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8.jdeps import com.google.devtools.build.lib.view.proto.Deps -import com.intellij.mock.MockProject import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement import io.bazel.kotlin.builder.utils.jars.JarOwner @@ -93,8 +93,10 @@ class JdepsGenExtension( // Ignore Java source local to this module. null } + is KotlinJvmBinarySourceElement -> (sourceElement.binaryClass as VirtualFileKotlinClass).file.canonicalPath + else -> null } } @@ -135,14 +137,17 @@ class JdepsGenExtension( is FunctionImportedFromObject -> { collectTypeReferences(resultingDescriptor.containingObject.defaultType) } + is PropertyImportedFromObject -> { collectTypeReferences(resultingDescriptor.containingObject.defaultType) } + is JavaMethodDescriptor -> { getClassCanonicalPath( (resultingDescriptor.containingDeclaration as ClassDescriptor).typeConstructor, )?.let { explicitClassesCanonicalPaths.add(it) } } + is FunctionDescriptor -> { resultingDescriptor.returnType?.let { addImplicitDep(it) } resultingDescriptor.valueParameters.forEach { valueParameter -> @@ -153,20 +158,25 @@ class JdepsGenExtension( ?: return explicitClassesCanonicalPaths.add(virtualFileClass.file.path) } + is ParameterDescriptor -> { getClassCanonicalPath(resultingDescriptor)?.let { explicitClassesCanonicalPaths.add(it) } } + is FakeCallableDescriptorForObject -> { collectTypeReferences(resultingDescriptor.type) } + is JavaPropertyDescriptor -> { getClassCanonicalPath(resultingDescriptor)?.let { explicitClassesCanonicalPaths.add(it) } } + is PropertyDescriptor -> { when (resultingDescriptor.containingDeclaration) { is ClassDescriptor -> collectTypeReferences( (resultingDescriptor.containingDeclaration as ClassDescriptor).defaultType, ) + else -> { val virtualFileClass = (resultingDescriptor).getContainingKotlinJvmBinaryClass() as? VirtualFileKotlinClass @@ -176,6 +186,7 @@ class JdepsGenExtension( } addImplicitDep(resultingDescriptor.type) } + else -> return } } @@ -191,6 +202,7 @@ class JdepsGenExtension( collectTypeReferences(it) } } + is FunctionDescriptor -> { descriptor.returnType?.let { collectTypeReferences(it) } descriptor.valueParameters.forEach { valueParameter -> @@ -203,6 +215,7 @@ class JdepsGenExtension( collectTypeReferences(it) } } + is PropertyDescriptor -> { collectTypeReferences(descriptor.type) descriptor.annotations.forEach { annotation -> @@ -212,6 +225,7 @@ class JdepsGenExtension( collectTypeReferences(annotation.type) } } + is LocalVariableDescriptor -> { collectTypeReferences(descriptor.type) } From 20b6462233b7e4113fe867c75094b749f1a53403 Mon Sep 17 00:00:00 2001 From: Corbin McNeely-Smith <58151731+restingbull@users.noreply.github.com> Date: Sun, 13 Aug 2023 18:56:45 -0500 Subject: [PATCH 8/9] Update docs with new verisons utility function. --- docs/kotlin.md | 18 ++++++++++++++++++ kotlin/BUILD | 14 +++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/docs/kotlin.md b/docs/kotlin.md index 534ac1c61..1ca735d2d 100755 --- a/docs/kotlin.md +++ b/docs/kotlin.md @@ -567,3 +567,21 @@ versions.use_repository(name, kwargs |

-

| none | + + +## versions.get_major + +
+versions.get_major(version)
+
+ + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| version |

-

| none | + + diff --git a/kotlin/BUILD b/kotlin/BUILD index e5919ea1b..6e04f5e26 100644 --- a/kotlin/BUILD +++ b/kotlin/BUILD @@ -54,13 +54,13 @@ release_archive( genrule( name = "stardoc", - srcs = [doc for doc in [ - "js", - "jvm", - "lint", - "core", - "repositories.doc", - ]], + srcs = [ + ":js", + ":jvm", + ":lint", + ":core", + ":repositories.doc", + ], outs = ["kotlin.md"], cmd = """ for md in $(SRCS); do From d1691fe0cc263394d06a45ce9cf366f41163f088 Mon Sep 17 00:00:00 2001 From: Corbin McNeely-Smith <58151731+restingbull@users.noreply.github.com> Date: Sun, 13 Aug 2023 18:58:07 -0500 Subject: [PATCH 9/9] Fix package supression annotation --- .../kotlin/plugin/com_github_jetbrains_kotlin_1_6/SkipCodeGen.kt | 1 + .../kotlin/plugin/com_github_jetbrains_kotlin_1_7/SkipCodeGen.kt | 1 + .../jdeps/JdepsGenCommandLineProcessor.kt | 1 + .../jdeps/JdepsGenComponentRegistrar.kt | 1 + .../jdeps/JdepsGenConfigurationKeys.kt | 1 + .../com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenExtension.kt | 1 + 6 files changed, 6 insertions(+) diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/SkipCodeGen.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/SkipCodeGen.kt index daf5d1ccc..13e2f0ebe 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/SkipCodeGen.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_6/SkipCodeGen.kt @@ -15,6 +15,7 @@ * */ @file:Suppress("ktlint:standard:package-name") + package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_6 import com.google.common.base.Preconditions diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/SkipCodeGen.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/SkipCodeGen.kt index 7b5ac1d2b..e6c20746d 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/SkipCodeGen.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_7/SkipCodeGen.kt @@ -15,6 +15,7 @@ * */ @file:Suppress("ktlint:standard:package-name") + package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_7 import com.google.common.base.Preconditions diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenCommandLineProcessor.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenCommandLineProcessor.kt index 1c7588981..92ed015b8 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenCommandLineProcessor.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenCommandLineProcessor.kt @@ -1,4 +1,5 @@ @file:Suppress("ktlint:standard:package-name") + package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8.jdeps import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenComponentRegistrar.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenComponentRegistrar.kt index d6b7b15da..7a4b94a63 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenComponentRegistrar.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenComponentRegistrar.kt @@ -1,4 +1,5 @@ @file:Suppress("ktlint:standard:package-name") + package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8.jdeps import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenConfigurationKeys.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenConfigurationKeys.kt index ef25058e6..74921063d 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenConfigurationKeys.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenConfigurationKeys.kt @@ -1,4 +1,5 @@ @file:Suppress("ktlint:standard:package-name") + package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8.jdeps import org.jetbrains.kotlin.config.CompilerConfigurationKey diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenExtension.kt b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenExtension.kt index d5e5db99d..10dc91f12 100644 --- a/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenExtension.kt +++ b/src/main/kotlin/io/bazel/kotlin/plugin/com_github_jetbrains_kotlin_1_8/jdeps/JdepsGenExtension.kt @@ -1,4 +1,5 @@ @file:Suppress("ktlint:standard:package-name") + package io.bazel.kotlin.plugin.com_github_jetbrains_kotlin_1_8.jdeps import com.google.devtools.build.lib.view.proto.Deps