Merge direct runtime jars, java constraints and JavaSourceInfoProvider in java_common.merge()

Fixes #8916.

Closes #8847.

PiperOrigin-RevId: 269313592
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfo.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfo.java
index a1898dd..53d83a7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfo.java
@@ -127,6 +127,8 @@
         JavaInfo.fetchProvidersFromList(providers, JavaExportsProvider.class);
     List<JavaRuleOutputJarsProvider> javaRuleOutputJarsProviders =
         JavaInfo.fetchProvidersFromList(providers, JavaRuleOutputJarsProvider.class);
+    List<JavaSourceInfoProvider> sourceInfos =
+        JavaInfo.fetchProvidersFromList(providers, JavaSourceInfoProvider.class);
 
     Runfiles mergedRunfiles = Runfiles.EMPTY;
     for (JavaRunfilesProvider javaRunfilesProvider : javaRunfilesProviders) {
@@ -134,6 +136,13 @@
       mergedRunfiles = mergedRunfiles == Runfiles.EMPTY ? runfiles : mergedRunfiles.merge(runfiles);
     }
 
+    ImmutableList.Builder<Artifact> runtimeJars = ImmutableList.builder();
+    ImmutableList.Builder<String> javaConstraints = ImmutableList.builder();
+    for (JavaInfo javaInfo : providers) {
+      runtimeJars.addAll(javaInfo.getDirectRuntimeJars());
+      javaConstraints.addAll(javaInfo.getJavaConstraints());
+    }
+
     return JavaInfo.Builder.create()
         .addProvider(
             JavaCompilationArgsProvider.class,
@@ -150,7 +159,11 @@
         .addProvider(
             JavaPluginInfoProvider.class, JavaPluginInfoProvider.merge(javaPluginInfoProviders))
         .addProvider(JavaExportsProvider.class, JavaExportsProvider.merge(javaExportsProviders))
+        .addProvider(JavaSourceInfoProvider.class, JavaSourceInfoProvider.merge(sourceInfos))
         // TODO(b/65618333): add merge function to JavaGenJarsProvider. See #3769
+        // TODO(iirina): merge or remove JavaCompilationInfoProvider
+        .setRuntimeJars(runtimeJars.build())
+        .setJavaConstraints(javaConstraints.build())
         .build();
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSourceInfoProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSourceInfoProvider.java
index ed127df..b910c82 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSourceInfoProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSourceInfoProvider.java
@@ -108,6 +108,29 @@
         .build();
   }
 
+  public static JavaSourceInfoProvider merge(Collection<JavaSourceInfoProvider> sourceInfos) {
+    JavaSourceInfoProvider.Builder javaSourceInfo = new JavaSourceInfoProvider.Builder();
+    ImmutableList.Builder<Artifact> jarFiles = new ImmutableList.Builder<>();
+    ImmutableMap.Builder<PathFragment, Artifact> resources = new ImmutableMap.Builder<>();
+    ImmutableList.Builder<Artifact> sourceFiles = new ImmutableList.Builder<>();
+    ImmutableList.Builder<Artifact> sourceJars = new ImmutableList.Builder<>();
+    ImmutableList.Builder<Artifact> sourceJarsForJarFiles = new ImmutableList.Builder<>();
+
+    for (JavaSourceInfoProvider sourceInfo : sourceInfos) {
+      jarFiles.addAll(sourceInfo.getJarFiles());
+      resources.putAll(sourceInfo.getResources());
+      sourceFiles.addAll(sourceInfo.getSourceFiles());
+      sourceJars.addAll(sourceInfo.getSourceJars());
+      sourceJarsForJarFiles.addAll(sourceInfo.getSourceJarsForJarFiles());
+    }
+    javaSourceInfo.setJarFiles(jarFiles.build());
+    javaSourceInfo.setResources(resources.build());
+    javaSourceInfo.setSourceFiles(sourceFiles.build());
+    javaSourceInfo.setSourceJars(sourceJars.build());
+    javaSourceInfo.setSourceJarsForJarFiles(sourceJarsForJarFiles.build());
+    return javaSourceInfo.build();
+  }
+
   /** Builder class for constructing JavaSourceInfoProviders. */
   public static final class Builder {
     private Collection<Artifact> sourceFiles = ImmutableList.<Artifact>of();
diff --git a/src/test/java/com/google/devtools/build/lib/rules/java/JavaSkylarkApiTest.java b/src/test/java/com/google/devtools/build/lib/rules/java/JavaSkylarkApiTest.java
index 9fbd784..025812d 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/java/JavaSkylarkApiTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/java/JavaSkylarkApiTest.java
@@ -1724,6 +1724,61 @@
   }
 
   @Test
+  public void mergeRuntimeOutputJarsTest() throws Exception {
+    scratch.file(
+        "foo/custom_library.bzl",
+        "def _impl(ctx):",
+        "  java_provider = java_common.merge([dep[JavaInfo] for dep in ctx.attr.deps])",
+        "  return [java_provider]",
+        "custom_library = rule(",
+        "  attrs = {",
+        "    'deps': attr.label_list(),",
+        "    'strict_deps': attr.bool()",
+        "  },",
+        "  implementation = _impl",
+        ")");
+    scratch.file(
+        "foo/BUILD",
+        "load(':custom_library.bzl', 'custom_library')",
+        "custom_library(name = 'custom', deps = [':a', ':b'])",
+        "java_library(name = 'a', srcs = ['java/A.java'])",
+        "java_library(name = 'b', srcs = ['java/B.java'])");
+
+    ConfiguredTarget myRuleTarget = getConfiguredTarget("//foo:custom");
+    JavaInfo javaInfo = (JavaInfo) myRuleTarget.get(JavaInfo.PROVIDER.getKey());
+    List<String> directJars = prettyArtifactNames(javaInfo.getRuntimeOutputJars());
+    assertThat(directJars).containsExactly("foo/liba.jar", "foo/libb.jar");
+  }
+
+  @Test
+  public void mergeSourceInfo() throws Exception {
+    scratch.file(
+        "foo/custom_library.bzl",
+        "def _impl(ctx):",
+        "  java_provider = java_common.merge([dep[JavaInfo] for dep in ctx.attr.deps])",
+        "  return [java_provider]",
+        "custom_library = rule(",
+        "  attrs = {",
+        "    'deps': attr.label_list(),",
+        "    'strict_deps': attr.bool()",
+        "  },",
+        "  implementation = _impl",
+        ")");
+    scratch.file(
+        "foo/BUILD",
+        "load(':custom_library.bzl', 'custom_library')",
+        "custom_library(name = 'custom', deps = [':a', ':b'])",
+        "java_import(name = 'a', jars = ['java/A.jar'])",
+        "java_import(name = 'b', jars = ['java/B.jar'])");
+
+    ConfiguredTarget myRuleTarget = getConfiguredTarget("//foo:custom");
+    JavaSourceInfoProvider sourceInfo =
+        JavaInfo.getProvider(JavaSourceInfoProvider.class, myRuleTarget);
+    assertThat(prettyArtifactNames(sourceInfo.getJarFiles()))
+        .containsExactly("foo/java/A.jar", "foo/java/B.jar");
+  }
+
+  @Test
   public void javaToolchainFlag_default() throws Exception {
     writeBuildFileForJavaToolchain();
     scratch.file(