Kapt: Support apt options (KT-13984)
(cherry picked from commit b566a37)
This commit is contained in:
committed by
Yan Zhulanow
parent
0ae9a7a9d1
commit
f15f90a719
+15
-1
@@ -25,6 +25,8 @@ class Kapt2IT: BaseGradleIT() {
|
|||||||
private const val GRADLE_VERSION = "2.10"
|
private const val GRADLE_VERSION = "2.10"
|
||||||
private const val GRADLE_2_14_VERSION = "2.14.1"
|
private const val GRADLE_2_14_VERSION = "2.14.1"
|
||||||
private const val ANDROID_GRADLE_PLUGIN_VERSION = "1.5.+"
|
private const val ANDROID_GRADLE_PLUGIN_VERSION = "1.5.+"
|
||||||
|
|
||||||
|
private val KAPT_SUCCESSFUL_REGEX = "Annotation processing complete in [0-9]+ ms, 0 errors, 0 warnings".toRegex()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun androidBuildOptions() =
|
private fun androidBuildOptions() =
|
||||||
@@ -35,8 +37,9 @@ class Kapt2IT: BaseGradleIT() {
|
|||||||
override fun defaultBuildOptions(): BuildOptions =
|
override fun defaultBuildOptions(): BuildOptions =
|
||||||
super.defaultBuildOptions().copy(withDaemon = true)
|
super.defaultBuildOptions().copy(withDaemon = true)
|
||||||
|
|
||||||
|
|
||||||
private fun CompiledProject.assertKaptSuccessful() {
|
private fun CompiledProject.assertKaptSuccessful() {
|
||||||
assertContains("Kapt: Annotation processing complete, 0 errors, 0 warnings")
|
KAPT_SUCCESSFUL_REGEX.findAll(this.output).single()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -98,6 +101,17 @@ class Kapt2IT: BaseGradleIT() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testArguments() {
|
||||||
|
Project("arguments", GRADLE_VERSION, directoryPrefix = "kapt2").build("build") {
|
||||||
|
assertSuccessful()
|
||||||
|
assertKaptSuccessful()
|
||||||
|
assertFileExists("build/generated/source/kapt2/main/example/TestClassCustomized.java")
|
||||||
|
assertFileExists("build/classes/main/example/TestClass.class")
|
||||||
|
assertFileExists("build/classes/main/example/TestClassCustomized.class")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testInheritedAnnotations() {
|
fun testInheritedAnnotations() {
|
||||||
Project("inheritedAnnotations", GRADLE_VERSION, directoryPrefix = "kapt2").build("build") {
|
Project("inheritedAnnotations", GRADLE_VERSION, directoryPrefix = "kapt2").build("build") {
|
||||||
|
|||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: "kotlin"
|
||||||
|
apply plugin: "kotlin-kapt"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
compile "org.jetbrains.kotlin:annotation-processor-example:$kotlin_version"
|
||||||
|
kapt "org.jetbrains.kotlin:annotation-processor-example:$kotlin_version"
|
||||||
|
}
|
||||||
|
|
||||||
|
kapt {
|
||||||
|
arguments {
|
||||||
|
arg("suffix", "Customized")
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
kapt.verbose=true
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package example
|
||||||
|
|
||||||
|
@example.ExampleAnnotation
|
||||||
|
public class TestClass {
|
||||||
|
|
||||||
|
@example.ExampleAnnotation
|
||||||
|
public val testVal: String = "text"
|
||||||
|
|
||||||
|
@example.ExampleAnnotation
|
||||||
|
public fun testFunction(): Class<*> = TestClassCustomized::class.java
|
||||||
|
|
||||||
|
}
|
||||||
+1
-1
@@ -201,7 +201,7 @@ class AnnotationProcessingManager(
|
|||||||
|
|
||||||
private fun appendAdditionalComplerArgs() {
|
private fun appendAdditionalComplerArgs() {
|
||||||
val kaptExtension = project.extensions.getByType(KaptExtension::class.java)
|
val kaptExtension = project.extensions.getByType(KaptExtension::class.java)
|
||||||
val args = kaptExtension.getAdditionalArguments(project, androidVariant, getAndroidExtension())
|
val args = kaptExtension.getAdditionalArgumentsForJavac(project, androidVariant, getAndroidExtension())
|
||||||
if (args.isEmpty()) return
|
if (args.isEmpty()) return
|
||||||
|
|
||||||
javaTask.modifyCompilerArguments { list ->
|
javaTask.modifyCompilerArguments { list ->
|
||||||
|
|||||||
+9
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.internal
|
package org.jetbrains.kotlin.gradle.internal
|
||||||
|
|
||||||
|
import com.android.build.gradle.BaseExtension
|
||||||
import com.android.build.gradle.api.AndroidSourceSet
|
import com.android.build.gradle.api.AndroidSourceSet
|
||||||
import com.android.build.gradle.internal.variant.BaseVariantData
|
import com.android.build.gradle.internal.variant.BaseVariantData
|
||||||
import com.android.builder.model.SourceProvider
|
import com.android.builder.model.SourceProvider
|
||||||
@@ -124,6 +125,14 @@ class Kapt2KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
|
|||||||
pluginOptions += SubpluginOption("verbose", "true")
|
pluginOptions += SubpluginOption("verbose", "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val androidPlugin = variantData?.let {
|
||||||
|
project.extensions.findByName("android") as? BaseExtension
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((key, value) in kaptExtension.getAdditionalArguments(project, variantData, androidPlugin)) {
|
||||||
|
pluginOptions += SubpluginOption("apoption", "$key:$value")
|
||||||
|
}
|
||||||
|
|
||||||
val annotationsFile = File(kotlinCompile.taskBuildDirectory, "source-annotations.txt")
|
val annotationsFile = File(kotlinCompile.taskBuildDirectory, "source-annotations.txt")
|
||||||
kotlinCompile.sourceAnnotationsRegistry = SourceAnnotationsRegistry(annotationsFile)
|
kotlinCompile.sourceAnnotationsRegistry = SourceAnnotationsRegistry(annotationsFile)
|
||||||
|
|
||||||
|
|||||||
+22
-11
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.gradle.plugin
|
|||||||
|
|
||||||
import groovy.lang.Closure
|
import groovy.lang.Closure
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
open class KaptExtension {
|
open class KaptExtension {
|
||||||
|
|
||||||
@@ -31,26 +32,36 @@ open class KaptExtension {
|
|||||||
this.closure = closure
|
this.closure = closure
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAdditionalArguments(project: Project, variant: Any?, android: Any?): List<String> {
|
fun getAdditionalArguments(project: Project, variantData: Any?, androidExtension: Any?): Map<String, String> {
|
||||||
val closureToExecute = closure ?: return emptyList()
|
val closureToExecute = closure ?: return emptyMap()
|
||||||
|
|
||||||
val executor = KaptAdditionalArgumentsDelegate(project, variant, android)
|
val executor = KaptAdditionalArgumentsDelegate(project, variantData, androidExtension)
|
||||||
executor.execute(closureToExecute)
|
executor.execute(closureToExecute)
|
||||||
return executor.additionalCompilerArgs
|
return executor.args
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAdditionalArgumentsForJavac(project: Project, variantData: Any?, androidExtension: Any?): List<String> {
|
||||||
|
val javacArgs = mutableListOf<String>()
|
||||||
|
for ((key, value) in getAdditionalArguments(project, variantData, androidExtension)) {
|
||||||
|
javacArgs += "-A" + key + (if (value.isNotEmpty()) "=$value" else "")
|
||||||
|
}
|
||||||
|
return javacArgs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [project], [variant] and [android] properties are intended to be used inside the closure.
|
||||||
|
*/
|
||||||
open class KaptAdditionalArgumentsDelegate(
|
open class KaptAdditionalArgumentsDelegate(
|
||||||
open val project: Project,
|
@Suppress("unused") open val project: Project,
|
||||||
open val variant: Any?,
|
@Suppress("unused") open val variant: Any?,
|
||||||
open val android: Any?
|
@Suppress("unused") open val android: Any?
|
||||||
) {
|
) {
|
||||||
|
internal val args = LinkedHashMap<String, String>()
|
||||||
|
|
||||||
val additionalCompilerArgs = arrayListOf<String>()
|
@Suppress("unused")
|
||||||
|
|
||||||
open fun arg(name: Any, vararg values: Any) {
|
open fun arg(name: Any, vararg values: Any) {
|
||||||
val valuesString = if (values.isNotEmpty()) values.joinToString(" ", prefix = "=") else ""
|
args.put(name.toString(), values.joinToString(" "))
|
||||||
additionalCompilerArgs.add("-A$name$valuesString")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun execute(closure: Closure<*>) {
|
fun execute(closure: Closure<*>) {
|
||||||
|
|||||||
+4
-3
@@ -45,10 +45,10 @@ import java.net.URLClassLoader
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.annotation.processing.Processor
|
import javax.annotation.processing.Processor
|
||||||
import javax.tools.Diagnostic
|
import javax.tools.Diagnostic
|
||||||
import kotlin.system.measureTimeMillis
|
|
||||||
|
|
||||||
class ClasspathBasedAnnotationProcessingExtension(
|
class ClasspathBasedAnnotationProcessingExtension(
|
||||||
val annotationProcessingClasspath: List<File>,
|
val annotationProcessingClasspath: List<File>,
|
||||||
|
override val options: Map<String, String>,
|
||||||
generatedSourcesOutputDir: File,
|
generatedSourcesOutputDir: File,
|
||||||
classesOutputDir: File,
|
classesOutputDir: File,
|
||||||
javaSourceRoots: List<File>,
|
javaSourceRoots: List<File>,
|
||||||
@@ -75,7 +75,7 @@ abstract class AbstractAnnotationProcessingExtension(
|
|||||||
private companion object {
|
private companion object {
|
||||||
val LINE_SEPARATOR = System.getProperty("line.separator") ?: "\n"
|
val LINE_SEPARATOR = System.getProperty("line.separator") ?: "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
private var annotationProcessingComplete = false
|
private var annotationProcessingComplete = false
|
||||||
private val messager = KotlinMessager()
|
private val messager = KotlinMessager()
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ abstract class AbstractAnnotationProcessingExtension(
|
|||||||
val javaPsiFacade = JavaPsiFacade.getInstance(project)
|
val javaPsiFacade = JavaPsiFacade.getInstance(project)
|
||||||
val projectScope = GlobalSearchScope.projectScope(project)
|
val projectScope = GlobalSearchScope.projectScope(project)
|
||||||
|
|
||||||
val options = emptyMap<String, String>()
|
val options = this.options
|
||||||
log { "Options: $options" }
|
log { "Options: $options" }
|
||||||
|
|
||||||
val filer = KotlinFiler(generatedSourcesOutputDir, classesOutputDir)
|
val filer = KotlinFiler(generatedSourcesOutputDir, classesOutputDir)
|
||||||
@@ -324,6 +324,7 @@ abstract class AbstractAnnotationProcessingExtension(
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun loadAnnotationProcessors(): List<Processor>
|
protected abstract fun loadAnnotationProcessors(): List<Processor>
|
||||||
|
protected abstract val options: Map<String, String>
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ProcessingResult(val errorCount: Int, val warningCount: Int, val wasAnythingGenerated: Boolean)
|
private class ProcessingResult(val errorCount: Int, val warningCount: Int, val wasAnythingGenerated: Boolean)
|
||||||
|
|||||||
+28
-9
@@ -35,6 +35,9 @@ import org.jetbrains.kotlin.java.model.internal.JeElementRegistry
|
|||||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
|
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.annotation.processing.AnnotationProcessingConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH
|
||||||
|
import org.jetbrains.kotlin.annotation.processing.AnnotationProcessingConfigurationKeys.APT_OPTIONS
|
||||||
|
|
||||||
object AnnotationProcessingConfigurationKeys {
|
object AnnotationProcessingConfigurationKeys {
|
||||||
val GENERATED_OUTPUT_DIR: CompilerConfigurationKey<String> =
|
val GENERATED_OUTPUT_DIR: CompilerConfigurationKey<String> =
|
||||||
CompilerConfigurationKey.create<String>("generated files output directory")
|
CompilerConfigurationKey.create<String>("generated files output directory")
|
||||||
@@ -45,6 +48,9 @@ object AnnotationProcessingConfigurationKeys {
|
|||||||
val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> =
|
val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> =
|
||||||
CompilerConfigurationKey.create<List<String>>("annotation processor classpath")
|
CompilerConfigurationKey.create<List<String>>("annotation processor classpath")
|
||||||
|
|
||||||
|
val APT_OPTIONS: CompilerConfigurationKey<List<String>> =
|
||||||
|
CompilerConfigurationKey.create<List<String>>("annotation processing options")
|
||||||
|
|
||||||
val INCREMENTAL_DATA_FILE: CompilerConfigurationKey<String> =
|
val INCREMENTAL_DATA_FILE: CompilerConfigurationKey<String> =
|
||||||
CompilerConfigurationKey.create<String>("data file for incremental compilation support")
|
CompilerConfigurationKey.create<String>("data file for incremental compilation support")
|
||||||
|
|
||||||
@@ -66,6 +72,10 @@ class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
|
|||||||
CliOption("apclasspath", "<classpath>", "Annotation processor classpath",
|
CliOption("apclasspath", "<classpath>", "Annotation processor classpath",
|
||||||
required = false, allowMultipleOccurrences = true)
|
required = false, allowMultipleOccurrences = true)
|
||||||
|
|
||||||
|
val APT_OPTIONS_OPTION: CliOption =
|
||||||
|
CliOption("apoption", "<key>:<value>", "Annotation processor option",
|
||||||
|
required = false, allowMultipleOccurrences = true)
|
||||||
|
|
||||||
val INCREMENTAL_DATA_FILE_OPTION: CliOption =
|
val INCREMENTAL_DATA_FILE_OPTION: CliOption =
|
||||||
CliOption("incrementalData", "<path>", "Location of the incremental data file", required = false)
|
CliOption("incrementalData", "<path>", "Location of the incremental data file", required = false)
|
||||||
|
|
||||||
@@ -76,16 +86,19 @@ class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
|
|||||||
override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
|
override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
|
||||||
|
|
||||||
override val pluginOptions: Collection<CliOption> =
|
override val pluginOptions: Collection<CliOption> =
|
||||||
listOf(GENERATED_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION,
|
listOf(GENERATED_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION, APT_OPTIONS_OPTION,
|
||||||
CLASS_FILES_OUTPUT_DIR_OPTION, INCREMENTAL_DATA_FILE_OPTION, VERBOSE_MODE_OPTION)
|
CLASS_FILES_OUTPUT_DIR_OPTION, INCREMENTAL_DATA_FILE_OPTION, VERBOSE_MODE_OPTION)
|
||||||
|
|
||||||
|
private fun <T> CompilerConfiguration.appendList(option: CompilerConfigurationKey<List<T>>, value: T) {
|
||||||
|
val paths = getList(option).toMutableList()
|
||||||
|
paths.add(value)
|
||||||
|
put(option, paths)
|
||||||
|
}
|
||||||
|
|
||||||
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
|
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
|
||||||
when (option) {
|
when (option) {
|
||||||
ANNOTATION_PROCESSOR_CLASSPATH_OPTION -> {
|
ANNOTATION_PROCESSOR_CLASSPATH_OPTION -> configuration.appendList(ANNOTATION_PROCESSOR_CLASSPATH, value)
|
||||||
val paths = configuration.getList(AnnotationProcessingConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH).toMutableList()
|
APT_OPTIONS_OPTION -> configuration.appendList(APT_OPTIONS, value)
|
||||||
paths.add(value)
|
|
||||||
configuration.put(AnnotationProcessingConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH, paths)
|
|
||||||
}
|
|
||||||
GENERATED_OUTPUT_DIR_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.GENERATED_OUTPUT_DIR, value)
|
GENERATED_OUTPUT_DIR_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.GENERATED_OUTPUT_DIR, value)
|
||||||
CLASS_FILES_OUTPUT_DIR_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.CLASS_FILES_OUTPUT_DIR, value)
|
CLASS_FILES_OUTPUT_DIR_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.CLASS_FILES_OUTPUT_DIR, value)
|
||||||
INCREMENTAL_DATA_FILE_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.INCREMENTAL_DATA_FILE, value)
|
INCREMENTAL_DATA_FILE_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.INCREMENTAL_DATA_FILE, value)
|
||||||
@@ -98,8 +111,14 @@ class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
|
|||||||
class AnnotationProcessingComponentRegistrar : ComponentRegistrar {
|
class AnnotationProcessingComponentRegistrar : ComponentRegistrar {
|
||||||
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
|
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
|
||||||
val generatedOutputDir = configuration.get(AnnotationProcessingConfigurationKeys.GENERATED_OUTPUT_DIR) ?: return
|
val generatedOutputDir = configuration.get(AnnotationProcessingConfigurationKeys.GENERATED_OUTPUT_DIR) ?: return
|
||||||
val apClasspath = configuration.get(AnnotationProcessingConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH)?.map(::File) ?: return
|
val apClasspath = configuration.get(ANNOTATION_PROCESSOR_CLASSPATH)?.map(::File) ?: return
|
||||||
|
|
||||||
|
val apOptions = (configuration.get(APT_OPTIONS) ?: listOf())
|
||||||
|
.map { it.split(':') }
|
||||||
|
.filter { it.size == 2 }
|
||||||
|
.map { it[0] to it[1] }
|
||||||
|
.toMap()
|
||||||
|
|
||||||
val incrementalDataFile = configuration.get(AnnotationProcessingConfigurationKeys.INCREMENTAL_DATA_FILE)?.let(::File)
|
val incrementalDataFile = configuration.get(AnnotationProcessingConfigurationKeys.INCREMENTAL_DATA_FILE)?.let(::File)
|
||||||
|
|
||||||
val generatedOutputDirFile = File(generatedOutputDir)
|
val generatedOutputDirFile = File(generatedOutputDir)
|
||||||
@@ -126,7 +145,7 @@ class AnnotationProcessingComponentRegistrar : ComponentRegistrar {
|
|||||||
val sourceRetentionAnnotationHandler = configuration[JVMConfigurationKeys.SOURCE_RETENTION_ANNOTATION_HANDLER]
|
val sourceRetentionAnnotationHandler = configuration[JVMConfigurationKeys.SOURCE_RETENTION_ANNOTATION_HANDLER]
|
||||||
|
|
||||||
val annotationProcessingExtension = ClasspathBasedAnnotationProcessingExtension(
|
val annotationProcessingExtension = ClasspathBasedAnnotationProcessingExtension(
|
||||||
classpath, generatedOutputDirFile, classesOutputDir, javaRoots, verboseOutput,
|
classpath, apOptions, generatedOutputDirFile, classesOutputDir, javaRoots, verboseOutput,
|
||||||
incrementalDataFile, sourceRetentionAnnotationHandler)
|
incrementalDataFile, sourceRetentionAnnotationHandler)
|
||||||
|
|
||||||
project.registerService(JeElementRegistry::class.java, JeElementRegistry())
|
project.registerService(JeElementRegistry::class.java, JeElementRegistry())
|
||||||
|
|||||||
+4
-1
@@ -46,7 +46,10 @@ class AnnotationProcessingExtensionForTests(
|
|||||||
) : AbstractAnnotationProcessingExtension(createTempDir(), createTempDir(), listOf(), true,
|
) : AbstractAnnotationProcessingExtension(createTempDir(), createTempDir(), listOf(), true,
|
||||||
createIncrementalDataFile(), SourceRetentionAnnotationHandlerImpl()) {
|
createIncrementalDataFile(), SourceRetentionAnnotationHandlerImpl()) {
|
||||||
override fun loadAnnotationProcessors() = processors
|
override fun loadAnnotationProcessors() = processors
|
||||||
|
|
||||||
|
override val options: Map<String, String>
|
||||||
|
get() = emptyMap()
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
fun createTempDir(): File = Files.createTempDirectory("ap-test").toFile().apply {
|
fun createTempDir(): File = Files.createTempDirectory("ap-test").toFile().apply {
|
||||||
deleteOnExit()
|
deleteOnExit()
|
||||||
|
|||||||
Reference in New Issue
Block a user