Expose j2objc.dead_code_report as a configuration field instead of a basic struct field on the j2objc fragment.

RELNOTES: None.
PiperOrigin-RevId: 190672475
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkLateBoundDefault.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkLateBoundDefault.java
index 2b22fe8..52d3162 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkLateBoundDefault.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkLateBoundDefault.java
@@ -71,6 +71,9 @@
    */
   private static Label getDefaultLabel(
       SkylarkConfigurationField annotation, String toolsRepository) {
+    if (annotation.defaultLabel().isEmpty()) {
+      return null;
+    }
     Label defaultLabel = annotation.defaultInToolRepository()
         ? Label.parseAbsoluteUnchecked(toolsRepository + annotation.defaultLabel())
         : Label.parseAbsoluteUnchecked(annotation.defaultLabel());
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/annotations/SkylarkConfigurationField.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/annotations/SkylarkConfigurationField.java
index 887ceda..6e72e31 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/annotations/SkylarkConfigurationField.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/annotations/SkylarkConfigurationField.java
@@ -47,7 +47,7 @@
    * <p>If the default label is under the tools repository, omit the tools repository prefix
    * from this default, but set {@link #defaultInToolRepository} to true.</p>
    */
-  String defaultLabel();
+  String defaultLabel() default "";
 
   /**
    * Whether the default label as defined in {@link #defaultLabel} should be prefixed with
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/BUILD b/src/main/java/com/google/devtools/build/lib/rules/objc/BUILD
index 73dfd7c..371c589 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/BUILD
@@ -23,6 +23,7 @@
         "//src/main/java/com/google/devtools/build/lib:util",
         "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/analysis/platform",
+        "//src/main/java/com/google/devtools/build/lib/analysis/skylark/annotations",
         "//src/main/java/com/google/devtools/build/lib/collect",
         "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
         "//src/main/java/com/google/devtools/build/lib/concurrent",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcConfiguration.java
index f57e901..82ac947 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcConfiguration.java
@@ -22,12 +22,12 @@
 import com.google.devtools.build.lib.analysis.config.ConfigurationEnvironment;
 import com.google.devtools.build.lib.analysis.config.ConfigurationFragmentFactory;
 import com.google.devtools.build.lib.analysis.config.FragmentOptions;
+import com.google.devtools.build.lib.analysis.skylark.annotations.SkylarkConfigurationField;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
 import java.util.Collections;
@@ -143,10 +143,11 @@
    * Returns null if no such report was requested.
    */
   @Nullable
-  @SkylarkCallable(name = "dead_code_report", structField = true,
+  @SkylarkConfigurationField(
+      name = "dead_code_report",
       doc = "The label of the dead code report generated by ProGuard for dead code elimination, "
           + "or <code>None</code> if no such report was requested.",
-      allowReturnNones = true)
+      defaultLabel = "")
   public Label deadCodeReport() {
     return deadCodeReport;
   }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcSkylarkTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcSkylarkTest.java
index 1d3da5e..20a32ce 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcSkylarkTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcSkylarkTest.java
@@ -25,11 +25,9 @@
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
-import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.SkylarkInfo;
 import com.google.devtools.build.lib.rules.apple.AppleToolchain;
 import com.google.devtools.build.lib.rules.apple.DottedVersion;
-import com.google.devtools.build.lib.syntax.Runtime;
 import com.google.devtools.build.lib.syntax.SkylarkDict;
 import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
 import com.google.devtools.build.lib.vfs.PathFragment;
@@ -263,6 +261,7 @@
         "   cpu = ctx.fragments.apple.ios_cpu()",
         "   platform = ctx.fragments.apple.ios_cpu_platform()",
         "   xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig]",
+        "   dead_code_report = ctx.attr._dead_code_report",
         "   env = apple_common.target_apple_env(xcode_config, platform)",
         "   xcode_version = xcode_config.xcode_version()",
         "   sdk_version = xcode_config.sdk_version_for_platform(platform)",
@@ -278,14 +277,19 @@
         "      single_arch_platform=str(single_arch_platform),",
         "      single_arch_cpu=str(single_arch_cpu),",
         "      platform_type=str(platform_type),",
-        "      bitcode_mode=str(bitcode_mode)",
+        "      bitcode_mode=str(bitcode_mode),",
+        "      dead_code_report=str(dead_code_report),",
         "   )",
         "swift_binary = rule(",
         "    implementation = swift_binary_impl,",
         "    fragments = ['apple'],",
-        "    attrs = { '_xcode_config': ",
-        "        attr.label(default = configuration_field(",
-        "            fragment = 'apple', name = 'xcode_config_label')),",
+        "    attrs = {",
+        "        '_xcode_config': attr.label(",
+        "            default = configuration_field(",
+        "                fragment = 'apple', name = 'xcode_config_label')),",
+        "        '_dead_code_report': attr.label(",
+        "            default = configuration_field(",
+        "                fragment = 'j2objc', name = 'dead_code_report')),",
         "    },",
         ")");
 
@@ -317,8 +321,85 @@
     assertThat(skylarkTarget.get("single_arch_cpu")).isEqualTo("i386");
     assertThat(skylarkTarget.get("platform_type")).isEqualTo("ios");
     assertThat(skylarkTarget.get("bitcode_mode")).isEqualTo("none");
+    assertThat(skylarkTarget.get("dead_code_report")).isEqualTo("None");
   }
-  
+
+  @Test
+  public void testDefaultJ2objcDeadCodeReport() throws Exception {
+    scratch.file("examples/rule/BUILD");
+    scratch.file(
+        "examples/rule/apple_rules.bzl",
+        "def swift_binary_impl(ctx):",
+        "   dead_code_report = ctx.attr._dead_code_report",
+        "   return struct(",
+        "      dead_code_report=str(dead_code_report),",
+        "   )",
+        "swift_binary = rule(",
+        "    implementation = swift_binary_impl,",
+        "    fragments = ['j2objc'],",
+        "    attrs = {",
+        "        '_dead_code_report': attr.label(",
+        "            default = configuration_field(",
+        "                fragment = 'j2objc', name = 'dead_code_report')),",
+        "    },",
+        ")");
+
+    scratch.file("examples/apple_skylark/a.m");
+    scratch.file(
+        "examples/apple_skylark/BUILD",
+        "package(default_visibility = ['//visibility:public'])",
+        "load('//examples/rule:apple_rules.bzl', 'swift_binary')",
+        "swift_binary(",
+        "   name='my_target',",
+        ")");
+
+    useConfiguration();
+    ConfiguredTarget skylarkTarget = getConfiguredTarget("//examples/apple_skylark:my_target");
+
+    assertThat(skylarkTarget.get("dead_code_report")).isEqualTo("None");
+  }
+
+  @Test
+  public void testCustomJ2objcDeadCodeReport() throws Exception {
+    scratch.file("examples/rule/BUILD");
+    scratch.file(
+        "examples/rule/apple_rules.bzl",
+        "def dead_code_report_impl(ctx):",
+        "   return struct(foo='bar')",
+        "def swift_binary_impl(ctx):",
+        "   dead_code_report = ctx.attr._dead_code_report.foo",
+        "   return struct(",
+        "      dead_code_report=dead_code_report,",
+        "   )",
+        "dead_code_report = rule(",
+        "    implementation = dead_code_report_impl,",
+        ")",
+        "swift_binary = rule(",
+        "    implementation = swift_binary_impl,",
+        "    fragments = ['j2objc'],",
+        "    attrs = {",
+        "        '_dead_code_report': attr.label(",
+        "            default = configuration_field(",
+        "                fragment = 'j2objc', name = 'dead_code_report')),",
+        "    },",
+        ")");
+
+    scratch.file("examples/apple_skylark/a.m");
+    scratch.file(
+        "examples/apple_skylark/BUILD",
+        "package(default_visibility = ['//visibility:public'])",
+        "load('//examples/rule:apple_rules.bzl', 'dead_code_report', 'swift_binary')",
+        "swift_binary(",
+        "   name='my_target',",
+        ")",
+        "dead_code_report(name='dead_code_report')");
+
+    useConfiguration("--j2objc_dead_code_report=//examples/apple_skylark:dead_code_report");
+    ConfiguredTarget skylarkTarget = getConfiguredTarget("//examples/apple_skylark:my_target");
+
+    assertThat(skylarkTarget.get("dead_code_report")).isEqualTo("bar");
+  }
+
   @Test
   public void testSkylarkCanAccessApplePlatformNames() throws Exception {
     scratch.file("examples/rule/BUILD");
@@ -530,41 +611,6 @@
   }
 
   @Test
-  public void testSkylarkCanAccessJ2objcConfiguration() throws Exception {
-    scratch.file("examples/rule/BUILD");
-    scratch.file(
-        "examples/rule/objc_rules.bzl",
-        "def test_rule_impl(ctx):",
-        "   dead_code_report = ctx.fragments.j2objc.dead_code_report",
-        "   return struct(",
-        "      dead_code_report=dead_code_report,",
-        "   )",
-        "test_rule = rule(",
-        "    implementation = test_rule_impl,",
-        "    fragments = ['j2objc']",
-        ")");
-
-    scratch.file(
-        "examples/objc_skylark/BUILD",
-        "package(default_visibility = ['//visibility:public'])",
-        "load('//examples/rule:objc_rules.bzl', 'test_rule')",
-        "test_rule(",
-        "   name='my_target',",
-        ")");
-
-    useConfiguration();
-    ConfiguredTarget skylarkTarget = getConfiguredTarget("//examples/objc_skylark:my_target");
-    assertThat(skylarkTarget.get("dead_code_report")).isEqualTo(Runtime.NONE);
-
-    useConfiguration("--j2objc_dead_code_report=//foo:bar");
-    skylarkTarget = getConfiguredTarget("//examples/objc_skylark:my_target");
-
-    @SuppressWarnings("unchecked")
-    Label label = (Label) skylarkTarget.get("dead_code_report");
-    assertThat(label.getCanonicalForm()).isEqualTo("//foo:bar");
-  }
-
-  @Test
   public void testSigningCertificateNameCanReturnNone() throws Exception {
     scratch.file("examples/rule/BUILD");
     scratch.file(