diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt index 29445dc75a1..30b986d605d 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt @@ -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") diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/arguments/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/arguments/build.gradle index a0b3a029c58..81d67cb1441 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/arguments/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/arguments/build.gradle @@ -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") + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt index 1bf3e9b427a..0da66bbed45 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt @@ -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 { 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 { + fun encodeOptions(options: Map): String { val os = ByteArrayOutputStream() val oos = ObjectOutputStream(os) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KaptExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KaptExtension.kt index f49e14fa931..49964a227aa 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KaptExtension.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KaptExtension.kt @@ -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 { + val closureToExecute = javacOptionsClosure ?: return emptyMap() + val executor = KaptJavacOptionsDelegate().apply { execute(closureToExecute) } + return executor.options } fun getAdditionalArguments(project: Project, variantData: Any?, androidExtension: Any?): Map { - 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 { @@ -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() + internal val options = LinkedHashMap() @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() + + 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() + } } \ No newline at end of file diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt index 27efa8d955d..c7f18707e09 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt @@ -51,6 +51,7 @@ class ClasspathBasedKapt3Extension( stubsOutputDir: File, incrementalDataOutputDir: File?, options: Map, + javacOptions: Map, 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, + val javacOptions: Map, 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) { diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt index daacd1e2bb0..724215a5f7a 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt @@ -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 = CompilerConfigurationKey.create("annotation processing options") + val JAVAC_CLI_OPTIONS: CompilerConfigurationKey = + CompilerConfigurationKey.create("javac CLI options") + val ANNOTATION_PROCESSORS: CompilerConfigurationKey = CompilerConfigurationKey.create("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", "", "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 = - 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 { + fun decodeOptions(options: String): Map { val map = LinkedHashMap() 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) } diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptContext.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptContext.kt index 470cb7eb6b1..9c757fb5de6 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptContext.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptContext.kt @@ -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, val origins: Map, - processorOptions: Map + processorOptions: Map, + javacOptions: Map = 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() { diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt index 817d3f577c0..f1cc41cdebf 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt @@ -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 @@ -66,12 +65,6 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() { process: (Set, RoundEnvironment, ProcessingEnvironment) -> Unit ) = testAP(true, name, options, process, *supportedAnnotations) - protected fun testShouldNotRun( - name: String, - vararg supportedAnnotations: String, - options: Map = 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