diff --git a/android/neverallow.go b/android/neverallow.go index b89d150cb..39013d11f 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -61,6 +61,7 @@ func init() { AddNeverAllowRules(createJavaExcludeStaticLibsRule()) AddNeverAllowRules(createProhibitHeaderOnlyRule()) AddNeverAllowRules(createLimitNdkExportRule()...) + AddNeverAllowRules(createKotlinPluginRule()...) } // Add a NeverAllow rule to the set of rules to apply. @@ -284,6 +285,22 @@ func createLimitNdkExportRule() []Rule { } } +func createKotlinPluginRule() []Rule { + kotlinPluginProjectsAllowedList := []string{ + // TODO: Migrate compose plugin to the bundled compiler plugin + // Actual path prebuilts/sdk/current/androidx/m2repository/androidx/compose/compiler/compiler-hosted + "prebuilts/sdk/current/androidx", + "external/kotlinc", + } + + return []Rule{ + NeverAllow(). + NotIn(kotlinPluginProjectsAllowedList...). + ModuleType("kotlin_plugin"). + Because("kotlin_plugin can only be used in allowed projects"), + } +} + func neverallowMutator(ctx BottomUpMutatorContext) { m, ok := ctx.Module().(Module) if !ok { diff --git a/java/base.go b/java/base.go index b64eb5b61..22d781e72 100644 --- a/java/base.go +++ b/java/base.go @@ -116,6 +116,9 @@ type CommonProperties struct { // List of modules to use as annotation processors Plugins []string + // List of modules to use as kotlin plugin + Kotlin_plugins []string + // List of modules to export to libraries that directly depend on this library as annotation // processors. Note that if the plugins set generates_api: true this will disable the turbine // optimization on modules that depend on this module, which will reduce parallelism and cause @@ -901,6 +904,7 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { } ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), pluginTag, j.properties.Plugins...) + ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag, j.properties.Kotlin_plugins...) ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), errorpronePluginTag, j.properties.Errorprone.Extra_check_modules...) ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), exportedPluginTag, j.properties.Exported_plugins...) @@ -933,7 +937,7 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { if j.useCompose(ctx) { ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag, - "androidx.compose.compiler_compiler-hosted") + "androidx.compose.compiler_compiler-hosted-plugin") } } @@ -2519,7 +2523,11 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName) } case kotlinPluginTag: - deps.kotlinPlugins = append(deps.kotlinPlugins, dep.ImplementationAndResourcesJars...) + if _, ok := module.(*KotlinPlugin); ok { + deps.kotlinPlugins = append(deps.kotlinPlugins, dep.ImplementationAndResourcesJars...) + } else { + ctx.PropertyErrorf("kotlin_plugins", "%q is not a kotlin_plugin module", otherName) + } case syspropPublicStubDepTag: // This is a sysprop implementation library, forward the JavaInfoProvider from // the corresponding sysprop public stub library as SyspropPublicStubInfoProvider. diff --git a/java/kotlin_test.go b/java/kotlin_test.go index f6e7fcaaa..45eac0134 100644 --- a/java/kotlin_test.go +++ b/java/kotlin_test.go @@ -500,8 +500,8 @@ func TestKotlinCompose(t *testing.T) { name: "androidx.compose.runtime_runtime", } - java_library_host { - name: "androidx.compose.compiler_compiler-hosted", + kotlin_plugin { + name: "androidx.compose.compiler_compiler-hosted-plugin", } java_library { @@ -523,7 +523,7 @@ func TestKotlinCompose(t *testing.T) { buildOS := result.Config.BuildOS.String() - composeCompiler := result.ModuleForTests("androidx.compose.compiler_compiler-hosted", buildOS+"_common").Rule("combineJar").Output + composeCompiler := result.ModuleForTests("androidx.compose.compiler_compiler-hosted-plugin", buildOS+"_common").Rule("combineJar").Output withCompose := result.ModuleForTests("withcompose", "android_common") noCompose := result.ModuleForTests("nocompose", "android_common") @@ -542,3 +542,50 @@ func TestKotlinCompose(t *testing.T) { android.AssertStringDoesNotContain(t, "unexpected compose compiler plugin", noCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String()) } + +func TestKotlinPlugin(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).RunTestWithBp(t, ` + kotlin_plugin { + name: "kotlin_plugin", + } + + java_library { + name: "with_kotlin_plugin", + srcs: ["a.kt"], + plugins: ["plugin"], + kotlin_plugins: ["kotlin_plugin"], + } + + java_library { + name: "no_kotlin_plugin", + srcs: ["a.kt"], + } + + java_plugin { + name: "plugin", + } + `) + + buildOS := result.Config.BuildOS.String() + + kotlinPlugin := result.ModuleForTests("kotlin_plugin", buildOS+"_common").Rule("combineJar").Output + withKotlinPlugin := result.ModuleForTests("with_kotlin_plugin", "android_common") + noKotlinPlugin := result.ModuleForTests("no_kotlin_plugin", "android_common") + + android.AssertStringListContains(t, "missing plugin compiler dependency", + withKotlinPlugin.Rule("kotlinc").Implicits.Strings(), kotlinPlugin.String()) + + android.AssertStringDoesContain(t, "missing kotlin plugin", + withKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+kotlinPlugin.String()) + + android.AssertStringListContains(t, "missing kapt kotlin plugin dependency", + withKotlinPlugin.Rule("kapt").Implicits.Strings(), kotlinPlugin.String()) + + android.AssertStringListDoesNotContain(t, "unexpected kotlin plugin dependency", + noKotlinPlugin.Rule("kotlinc").Implicits.Strings(), kotlinPlugin.String()) + + android.AssertStringDoesNotContain(t, "unexpected kotlin plugin", + noKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+kotlinPlugin.String()) +} diff --git a/java/plugin.go b/java/plugin.go index 9c4774a10..610c9fd11 100644 --- a/java/plugin.go +++ b/java/plugin.go @@ -24,6 +24,7 @@ func init() { func registerJavaPluginBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("java_plugin", PluginFactory) + ctx.RegisterModuleType("kotlin_plugin", KotlinPluginFactory) } func PluginFactory() android.Module { @@ -37,6 +38,16 @@ func PluginFactory() android.Module { return module } +func KotlinPluginFactory() android.Module { + module := &KotlinPlugin{} + + module.addHostProperties() + + InitJavaModule(module, android.HostSupported) + + return module +} + // Plugin describes a java_plugin module, a host java library that will be used by javac as an annotation processor. type Plugin struct { Library @@ -53,3 +64,8 @@ type PluginProperties struct { // parallelism and cause more recompilation for modules that depend on modules that use this plugin. Generates_api *bool } + +// Plugin describes a kotlin_plugin module, a host java/kotlin library that will be used by kotlinc as a compiler plugin. +type KotlinPlugin struct { + Library +}