Enable compose kotlinc plugin when depending on the compose runtime

When a module depends on the compose runtime add a -Xplugin argument
to the kotlinc flags that enables the compose compiler plugin.

Bug: 196351110
Test: TestKotlinCompose
Change-Id: I423a3c4d12df42804a24b672a40a165bc8dd165f
diff --git a/java/base.go b/java/base.go
index 86022c3..86e378b 100644
--- a/java/base.go
+++ b/java/base.go
@@ -643,6 +643,11 @@
 	} else if j.shouldInstrumentStatic(ctx) {
 		ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent")
 	}
+
+	if j.useCompose() {
+		ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag,
+			"androidx.compose.compiler_compiler-hosted")
+	}
 }
 
 func hasSrcExt(srcs []string, ext string) bool {
@@ -911,6 +916,12 @@
 		if ctx.Device() {
 			kotlincFlags = append(kotlincFlags, "-no-jdk")
 		}
+
+		for _, plugin := range deps.kotlinPlugins {
+			kotlincFlags = append(kotlincFlags, "-Xplugin="+plugin.String())
+		}
+		flags.kotlincDeps = append(flags.kotlincDeps, deps.kotlinPlugins...)
+
 		if len(kotlincFlags) > 0 {
 			// optimization.
 			ctx.Variable(pctx, "kotlincFlags", strings.Join(kotlincFlags, " "))
@@ -1325,6 +1336,10 @@
 	j.outputFile = outputFile.WithoutRel()
 }
 
+func (j *Module) useCompose() bool {
+	return android.InList("androidx.compose.runtime_runtime", j.properties.Static_libs)
+}
+
 // Returns a copy of the supplied flags, but with all the errorprone-related
 // fields copied to the regular build's fields.
 func enableErrorproneFlags(flags javaBuilderFlags) javaBuilderFlags {
@@ -1755,6 +1770,8 @@
 				deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars...)
 			case kotlinAnnotationsTag:
 				deps.kotlinAnnotations = dep.HeaderJars
+			case kotlinPluginTag:
+				deps.kotlinPlugins = append(deps.kotlinPlugins, dep.ImplementationAndResourcesJars...)
 			case syspropPublicStubDepTag:
 				// This is a sysprop implementation library, forward the JavaInfoProvider from
 				// the corresponding sysprop public stub library as SyspropPublicStubInfoProvider.
diff --git a/java/builder.go b/java/builder.go
index ea011b8..ae124a3 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -263,6 +263,7 @@
 
 	kotlincFlags     string
 	kotlincClasspath classpath
+	kotlincDeps      android.Paths
 
 	proto android.ProtoFlags
 }
diff --git a/java/java.go b/java/java.go
index 1a052b4..a1175ba 100644
--- a/java/java.go
+++ b/java/java.go
@@ -286,6 +286,7 @@
 	frameworkResTag         = dependencyTag{name: "framework-res"}
 	kotlinStdlibTag         = dependencyTag{name: "kotlin-stdlib"}
 	kotlinAnnotationsTag    = dependencyTag{name: "kotlin-annotations"}
+	kotlinPluginTag         = dependencyTag{name: "kotlin-plugin"}
 	proguardRaiseTag        = dependencyTag{name: "proguard-raise"}
 	certificateTag          = dependencyTag{name: "certificate"}
 	instrumentationForTag   = dependencyTag{name: "instrumentation_for"}
@@ -380,6 +381,7 @@
 	aidlPreprocess          android.OptionalPath
 	kotlinStdlib            android.Paths
 	kotlinAnnotations       android.Paths
+	kotlinPlugins           android.Paths
 
 	disableTurbine bool
 }
diff --git a/java/kotlin.go b/java/kotlin.go
index 3a6fc0f..e4f1bc1 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -81,6 +81,7 @@
 
 	var deps android.Paths
 	deps = append(deps, flags.kotlincClasspath...)
+	deps = append(deps, flags.kotlincDeps...)
 	deps = append(deps, srcJars...)
 	deps = append(deps, commonSrcFiles...)
 
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index db30696..cac0af3 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -281,3 +281,46 @@
 		})
 	}
 }
+
+func TestKotlinCompose(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+	).RunTestWithBp(t, `
+		java_library {
+			name: "androidx.compose.runtime_runtime",
+		}
+
+		java_library_host {
+			name: "androidx.compose.compiler_compiler-hosted",
+		}
+
+		java_library {
+			name: "withcompose",
+			srcs: ["a.kt"],
+			static_libs: ["androidx.compose.runtime_runtime"],
+		}
+
+		java_library {
+			name: "nocompose",
+			srcs: ["a.kt"],
+		}
+	`)
+
+	buildOS := result.Config.BuildOS.String()
+
+	composeCompiler := result.ModuleForTests("androidx.compose.compiler_compiler-hosted", buildOS+"_common").Rule("combineJar").Output
+	withCompose := result.ModuleForTests("withcompose", "android_common")
+	noCompose := result.ModuleForTests("nocompose", "android_common")
+
+	android.AssertStringListContains(t, "missing compose compiler dependency",
+		withCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String())
+
+	android.AssertStringDoesContain(t, "missing compose compiler plugin",
+		withCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String())
+
+	android.AssertStringListDoesNotContain(t, "unexpected compose compiler dependency",
+		noCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String())
+
+	android.AssertStringDoesNotContain(t, "unexpected compose compiler plugin",
+		noCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String())
+}