Add support for data dependencies to java_plugin and java_package_configuration

This allows loading data inputs to annotation processors and Error Prone plugins.
Previously the only supported way to do this was using Java resources, but in
the case of per-package configuration that ties any changes to the resources
to JavaBuilder's release process.

PiperOrigin-RevId: 206106802
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPluginRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPluginRule.java
index 1fa1f74..fed0467 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPluginRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPluginRule.java
@@ -70,7 +70,6 @@
         .removeAttribute("runtime_deps")
         .removeAttribute("exports")
         .removeAttribute("exported_plugins")
-        .removeAttribute("data")
         .build();
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java
index 861ee09..7da5b33 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java
@@ -23,6 +23,7 @@
 import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
+import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.OutputGroupInfo;
 import com.google.devtools.build.lib.analysis.PrerequisiteArtifacts;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -427,11 +428,29 @@
   /** Returns the per-package configured javacopts. */
   public static ImmutableList<String> computePerPackageJavacOpts(
       RuleContext ruleContext, JavaToolchainProvider toolchain) {
+    return computePerPackageConfiguration(ruleContext, toolchain)
+        .stream()
+        .flatMap(p -> p.javacopts().stream())
+        .collect(toImmutableList());
+  }
+
+  /** Returns the per-package configured runfiles. */
+  public static NestedSet<Artifact> computePerPackageData(
+      RuleContext ruleContext, JavaToolchainProvider toolchain) {
+    NestedSetBuilder<Artifact> data = NestedSetBuilder.naiveLinkOrder();
+    computePerPackageConfiguration(ruleContext, toolchain)
+        .stream()
+        .map(p -> p.data())
+        .forEach(data::addTransitive);
+    return data.build();
+  }
+
+  private static ImmutableList<JavaPackageConfigurationProvider> computePerPackageConfiguration(
+      RuleContext ruleContext, JavaToolchainProvider toolchain) {
     return toolchain
         .packageConfiguration()
         .stream()
         .filter(p -> p.matches(ruleContext.getLabel()))
-        .flatMap(p -> p.javacopts().stream())
         .collect(toImmutableList());
   }
 
@@ -773,8 +792,13 @@
     NestedSet<String> processorClasses =
         NestedSetBuilder.wrap(Order.NAIVE_LINK_ORDER, getProcessorClasses(ruleContext));
     NestedSet<Artifact> processorClasspath = getRuntimeClasspath();
+    FileProvider dataProvider = ruleContext.getPrerequisite("data", Mode.HOST, FileProvider.class);
+    NestedSet<Artifact> data =
+        dataProvider != null
+            ? dataProvider.getFilesToBuild()
+            : NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER);
     return JavaPluginInfoProvider.create(
-        JavaPluginInfo.create(processorClasses, processorClasspath),
+        JavaPluginInfo.create(processorClasses, processorClasspath, data),
         ruleContext.attributes().get("generates_api", Type.BOOLEAN));
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
index db303ae..2c9364c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
@@ -230,6 +230,7 @@
     builder.setTempDirectory(tempDir(classJar));
     builder.setClassDirectory(classDir(classJar));
     builder.setPlugins(attributes.plugins().plugins());
+    builder.setExtraData(JavaCommon.computePerPackageData(ruleContext, javaToolchain));
     builder.setStrictJavaDeps(attributes.getStrictJavaDeps());
     builder.setFixDepsTool(getJavaConfiguration().getFixDepsTool());
     builder.setDirectJars(attributes.getDirectJars());
@@ -405,6 +406,9 @@
 
     // only run API-generating annotation processors during header compilation
     builder.setPlugins(attributes.plugins().apiGeneratingPlugins());
+    // Exclude any per-package configured data (see JavaCommon.computePerPackageData).
+    // It is used to allow Error Prone checks to load additional data,
+    // and Error Prone doesn't run during header compilation.
     builder.setJavacOpts(getJavacOpts());
     builder.setTempDirectory(tempDir(headerJar));
     builder.setOutputJar(headerJar);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
index dc960d7..a7158d3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
@@ -457,6 +457,7 @@
     private PathFragment tempDirectory;
     private PathFragment classDirectory;
     private JavaPluginInfo plugins = JavaPluginInfo.empty();
+    private NestedSet<Artifact> extraData = NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER);
     private Label targetLabel;
     @Nullable private String injectingRuleKind;
 
@@ -572,6 +573,8 @@
               .addTransitive(classpathEntries)
               .addTransitive(compileTimeDependencyArtifacts)
               .addTransitive(plugins.processorClasspath())
+              .addTransitive(plugins.data())
+              .addTransitive(extraData)
               .addAll(sourceJars)
               .addAll(sourceFiles)
               .addAll(javabaseInputs)
@@ -955,6 +958,12 @@
       return this;
     }
 
+    public void setExtraData(NestedSet<Artifact> extraData) {
+      checkNotNull(extraData, "extraData must not be null");
+      checkState(this.extraData.isEmpty());
+      this.extraData = extraData;
+    }
+
     public Builder setLangtoolsJar(Artifact langtoolsJar) {
       this.langtoolsJar = langtoolsJar;
       return this;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileAction.java
index 5d7d66f..6198048 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileAction.java
@@ -437,6 +437,7 @@
               .addTransitive(baseInputs)
               .addTransitive(classpathEntries)
               .addTransitive(plugins.processorClasspath())
+              .addTransitive(plugins.data())
               .addTransitive(compileTimeDependencyArtifacts);
       final CommandLines commandLines;
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfiguration.java
index 3ea3935..78964b9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfiguration.java
@@ -15,8 +15,10 @@
 package com.google.devtools.build.lib.rules.java;
 
 import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.PackageSpecificationProvider;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -24,6 +26,7 @@
 import com.google.devtools.build.lib.analysis.Runfiles;
 import com.google.devtools.build.lib.analysis.RunfilesProvider;
 import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.syntax.Type;
@@ -39,11 +42,16 @@
         ImmutableList.copyOf(
             ruleContext.getPrerequisites(
                 "packages", Mode.HOST, PackageSpecificationProvider.class));
+    FileProvider dataProvider = ruleContext.getPrerequisite("data", Mode.HOST, FileProvider.class);
+    NestedSet<Artifact> data =
+        dataProvider != null
+            ? dataProvider.getFilesToBuild()
+            : NestedSetBuilder.emptySet(Order.STABLE_ORDER);
     List<String> javacopts = ruleContext.attributes().get("javacopts", Type.STRING_LIST);
     return new RuleConfiguredTargetBuilder(ruleContext)
         .addProvider(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY))
         .setFilesToBuild(NestedSetBuilder.emptySet(Order.STABLE_ORDER))
-        .addProvider(JavaPackageConfigurationProvider.create(packages, javacopts))
+        .addProvider(JavaPackageConfigurationProvider.create(packages, javacopts, data))
         .build();
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfigurationProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfigurationProvider.java
index beebd79..86e8883 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfigurationProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfigurationProvider.java
@@ -16,9 +16,11 @@
 
 import com.google.auto.value.AutoValue;
 import com.google.common.collect.Streams;
+import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.analysis.PackageSpecificationProvider;
 import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
 import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import java.util.List;
@@ -32,8 +34,10 @@
   /** Creates a {@link JavaPackageConfigurationProvider}. */
   @AutoCodec.Instantiator
   public static JavaPackageConfigurationProvider create(
-      List<PackageSpecificationProvider> packageSpecifications, List<String> javacopts) {
-    return new AutoValue_JavaPackageConfigurationProvider(packageSpecifications, javacopts);
+      List<PackageSpecificationProvider> packageSpecifications,
+      List<String> javacopts,
+      NestedSet<Artifact> data) {
+    return new AutoValue_JavaPackageConfigurationProvider(packageSpecifications, javacopts, data);
   }
 
   /** Package specifications for which the configuration should be applied. */
@@ -42,6 +46,8 @@
   /** The javacopts for this configuration. */
   abstract List<String> javacopts();
 
+  abstract NestedSet<Artifact> data();
+
   /**
    * Returns true if this configuration matches the current label: that is, if the label's package
    * is contained by any of the {@link #packageSpecifications}.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfigurationRule.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfigurationRule.java
index 7f6bc85..b114ec9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfigurationRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfigurationRule.java
@@ -15,6 +15,7 @@
 package com.google.devtools.build.lib.rules.java;
 
 import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
 import static com.google.devtools.build.lib.packages.BuildType.LICENSE;
 
 import com.google.common.collect.ImmutableList;
@@ -23,9 +24,9 @@
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.analysis.config.HostTransition;
-import com.google.devtools.build.lib.packages.BuildType;
 import com.google.devtools.build.lib.packages.RuleClass;
 import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.util.FileTypeSet;
 
 /** Rule definition for {@code java_package_configuration} */
 public class JavaPackageConfigurationRule implements RuleDefinition {
@@ -38,7 +39,7 @@
         the configuration should be applied to.
         <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
         .add(
-            attr("packages", BuildType.LABEL_LIST)
+            attr("packages", LABEL_LIST)
                 .cfg(HostTransition.INSTANCE)
                 .allowedFileTypes()
                 .mandatoryNativeProviders(ImmutableList.of(PackageSpecificationProvider.class)))
@@ -46,6 +47,10 @@
         Java compiler flags.
         <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
         .add(attr("javacopts", Type.STRING_LIST))
+        /* <!-- #BLAZE_RULE(java_package_configuration).ATTRIBUTE(data) -->
+        The list of files needed by this configuration at runtime.
+        <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+        .add(attr("data", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE).dontCheckConstraints())
         .add(attr("output_licenses", LICENSE))
         .build();
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPluginInfoProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPluginInfoProvider.java
index 48241d4..0d125f9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPluginInfoProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPluginInfoProvider.java
@@ -38,26 +38,31 @@
   public abstract static class JavaPluginInfo {
 
     public static JavaPluginInfo create(
-        NestedSet<String> processorClasses, NestedSet<Artifact> processorClasspath) {
+        NestedSet<String> processorClasses,
+        NestedSet<Artifact> processorClasspath,
+        NestedSet<Artifact> data) {
       return new AutoValue_JavaPluginInfoProvider_JavaPluginInfo(
-          processorClasses, processorClasspath);
+          processorClasses, processorClasspath, data);
     }
 
     @AutoCodec.Instantiator
     public static JavaPluginInfo empty() {
       return create(
           NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER),
+          NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER),
           NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER));
     }
 
     public static JavaPluginInfo merge(Iterable<JavaPluginInfo> plugins) {
       NestedSetBuilder<String> processorClasses = NestedSetBuilder.naiveLinkOrder();
       NestedSetBuilder<Artifact> processorClasspath = NestedSetBuilder.naiveLinkOrder();
+      NestedSetBuilder<Artifact> data = NestedSetBuilder.naiveLinkOrder();
       for (JavaPluginInfo plugin : plugins) {
         processorClasses.addTransitive(plugin.processorClasses());
         processorClasspath.addTransitive(plugin.processorClasspath());
+        data.addTransitive(plugin.data());
       }
-      return create(processorClasses.build(), processorClasspath.build());
+      return create(processorClasses.build(), processorClasspath.build(), data.build());
     }
 
     /**
@@ -69,8 +74,10 @@
     /** Returns the artifacts to add to the runtime classpath for this plugin. */
     public abstract NestedSet<Artifact> processorClasspath();
 
+    public abstract NestedSet<Artifact> data();
+
     public boolean isEmpty() {
-      return processorClasses().isEmpty() && processorClasspath().isEmpty();
+      return processorClasses().isEmpty() && processorClasspath().isEmpty() && data().isEmpty();
     }
   }