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()
assertContains("Options: {suffix=Customized, justColon=:, justEquals==, containsColon=a:b, " +
"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/classes/main/example/TestClass.class")
assertFileExists("build/classes/main/example/TestClassCustomized.class")
@@ -33,4 +33,9 @@ kapt {
arg("endsWithEquals", "a:")
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.android.AndroidGradleWrapper
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.preprocessor.mkdirsOrFail
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.ObjectOutputStream
@@ -193,14 +192,16 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
androidOptions +
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)
return pluginOptions
}
fun encodeAnnotationProcessingOptions(options: Map<String, String>): String {
fun encodeOptions(options: Map<String, String>): String {
val os = ByteArrayOutputStream()
val oos = ObjectOutputStream(os)
@@ -32,18 +32,29 @@ open class KaptExtension {
open var processors: String = ""
private var closure: Closure<*>? = null
private var apOptionsClosure: Closure<*>? = null
private var javacOptionsClosure: Closure<*>? = null
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> {
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)
return executor.args
return executor.options
}
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.
*/
open class KaptAdditionalArgumentsDelegate(
open class KaptAnnotationProcessorOptions(
@Suppress("unused") open val project: Project,
@Suppress("unused") open val variant: Any?,
@Suppress("unused") open val android: Any?
) {
internal val args = LinkedHashMap<String, String>()
internal val options = LinkedHashMap<String, String>()
@Suppress("unused")
open fun arg(name: Any, vararg values: Any) {
args.put(name.toString(), values.joinToString(" "))
options.put(name.toString(), values.joinToString(" "))
}
fun execute(closure: Closure<*>) {
@@ -76,4 +87,22 @@ open class KaptAdditionalArgumentsDelegate(
closure.call()
}
}
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,
incrementalDataOutputDir: File?,
options: Map<String, String>,
javacOptions: Map<String, String>,
annotationProcessors: String,
aptOnly: Boolean,
val useLightAnalysis: Boolean,
@@ -58,7 +59,7 @@ class ClasspathBasedKapt3Extension(
pluginInitializedTime: Long,
logger: KaptLogger
) : AbstractKapt3Extension(compileClasspath, annotationProcessingClasspath, javaSourceRoots, sourcesOutputDir,
classFilesOutputDir, stubsOutputDir, incrementalDataOutputDir, options, annotationProcessors,
classFilesOutputDir, stubsOutputDir, incrementalDataOutputDir, options, javacOptions, annotationProcessors,
aptOnly, pluginInitializedTime, logger, correctErrorTypes) {
override val analyzePartially: Boolean
get() = useLightAnalysis
@@ -103,6 +104,7 @@ abstract class AbstractKapt3Extension(
val stubsOutputDir: File,
val incrementalDataOutputDir: File?,
val options: Map<String, String>,
val javacOptions: Map<String, String>,
val annotationProcessors: String,
val aptOnly: Boolean,
val pluginInitializedTime: Long,
@@ -204,7 +206,7 @@ abstract class AbstractKapt3Extension(
logger.info { "Stubs compilation took $classFilesCompilationTime ms" }
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) {
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.container.ComponentProvider
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
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.util.KaptLogger
import org.jetbrains.kotlin.psi.KtFile
@@ -67,6 +68,9 @@ object Kapt3ConfigurationKeys {
val APT_OPTIONS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("annotation processing options")
val JAVAC_CLI_OPTIONS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("javac CLI options")
val ANNOTATION_PROCESSORS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("annotation processor qualified names")
@@ -107,6 +111,10 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
CliOption("apoptions", "options map", "Encoded annotation processor options",
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 =
CliOption("processors", "<fqname,[fqname2,...]>", "Annotation processor qualified names",
required = false, allowMultipleOccurrences = true)
@@ -127,7 +135,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
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,
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_PROCESSORS_OPTION -> configuration.put(Kapt3ConfigurationKeys.ANNOTATION_PROCESSORS, 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)
CLASS_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.CLASS_OUTPUT_DIR, value)
STUBS_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.STUBS_OUTPUT_DIR, value)
@@ -150,7 +159,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
}
class Kapt3ComponentRegistrar : ComponentRegistrar {
fun decodeAnnotationProcessingOptions(options: String): Map<String, String> {
fun decodeOptions(options: String): Map<String, String> {
val map = LinkedHashMap<String, String>()
val decodedBytes = DatatypeConverter.parseBase64Binary(options)
@@ -199,7 +208,8 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
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()
@@ -232,7 +242,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
val kapt3AnalysisCompletedHandlerExtension = ClasspathBasedKapt3Extension(
compileClasspath, apClasspath, javaSourceRoots, sourcesOutputDir, classFilesOutputDir,
stubsOutputDir, incrementalDataOutputDir, apOptions, annotationProcessors,
stubsOutputDir, incrementalDataOutputDir, apOptions, javacCliOptions, annotationProcessors,
isAptOnly, useLightAnalysis, correctErrorTypes, System.currentTimeMillis(), logger)
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.resolve.BindingContext
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.utils.keysToMap
import org.jetbrains.org.objectweb.asm.tree.ClassNode
import javax.tools.JavaFileManager
@@ -35,7 +36,8 @@ class KaptContext(
val bindingContext: BindingContext,
val compiledClasses: List<ClassNode>,
val origins: Map<Any, JvmDeclarationOrigin>,
processorOptions: Map<String, String>
processorOptions: Map<String, String>,
javacOptions: Map<String, String> = emptyMap()
) : AutoCloseable {
val context = Context()
val compiler: KaptJavaCompiler
@@ -61,6 +63,18 @@ class KaptContext(
val option = if (value.isEmpty()) "-A$key" else "-A$key=$value"
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() {
@@ -53,7 +53,6 @@ import com.sun.tools.javac.util.List as JavacList
abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
private companion object {
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>
@@ -66,12 +65,6 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
process: (Set<TypeElement>, RoundEnvironment, ProcessingEnvironment) -> Unit
) = 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(
shouldRun: Boolean,
name: String,
@@ -162,7 +155,7 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
incrementalDataOutputDir: File
) : AbstractKapt3Extension(PathUtil.getJdkClassesRoots() + PathUtil.getKotlinPathsForIdeaPlugin().stdlibPath,
emptyList(), javaSourceRoots, outputDir, outputDir,
stubsOutputDir, incrementalDataOutputDir, options, "", true, System.currentTimeMillis(),
stubsOutputDir, incrementalDataOutputDir, options, emptyMap(), "", true, System.currentTimeMillis(),
KaptLogger(true), correctErrorTypes = true
) {
internal var savedStubs: String? = null