Kapt: Support specifying javac options (KT-17245)

This commit is contained in:
Yan Zhulanow
2017-04-05 19:12:23 +03:00
committed by Yan Zhulanow
parent 8cdb08cbfe
commit 3ee65ac499
8 changed files with 82 additions and 27 deletions
@@ -124,7 +124,8 @@ class Kapt3IT : BaseGradleIT() {
assertKaptSuccessful() assertKaptSuccessful()
assertContains("Options: {suffix=Customized, justColon=:, justEquals==, containsColon=a:b, " + assertContains("Options: {suffix=Customized, justColon=:, justEquals==, containsColon=a:b, " +
"containsEquals=a=b, startsWithColon=:a, startsWithEquals==a, endsWithColon=a:, " + "containsEquals=a=b, startsWithColon=:a, startsWithEquals==a, endsWithColon=a:, " +
"endsWithEquals=a:, withSpace=a b c}") "endsWithEquals=a:, withSpace=a b c,")
assertContains("-Xmaxerrs=500, -Xlint:all=-Xlint:all") // Javac options test
assertFileExists("build/generated/source/kapt/main/example/TestClassCustomized.java") assertFileExists("build/generated/source/kapt/main/example/TestClassCustomized.java")
assertFileExists("build/classes/main/example/TestClass.class") assertFileExists("build/classes/main/example/TestClass.class")
assertFileExists("build/classes/main/example/TestClassCustomized.class") assertFileExists("build/classes/main/example/TestClassCustomized.class")
@@ -33,4 +33,9 @@ kapt {
arg("endsWithEquals", "a:") arg("endsWithEquals", "a:")
arg("withSpace", "a b c") // key doesn't support spaces arg("withSpace", "a b c") // key doesn't support spaces
} }
javacOptions {
option("-Xmaxerrs", 500)
option("-Xlint:all")
}
} }
@@ -29,7 +29,6 @@ import org.gradle.api.tasks.compile.JavaCompile
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.preprocessor.mkdirsOrFail
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.File import java.io.File
import java.io.ObjectOutputStream import java.io.ObjectOutputStream
@@ -193,14 +192,16 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
androidOptions + androidOptions +
mapOf("kapt.kotlin.generated" to kotlinSourcesOutputDir.absolutePath) mapOf("kapt.kotlin.generated" to kotlinSourcesOutputDir.absolutePath)
pluginOptions += SubpluginOption("apoptions", encodeAnnotationProcessingOptions(apOptions)) pluginOptions += SubpluginOption("apoptions", encodeOptions(apOptions))
pluginOptions += SubpluginOption("javacArguments", encodeOptions(kaptExtension.getJavacOptions()))
addMiscOptions(pluginOptions) addMiscOptions(pluginOptions)
return pluginOptions return pluginOptions
} }
fun encodeAnnotationProcessingOptions(options: Map<String, String>): String { fun encodeOptions(options: Map<String, String>): String {
val os = ByteArrayOutputStream() val os = ByteArrayOutputStream()
val oos = ObjectOutputStream(os) val oos = ObjectOutputStream(os)
@@ -32,18 +32,29 @@ open class KaptExtension {
open var processors: String = "" open var processors: String = ""
private var closure: Closure<*>? = null private var apOptionsClosure: Closure<*>? = null
private var javacOptionsClosure: Closure<*>? = null
open fun arguments(closure: Closure<*>) { open fun arguments(closure: Closure<*>) {
this.closure = closure this.apOptionsClosure = closure
}
open fun javacOptions(closure: Closure<*>) {
this.javacOptionsClosure = closure
}
fun getJavacOptions(): Map<String, String> {
val closureToExecute = javacOptionsClosure ?: return emptyMap()
val executor = KaptJavacOptionsDelegate().apply { execute(closureToExecute) }
return executor.options
} }
fun getAdditionalArguments(project: Project, variantData: Any?, androidExtension: Any?): Map<String, String> { fun getAdditionalArguments(project: Project, variantData: Any?, androidExtension: Any?): Map<String, String> {
val closureToExecute = closure ?: return emptyMap() val closureToExecute = apOptionsClosure ?: return emptyMap()
val executor = KaptAdditionalArgumentsDelegate(project, variantData, androidExtension) val executor = KaptAnnotationProcessorOptions(project, variantData, androidExtension)
executor.execute(closureToExecute) executor.execute(closureToExecute)
return executor.args return executor.options
} }
fun getAdditionalArgumentsForJavac(project: Project, variantData: Any?, androidExtension: Any?): List<String> { fun getAdditionalArgumentsForJavac(project: Project, variantData: Any?, androidExtension: Any?): List<String> {
@@ -58,16 +69,16 @@ open class KaptExtension {
/** /**
* [project], [variant] and [android] properties are intended to be used inside the closure. * [project], [variant] and [android] properties are intended to be used inside the closure.
*/ */
open class KaptAdditionalArgumentsDelegate( open class KaptAnnotationProcessorOptions(
@Suppress("unused") open val project: Project, @Suppress("unused") open val project: Project,
@Suppress("unused") open val variant: Any?, @Suppress("unused") open val variant: Any?,
@Suppress("unused") open val android: Any? @Suppress("unused") open val android: Any?
) { ) {
internal val args = LinkedHashMap<String, String>() internal val options = LinkedHashMap<String, String>()
@Suppress("unused") @Suppress("unused")
open fun arg(name: Any, vararg values: Any) { open fun arg(name: Any, vararg values: Any) {
args.put(name.toString(), values.joinToString(" ")) options.put(name.toString(), values.joinToString(" "))
} }
fun execute(closure: Closure<*>) { fun execute(closure: Closure<*>) {
@@ -77,3 +88,21 @@ open class KaptAdditionalArgumentsDelegate(
} }
} }
open class KaptJavacOptionsDelegate {
internal val options = LinkedHashMap<String, String>()
open fun option(name: Any, value: Any) {
options.put(name.toString(), value.toString())
}
open fun option(name: Any) {
options.put(name.toString(), "")
}
fun execute(closure: Closure<*>) {
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure.delegate = this
closure.call()
}
}
@@ -51,6 +51,7 @@ class ClasspathBasedKapt3Extension(
stubsOutputDir: File, stubsOutputDir: File,
incrementalDataOutputDir: File?, incrementalDataOutputDir: File?,
options: Map<String, String>, options: Map<String, String>,
javacOptions: Map<String, String>,
annotationProcessors: String, annotationProcessors: String,
aptOnly: Boolean, aptOnly: Boolean,
val useLightAnalysis: Boolean, val useLightAnalysis: Boolean,
@@ -58,7 +59,7 @@ class ClasspathBasedKapt3Extension(
pluginInitializedTime: Long, pluginInitializedTime: Long,
logger: KaptLogger logger: KaptLogger
) : AbstractKapt3Extension(compileClasspath, annotationProcessingClasspath, javaSourceRoots, sourcesOutputDir, ) : AbstractKapt3Extension(compileClasspath, annotationProcessingClasspath, javaSourceRoots, sourcesOutputDir,
classFilesOutputDir, stubsOutputDir, incrementalDataOutputDir, options, annotationProcessors, classFilesOutputDir, stubsOutputDir, incrementalDataOutputDir, options, javacOptions, annotationProcessors,
aptOnly, pluginInitializedTime, logger, correctErrorTypes) { aptOnly, pluginInitializedTime, logger, correctErrorTypes) {
override val analyzePartially: Boolean override val analyzePartially: Boolean
get() = useLightAnalysis get() = useLightAnalysis
@@ -103,6 +104,7 @@ abstract class AbstractKapt3Extension(
val stubsOutputDir: File, val stubsOutputDir: File,
val incrementalDataOutputDir: File?, val incrementalDataOutputDir: File?,
val options: Map<String, String>, val options: Map<String, String>,
val javacOptions: Map<String, String>,
val annotationProcessors: String, val annotationProcessors: String,
val aptOnly: Boolean, val aptOnly: Boolean,
val pluginInitializedTime: Long, val pluginInitializedTime: Long,
@@ -204,7 +206,7 @@ abstract class AbstractKapt3Extension(
logger.info { "Stubs compilation took $classFilesCompilationTime ms" } logger.info { "Stubs compilation took $classFilesCompilationTime ms" }
logger.info { "Compiled classes: " + compiledClasses.joinToString { it.name } } logger.info { "Compiled classes: " + compiledClasses.joinToString { it.name } }
return Pair(KaptContext(logger, bindingContext, compiledClasses, origins, options), generationState) return Pair(KaptContext(logger, bindingContext, compiledClasses, origins, options, javacOptions), generationState)
} }
private fun generateKotlinSourceStubs(kaptContext: KaptContext, generationState: GenerationState) { private fun generateKotlinSourceStubs(kaptContext: KaptContext, generationState: GenerationState) {
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.container.ComponentProvider
import org.jetbrains.kotlin.context.ProjectContext import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.JAVAC_CLI_OPTIONS
import org.jetbrains.kotlin.kapt3.diagnostic.DefaultErrorMessagesKapt3 import org.jetbrains.kotlin.kapt3.diagnostic.DefaultErrorMessagesKapt3
import org.jetbrains.kotlin.kapt3.util.KaptLogger import org.jetbrains.kotlin.kapt3.util.KaptLogger
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
@@ -67,6 +68,9 @@ object Kapt3ConfigurationKeys {
val APT_OPTIONS: CompilerConfigurationKey<String> = val APT_OPTIONS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("annotation processing options") CompilerConfigurationKey.create<String>("annotation processing options")
val JAVAC_CLI_OPTIONS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("javac CLI options")
val ANNOTATION_PROCESSORS: CompilerConfigurationKey<String> = val ANNOTATION_PROCESSORS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("annotation processor qualified names") CompilerConfigurationKey.create<String>("annotation processor qualified names")
@@ -107,6 +111,10 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
CliOption("apoptions", "options map", "Encoded annotation processor options", CliOption("apoptions", "options map", "Encoded annotation processor options",
required = false, allowMultipleOccurrences = false) required = false, allowMultipleOccurrences = false)
val JAVAC_CLI_OPTIONS_OPTION: CliOption =
CliOption("javacArguments", "javac CLI options map", "Encoded javac CLI options",
required = false, allowMultipleOccurrences = false)
val ANNOTATION_PROCESSORS_OPTION: CliOption = val ANNOTATION_PROCESSORS_OPTION: CliOption =
CliOption("processors", "<fqname,[fqname2,...]>", "Annotation processor qualified names", CliOption("processors", "<fqname,[fqname2,...]>", "Annotation processor qualified names",
required = false, allowMultipleOccurrences = true) required = false, allowMultipleOccurrences = true)
@@ -127,7 +135,7 @@ class Kapt3CommandLineProcessor : 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(SOURCE_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION, APT_OPTIONS_OPTION, listOf(SOURCE_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION, APT_OPTIONS_OPTION, JAVAC_CLI_OPTIONS_OPTION,
CLASS_OUTPUT_DIR_OPTION, VERBOSE_MODE_OPTION, STUBS_OUTPUT_DIR_OPTION, APT_ONLY_OPTION, CLASS_OUTPUT_DIR_OPTION, VERBOSE_MODE_OPTION, STUBS_OUTPUT_DIR_OPTION, APT_ONLY_OPTION,
USE_LIGHT_ANALYSIS_OPTION, CORRECT_ERROR_TYPES_OPTION, ANNOTATION_PROCESSORS_OPTION) USE_LIGHT_ANALYSIS_OPTION, CORRECT_ERROR_TYPES_OPTION, ANNOTATION_PROCESSORS_OPTION)
@@ -136,6 +144,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
ANNOTATION_PROCESSOR_CLASSPATH_OPTION -> configuration.appendList(ANNOTATION_PROCESSOR_CLASSPATH, value) ANNOTATION_PROCESSOR_CLASSPATH_OPTION -> configuration.appendList(ANNOTATION_PROCESSOR_CLASSPATH, value)
ANNOTATION_PROCESSORS_OPTION -> configuration.put(Kapt3ConfigurationKeys.ANNOTATION_PROCESSORS, value) ANNOTATION_PROCESSORS_OPTION -> configuration.put(Kapt3ConfigurationKeys.ANNOTATION_PROCESSORS, value)
APT_OPTIONS_OPTION -> configuration.put(Kapt3ConfigurationKeys.APT_OPTIONS, value) APT_OPTIONS_OPTION -> configuration.put(Kapt3ConfigurationKeys.APT_OPTIONS, value)
JAVAC_CLI_OPTIONS_OPTION -> configuration.put(Kapt3ConfigurationKeys.JAVAC_CLI_OPTIONS, value)
SOURCE_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.SOURCE_OUTPUT_DIR, value) SOURCE_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.SOURCE_OUTPUT_DIR, value)
CLASS_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.CLASS_OUTPUT_DIR, value) CLASS_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.CLASS_OUTPUT_DIR, value)
STUBS_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.STUBS_OUTPUT_DIR, value) STUBS_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.STUBS_OUTPUT_DIR, value)
@@ -150,7 +159,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
} }
class Kapt3ComponentRegistrar : ComponentRegistrar { class Kapt3ComponentRegistrar : ComponentRegistrar {
fun decodeAnnotationProcessingOptions(options: String): Map<String, String> { fun decodeOptions(options: String): Map<String, String> {
val map = LinkedHashMap<String, String>() val map = LinkedHashMap<String, String>()
val decodedBytes = DatatypeConverter.parseBase64Binary(options) val decodedBytes = DatatypeConverter.parseBase64Binary(options)
@@ -199,7 +208,8 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
return return
} }
val apOptions = configuration.get(APT_OPTIONS)?.let { decodeAnnotationProcessingOptions(it) } ?: emptyMap() val apOptions = configuration.get(APT_OPTIONS)?.let { decodeOptions(it) } ?: emptyMap()
val javacCliOptions = configuration.get(JAVAC_CLI_OPTIONS)?.let { decodeOptions(it) } ?: emptyMap()
sourcesOutputDir.mkdirs() sourcesOutputDir.mkdirs()
@@ -232,7 +242,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
val kapt3AnalysisCompletedHandlerExtension = ClasspathBasedKapt3Extension( val kapt3AnalysisCompletedHandlerExtension = ClasspathBasedKapt3Extension(
compileClasspath, apClasspath, javaSourceRoots, sourcesOutputDir, classFilesOutputDir, compileClasspath, apClasspath, javaSourceRoots, sourcesOutputDir, classFilesOutputDir,
stubsOutputDir, incrementalDataOutputDir, apOptions, annotationProcessors, stubsOutputDir, incrementalDataOutputDir, apOptions, javacCliOptions, annotationProcessors,
isAptOnly, useLightAnalysis, correctErrorTypes, System.currentTimeMillis(), logger) isAptOnly, useLightAnalysis, correctErrorTypes, System.currentTimeMillis(), logger)
AnalysisHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension) AnalysisHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension)
} }
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
import org.jetbrains.kotlin.kapt3.util.KaptLogger import org.jetbrains.kotlin.kapt3.util.KaptLogger
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.utils.keysToMap
import org.jetbrains.org.objectweb.asm.tree.ClassNode import org.jetbrains.org.objectweb.asm.tree.ClassNode
import javax.tools.JavaFileManager import javax.tools.JavaFileManager
@@ -35,7 +36,8 @@ class KaptContext(
val bindingContext: BindingContext, val bindingContext: BindingContext,
val compiledClasses: List<ClassNode>, val compiledClasses: List<ClassNode>,
val origins: Map<Any, JvmDeclarationOrigin>, val origins: Map<Any, JvmDeclarationOrigin>,
processorOptions: Map<String, String> processorOptions: Map<String, String>,
javacOptions: Map<String, String> = emptyMap()
) : AutoCloseable { ) : AutoCloseable {
val context = Context() val context = Context()
val compiler: KaptJavaCompiler val compiler: KaptJavaCompiler
@@ -61,6 +63,18 @@ class KaptContext(
val option = if (value.isEmpty()) "-A$key" else "-A$key=$value" val option = if (value.isEmpty()) "-A$key" else "-A$key=$value"
options.put(option, option) // key == value: it's intentional options.put(option, option) // key == value: it's intentional
} }
for ((key, value) in javacOptions) {
if (value.isNotEmpty()) {
options.put(key, value)
} else {
options.put(key, key)
}
}
if (logger.isVerbose) {
logger.info("Javac options: " + options.keySet().keysToMap { key -> options[key] ?: "" })
}
} }
override fun close() { override fun close() {
@@ -53,7 +53,6 @@ import com.sun.tools.javac.util.List as JavacList
abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() { abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
private companion object { private companion object {
val TEST_DATA_DIR = File("plugins/kapt3/testData/kotlinRunner") val TEST_DATA_DIR = File("plugins/kapt3/testData/kotlinRunner")
val messageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false)
} }
private lateinit var processors: List<Processor> private lateinit var processors: List<Processor>
@@ -66,12 +65,6 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
process: (Set<TypeElement>, RoundEnvironment, ProcessingEnvironment) -> Unit process: (Set<TypeElement>, RoundEnvironment, ProcessingEnvironment) -> Unit
) = testAP(true, name, options, process, *supportedAnnotations) ) = testAP(true, name, options, process, *supportedAnnotations)
protected fun testShouldNotRun(
name: String,
vararg supportedAnnotations: String,
options: Map<String, String> = emptyMap()
) = testAP(false, name, options, { _, _, _ -> fail("Should not run") }, *supportedAnnotations)
protected fun testAP( protected fun testAP(
shouldRun: Boolean, shouldRun: Boolean,
name: String, name: String,
@@ -162,7 +155,7 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
incrementalDataOutputDir: File incrementalDataOutputDir: File
) : AbstractKapt3Extension(PathUtil.getJdkClassesRoots() + PathUtil.getKotlinPathsForIdeaPlugin().stdlibPath, ) : AbstractKapt3Extension(PathUtil.getJdkClassesRoots() + PathUtil.getKotlinPathsForIdeaPlugin().stdlibPath,
emptyList(), javaSourceRoots, outputDir, outputDir, emptyList(), javaSourceRoots, outputDir, outputDir,
stubsOutputDir, incrementalDataOutputDir, options, "", true, System.currentTimeMillis(), stubsOutputDir, incrementalDataOutputDir, options, emptyMap(), "", true, System.currentTimeMillis(),
KaptLogger(true), correctErrorTypes = true KaptLogger(true), correctErrorTypes = true
) { ) {
internal var savedStubs: String? = null internal var savedStubs: String? = null