1package dev.mboa.errorprone
2
3import com.android.build.api.variant.AndroidComponentsExtension
4import org.gradle.api.Plugin
5import org.gradle.api.Project
6import org.gradle.api.tasks.compile.JavaCompile
7import org.gradle.process.CommandLineArgumentProvider
8
9class ErrorProneAgpPlugin : Plugin<Project> {
10 override fun apply(project: Project) {
11 val errorproneConfiguration = project.configurations.create("errorprone").apply {
12 isVisible = false
13 isCanBeConsumed = false
14 isCanBeResolved = true
15 description = "ErrorProne dependencies for static analysis"
16 }
17
18 // Wait for the Android plugin to be applied before accessing its extensions
19 project.pluginManager.withPlugin("com.android.application") {
20 configureErrorProne(project, errorproneConfiguration)
21 }
22
23 project.pluginManager.withPlugin("com.android.library") {
24 configureErrorProne(project, errorproneConfiguration)
25 }
26 }
27
28 private fun configureErrorProne(project: Project, errorproneConfiguration: org.gradle.api.artifacts.Configuration) {
29 val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
30
31 androidComponents.onVariants { variant ->
32 // Use afterEvaluate to ensure we configure after AGP/databinding have set up their annotation processors
33 project.afterEvaluate {
34 project.tasks.withType(JavaCompile::class.java).configureEach {
35 if (name.contains(variant.name, ignoreCase = true)) {
36 // Add ErrorProne to the annotation processor path
37 // This makes it available to the compiler as a plugin
38 val currentPath = options.annotationProcessorPath ?: project.files()
39 options.annotationProcessorPath = currentPath.plus(errorproneConfiguration)
40
41 val isTestVariant = variant.name.contains("test", ignoreCase = true) ||
42 variant.name.contains("androidTest", ignoreCase = true)
43
44 options.compilerArgumentProviders.add(CommandLineArgumentProvider {
45 val args = mutableListOf(
46 "-XDcompilePolicy=simple", // Required by ErrorProne
47 "-XDshould-stop.ifError=FLOW", // Required by ErrorProne
48 "-Xplugin:ErrorProne"
49 )
50 if (isTestVariant) {
51 args.add("-XepCompilingTestOnlyCode")
52 }
53 args
54 })
55
56 // ErrorProne requires access to internal JDK compiler APIs
57 // Enable forking and add required JVM arguments
58 options.isFork = true
59 options.forkOptions.jvmArgs = options.forkOptions.jvmArgs ?: mutableListOf()
60 (options.forkOptions.jvmArgs as MutableList).addAll(listOf(
61 "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
62 "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
63 "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
64 "--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED",
65 "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
66 "--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED",
67 "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
68 "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
69 "--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
70 "--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED"
71 ))
72 }
73 }
74 }
75 }
76 }
77}