diff --git a/kotlin/internal/jvm/compile.bzl b/kotlin/internal/jvm/compile.bzl index 4d41ab1f2..0a0e9b412 100644 --- a/kotlin/internal/jvm/compile.bzl +++ b/kotlin/internal/jvm/compile.bzl @@ -64,9 +64,18 @@ def find_java_runtime_toolchain(ctx, target): def _java_info(target): return target[JavaInfo] if JavaInfo in target else None -def _deps_artifacts(toolchains, targets): +def _report_unused_deps(ctx, toolchains): + if "kt_experimental_report_unused_deps_off" in ctx.attr.tags: + return "off" + if "kt_experimental_report_unused_deps_warn" in ctx.attr.tags: + return "warn" + if "kt_experimental_report_unused_deps_error" in ctx.attr.tags: + return "error" + return toolchains.kt.experimental_report_unused_deps + +def _deps_artifacts(ctx, toolchains, targets): """Collect Jdeps artifacts if required.""" - if not toolchains.kt.experimental_report_unused_deps == "off": + if not _report_unused_deps(ctx, toolchains) == "off": deps_artifacts = [t[JavaInfo].outputs.jdeps for t in targets if JavaInfo in t and t[JavaInfo].outputs.jdeps] else: deps_artifacts = [] @@ -320,7 +329,13 @@ def _run_merge_jdeps_action(ctx, toolchains, jdeps, outputs, deps): args.add("--" + f, path) args.add_all("--inputs", jdeps, omit_if_empty = True) - args.add("--report_unused_deps", toolchains.kt.experimental_report_unused_deps) + args.add("--report_unused_deps", _report_unused_deps(ctx, toolchains)) + unused_deps_ignored_targets = [ + tag.split(":", 1)[1] + for tag in ctx.attr.tags + if tag.startswith("kt_experimental_unused_deps_ignored_targets:") + ] + args.add_all("--unused_deps_ignored_targets", unused_deps_ignored_targets, omit_if_empty = True) mnemonic = "JdepsMerge" progress_message = "%s %%{label} { jdeps: %d }" % ( @@ -329,7 +344,7 @@ def _run_merge_jdeps_action(ctx, toolchains, jdeps, outputs, deps): ) inputs = depset(jdeps) - if not toolchains.kt.experimental_report_unused_deps == "off": + if not _report_unused_deps(ctx, toolchains) == "off": # For sandboxing to work, and for this action to be deterministic, the compile jars need to be passed as inputs inputs = depset(jdeps, transitive = [depset([], transitive = [dep.transitive_compile_time_jars for dep in deps])]) @@ -596,7 +611,7 @@ def kt_jvm_produce_jar_actions(ctx, rule_kind): transitive_runtime_jars = _plugin_mappers.targets_to_transitive_runtime_jars(ctx.attr.plugins + ctx.attr.deps) plugins = _new_plugins_from(ctx.attr.plugins + _exported_plugins(deps = ctx.attr.deps)) - deps_artifacts = _deps_artifacts(toolchains, ctx.attr.deps + ctx.attr.associates) + deps_artifacts = _deps_artifacts(ctx, toolchains, ctx.attr.deps + ctx.attr.associates) generated_src_jars = [] annotation_processing = None diff --git a/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/JdepsMerger.kt b/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/JdepsMerger.kt index 5afacbebd..389bf9fab 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/JdepsMerger.kt +++ b/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/JdepsMerger.kt @@ -38,6 +38,7 @@ class JdepsMerger { OUTPUT("--output"), TARGET_LABEL("--target_label"), REPORT_UNUSED_DEPS("--report_unused_deps"), + UNUSED_DEPS_IGNORED_TARGETS("--unused_deps_ignored_targets"), } private fun readJarOwnerFromManifest(jarPath: Path): JarOwner { @@ -63,6 +64,7 @@ class JdepsMerger { inputs: List, output: String, reportUnusedDeps: String, + unusedDepsIgnoredTargets: List, ): Int { val rootBuilder = Deps.Dependencies.newBuilder() rootBuilder.success = false @@ -114,6 +116,7 @@ class JdepsMerger { .filter { it.value == Deps.Dependency.Kind.UNUSED } .map { it.key } .filter { it != label } + .filter { it !in unusedDepsIgnoredTargets } if (unusedLabels.isNotEmpty()) { ctx.info { @@ -160,7 +163,9 @@ class JdepsMerger { val output = argMap.mandatorySingle(JdepsMergerFlags.OUTPUT) val label = argMap.mandatorySingle(JdepsMergerFlags.TARGET_LABEL) val reportUnusedDeps = argMap.mandatorySingle(JdepsMergerFlags.REPORT_UNUSED_DEPS) + val unusedDepsIgnoredTargets = + argMap.optional(JdepsMergerFlags.UNUSED_DEPS_IGNORED_TARGETS).orEmpty() - return merge(ctx, label, inputs, output, reportUnusedDeps) + return merge(ctx, label, inputs, output, reportUnusedDeps, unusedDepsIgnoredTargets) } } diff --git a/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/JdepsMergerTest.kt b/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/JdepsMergerTest.kt index 2f4e2b187..cd935f880 100644 --- a/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/JdepsMergerTest.kt +++ b/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/JdepsMergerTest.kt @@ -204,6 +204,67 @@ class JdepsMergerTest { ).containsExactly(unusedKotlinDep) } + @Test + fun `unused deps report warning unless ignored`() { + val merger = DaggerJdepsMergerTestComponent.builder().build().jdepsMerger() + + val unusedKotlinDep1 = ktJvmLibrary("kotlin_dep1") + val unusedKotlinDep2 = ktJvmLibrary("kotlin_dep2") + val kotlinJdeps = jdeps("kt.jdeps") { + addDependency( + with(Dependency.newBuilder()) { + kind = Dependency.Kind.UNUSED + path = unusedKotlinDep1 + build() + }, + ) + addDependency( + with(Dependency.newBuilder()) { + kind = Dependency.Kind.UNUSED + path = unusedKotlinDep2 + build() + }, + ) + } + + val javaJdeps = jdeps("java.jdeps") { + addDependency( + with(Dependency.newBuilder()) { + kind = Dependency.Kind.EXPLICIT + path = ktJvmLibrary("java_dep") + build() + }, + ) + } + + val mergedJdeps = out("merged.jdeps") + + val result = WorkerContext.run { + doTask("jdepsmerge") { taskCtx -> + MergeJdeps(merger = merger).invoke( + taskCtx, + args { + input(kotlinJdeps) + input(javaJdeps) + flag(JdepsMergerFlags.TARGET_LABEL, "//foo/bar:baz") + flag(JdepsMergerFlags.OUTPUT, mergedJdeps) + flag(JdepsMergerFlags.REPORT_UNUSED_DEPS, "warn") + flag(JdepsMergerFlags.UNUSED_DEPS_IGNORED_TARGETS, "kotlin_dep2") + }, + ) + } + } + assertThat(result.status).isEqualTo(SUCCESS) + assertThat(result.log.out.toString()).contains("'remove deps kotlin_dep1' //foo/bar:baz") + + val depsProto = depsProto(mergedJdeps) + assertThat( + depsProto.dependencyList + .filter { it.kind == Dependency.Kind.UNUSED } + .map { it.path }, + ).containsExactly(unusedKotlinDep1, unusedKotlinDep2) + } + @Test fun `unused deps report error`() { val merger = DaggerJdepsMergerTestComponent.builder().build().jdepsMerger()