From e350b947565a973a6bea72c16c662887a6510887 Mon Sep 17 00:00:00 2001 From: Jonathan Perry Date: Fri, 26 Jun 2026 10:21:47 +0100 Subject: [PATCH 1/6] Support toolchain-driven unused dependencies checking (Starlark changes) --- .../rules/java_package_configuration.bzl | 9 +++++ java/private/java_common_internal.bzl | 33 ++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/java/common/rules/java_package_configuration.bzl b/java/common/rules/java_package_configuration.bzl index a1abcd05..45d65d58 100644 --- a/java/common/rules/java_package_configuration.bzl +++ b/java/common/rules/java_package_configuration.bzl @@ -28,6 +28,7 @@ JavaPackageConfigurationInfo = provider( "matches", "package_specs", "system", + "unused_deps", ], ) @@ -50,6 +51,7 @@ def _rule_impl(ctx): matches = _matches, package_specs = package_specs, system = system, + unused_deps = ctx.attr.unused_deps, ), ] @@ -116,6 +118,13 @@ The list of files needed by this configuration at runtime. providers = [BootClassPathInfo], doc = """ Corresponds to javac's --system flag. +""", + ), + "unused_deps": attr.string( + default = "off", + values = ["off", "error"], + doc = """ +Unused dependencies checking mode. """, ), # buildifier: disable=attr-licenses diff --git a/java/private/java_common_internal.bzl b/java/private/java_common_internal.bzl index 30d9533c..9c1262c6 100644 --- a/java/private/java_common_internal.bzl +++ b/java/private/java_common_internal.bzl @@ -20,6 +20,7 @@ load("//java/common/rules:java_helper.bzl", "helper") load("//java/common/rules:java_toolchain.bzl", "JavaToolchainInfo") load( ":java_info.bzl", + "JavaInfo", "JavaPluginInfo", "disable_plugin_info_annotation_processing", "java_info_for_compilation", @@ -314,7 +315,36 @@ def compile( if uses_annotation_processing: generated_class_jar = _derive_output_file(ctx, output, name_suffix = "-gen") generated_source_jar = _derive_output_file(ctx, output, name_suffix = "-gensrc") - get_internal_java_common().create_compilation_action( + + direct_dep_jars_to_verify = [] + resolved_unused_deps_mode = "off" + internal_common = get_internal_java_common() + is_unused_deps_supported = hasattr(internal_common, "is_unused_deps_supported") and internal_common.is_unused_deps_supported() + + if is_unused_deps_supported and not ctx.label.workspace_name: + for package_config in java_toolchain._package_configuration: + matched = package_config.matches(package_config.package_specs, ctx.label) + if matched: + if hasattr(package_config, "unused_deps"): + resolved_unused_deps_mode = package_config.unused_deps + + if resolved_unused_deps_mode == "error" and hasattr(ctx.attr, "deps"): + for dep in ctx.attr.deps: + if JavaInfo in dep: + if hasattr(dep[JavaInfo], "java_outputs"): + for output_info in dep[JavaInfo].java_outputs: + compile_jar = output_info.compile_jar if output_info.compile_jar else output_info.class_jar + if compile_jar: + direct_dep_jars_to_verify.append(struct( + jar = compile_jar, + label = str(dep.label), + )) + + additional_kwargs = {} + if is_unused_deps_supported: + additional_kwargs["direct_dep_jars_to_verify"] = direct_dep_jars_to_verify + + internal_common.create_compilation_action( ctx, java_toolchain, output, @@ -343,6 +373,7 @@ def compile( enable_direct_classpath, annotation_processor_additional_inputs, annotation_processor_additional_outputs, + **additional_kwargs ) create_output_source_jar = len(source_files) > 0 or source_jars != [output_source_jar] From f446408556787857c79a2d3a7f33a705ffb324ce Mon Sep 17 00:00:00 2001 From: Jonathan Perry Date: Fri, 26 Jun 2026 14:00:33 +0100 Subject: [PATCH 2/6] Fix workspace_name deprecation by using repo_name --- java/private/java_common_internal.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/private/java_common_internal.bzl b/java/private/java_common_internal.bzl index 9c1262c6..41e3dfcc 100644 --- a/java/private/java_common_internal.bzl +++ b/java/private/java_common_internal.bzl @@ -320,8 +320,8 @@ def compile( resolved_unused_deps_mode = "off" internal_common = get_internal_java_common() is_unused_deps_supported = hasattr(internal_common, "is_unused_deps_supported") and internal_common.is_unused_deps_supported() - - if is_unused_deps_supported and not ctx.label.workspace_name: + repo_name = ctx.label.repo_name if hasattr(ctx.label, "repo_name") else ctx.label.workspace_name + if is_unused_deps_supported and not repo_name: for package_config in java_toolchain._package_configuration: matched = package_config.matches(package_config.package_specs, ctx.label) if matched: From b21884e4943e6fc8cad306cd14660242b1ceee0b Mon Sep 17 00:00:00 2001 From: Gemini CLI Date: Wed, 8 Jul 2026 13:41:26 +0100 Subject: [PATCH 3/6] Represent direct_dep_jars_to_verify as a dict instead of a list of structs --- java/private/java_common_internal.bzl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/java/private/java_common_internal.bzl b/java/private/java_common_internal.bzl index 41e3dfcc..fabc6e6f 100644 --- a/java/private/java_common_internal.bzl +++ b/java/private/java_common_internal.bzl @@ -316,7 +316,7 @@ def compile( generated_class_jar = _derive_output_file(ctx, output, name_suffix = "-gen") generated_source_jar = _derive_output_file(ctx, output, name_suffix = "-gensrc") - direct_dep_jars_to_verify = [] + direct_dep_jars_to_verify = {} resolved_unused_deps_mode = "off" internal_common = get_internal_java_common() is_unused_deps_supported = hasattr(internal_common, "is_unused_deps_supported") and internal_common.is_unused_deps_supported() @@ -335,10 +335,7 @@ def compile( for output_info in dep[JavaInfo].java_outputs: compile_jar = output_info.compile_jar if output_info.compile_jar else output_info.class_jar if compile_jar: - direct_dep_jars_to_verify.append(struct( - jar = compile_jar, - label = str(dep.label), - )) + direct_dep_jars_to_verify[compile_jar] = str(dep.label) additional_kwargs = {} if is_unused_deps_supported: From 631bb4f6a53b08b92208e9d87f639caac6d6492f Mon Sep 17 00:00:00 2001 From: Gemini CLI Date: Wed, 12 Aug 2026 08:24:43 +0100 Subject: [PATCH 4/6] Pass extra_args Args object from rules_java for unused deps checking --- java/private/java_common_internal.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/private/java_common_internal.bzl b/java/private/java_common_internal.bzl index fabc6e6f..e20111f0 100644 --- a/java/private/java_common_internal.bzl +++ b/java/private/java_common_internal.bzl @@ -316,7 +316,7 @@ def compile( generated_class_jar = _derive_output_file(ctx, output, name_suffix = "-gen") generated_source_jar = _derive_output_file(ctx, output, name_suffix = "-gensrc") - direct_dep_jars_to_verify = {} + extra_args = ctx.actions.args() resolved_unused_deps_mode = "off" internal_common = get_internal_java_common() is_unused_deps_supported = hasattr(internal_common, "is_unused_deps_supported") and internal_common.is_unused_deps_supported() @@ -335,11 +335,11 @@ def compile( for output_info in dep[JavaInfo].java_outputs: compile_jar = output_info.compile_jar if output_info.compile_jar else output_info.class_jar if compile_jar: - direct_dep_jars_to_verify[compile_jar] = str(dep.label) + extra_args.add("--declared_dep", compile_jar, format = "%s::" + str(dep.label)) additional_kwargs = {} if is_unused_deps_supported: - additional_kwargs["direct_dep_jars_to_verify"] = direct_dep_jars_to_verify + additional_kwargs["extra_args"] = extra_args internal_common.create_compilation_action( ctx, From d31c8f22a969443a6aa84d187af4a1bd89a10a67 Mon Sep 17 00:00:00 2001 From: Gemini CLI Date: Wed, 12 Aug 2026 08:37:56 +0100 Subject: [PATCH 5/6] Forward extra_args unconditionally in java_common.compile --- java/private/java_common_internal.bzl | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/java/private/java_common_internal.bzl b/java/private/java_common_internal.bzl index e20111f0..70365e67 100644 --- a/java/private/java_common_internal.bzl +++ b/java/private/java_common_internal.bzl @@ -166,7 +166,8 @@ def compile( include_compilation_info = True, classpath_resources = [], resource_jars = [], - injecting_rule_kind = None): + injecting_rule_kind = None, + extra_args = None): """Compiles Java source files/jars from the implementation of a Starlark rule The result is a provider that represents the results of the compilation and can be added to the @@ -216,6 +217,7 @@ def compile( add_exports: ([str]) Allow this library to access the given /. Optional. add_opens: ([str]) Allow this library to reflectively access the given /. Optional. + extra_args: (Args|None) Additional args to pass to JavaBuilder. Optional. Returns: (JavaInfo) @@ -316,12 +318,12 @@ def compile( generated_class_jar = _derive_output_file(ctx, output, name_suffix = "-gen") generated_source_jar = _derive_output_file(ctx, output, name_suffix = "-gensrc") - extra_args = ctx.actions.args() + if extra_args == None: + extra_args = ctx.actions.args() resolved_unused_deps_mode = "off" internal_common = get_internal_java_common() - is_unused_deps_supported = hasattr(internal_common, "is_unused_deps_supported") and internal_common.is_unused_deps_supported() repo_name = ctx.label.repo_name if hasattr(ctx.label, "repo_name") else ctx.label.workspace_name - if is_unused_deps_supported and not repo_name: + if not repo_name: for package_config in java_toolchain._package_configuration: matched = package_config.matches(package_config.package_specs, ctx.label) if matched: @@ -337,10 +339,6 @@ def compile( if compile_jar: extra_args.add("--declared_dep", compile_jar, format = "%s::" + str(dep.label)) - additional_kwargs = {} - if is_unused_deps_supported: - additional_kwargs["extra_args"] = extra_args - internal_common.create_compilation_action( ctx, java_toolchain, @@ -370,7 +368,7 @@ def compile( enable_direct_classpath, annotation_processor_additional_inputs, annotation_processor_additional_outputs, - **additional_kwargs + extra_args = extra_args, ) create_output_source_jar = len(source_files) > 0 or source_jars != [output_source_jar] From 1b89a957031376c35bd3761b73ef0b948ea39dab Mon Sep 17 00:00:00 2001 From: Gemini CLI Date: Wed, 12 Aug 2026 08:42:03 +0100 Subject: [PATCH 6/6] Update extra_args to accept and pass a list of Args --- java/private/java_common_internal.bzl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/java/private/java_common_internal.bzl b/java/private/java_common_internal.bzl index 70365e67..1c89bad8 100644 --- a/java/private/java_common_internal.bzl +++ b/java/private/java_common_internal.bzl @@ -167,7 +167,7 @@ def compile( classpath_resources = [], resource_jars = [], injecting_rule_kind = None, - extra_args = None): + extra_args = []): """Compiles Java source files/jars from the implementation of a Starlark rule The result is a provider that represents the results of the compilation and can be added to the @@ -217,7 +217,7 @@ def compile( add_exports: ([str]) Allow this library to access the given /. Optional. add_opens: ([str]) Allow this library to reflectively access the given /. Optional. - extra_args: (Args|None) Additional args to pass to JavaBuilder. Optional. + extra_args: (list[Args]) Additional args to pass to JavaBuilder. Optional. Returns: (JavaInfo) @@ -318,8 +318,8 @@ def compile( generated_class_jar = _derive_output_file(ctx, output, name_suffix = "-gen") generated_source_jar = _derive_output_file(ctx, output, name_suffix = "-gensrc") - if extra_args == None: - extra_args = ctx.actions.args() + extra_args_list = list(extra_args) + unused_deps_args = ctx.actions.args() resolved_unused_deps_mode = "off" internal_common = get_internal_java_common() repo_name = ctx.label.repo_name if hasattr(ctx.label, "repo_name") else ctx.label.workspace_name @@ -337,7 +337,8 @@ def compile( for output_info in dep[JavaInfo].java_outputs: compile_jar = output_info.compile_jar if output_info.compile_jar else output_info.class_jar if compile_jar: - extra_args.add("--declared_dep", compile_jar, format = "%s::" + str(dep.label)) + unused_deps_args.add("--declared_dep", compile_jar, format = "%s::" + str(dep.label)) + extra_args_list.append(unused_deps_args) internal_common.create_compilation_action( ctx, @@ -368,7 +369,7 @@ def compile( enable_direct_classpath, annotation_processor_additional_inputs, annotation_processor_additional_outputs, - extra_args = extra_args, + extra_args = extra_args_list, ) create_output_source_jar = len(source_files) > 0 or source_jars != [output_source_jar]