Kapt: Implement 'kapt' command-line tool (KT-24998, KT-24997)

This commit is contained in:
Yan Zhulanow
2018-10-22 21:25:59 +03:00
parent 2e56feed73
commit 6e5eb0fdd4
15 changed files with 560 additions and 61 deletions
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
# Copyright 2010-2015 JetBrains s.r.o.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
export KOTLIN_TOOL=kotlin-annotation-processing-cli.jar
export KOTLIN_COMPILER=org.jetbrains.kotlin.kapt.cli.KaptCli
DIR="${BASH_SOURCE[0]%/*}"
: ${DIR:="."}
"${DIR}"/kotlinc "$@"
+21
View File
@@ -0,0 +1,21 @@
@echo off
rem Copyright 2010-2015 JetBrains s.r.o.
rem
rem Licensed under the Apache License, Version 2.0 (the "License");
rem you may not use this file except in compliance with the License.
rem You may obtain a copy of the License at
rem
rem http://www.apache.org/licenses/LICENSE-2.0
rem
rem Unless required by applicable law or agreed to in writing, software
rem distributed under the License is distributed on an "AS IS" BASIS,
rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rem See the License for the specific language governing permissions and
rem limitations under the License.
setlocal
set _KOTLIN_COMPILER=org.jetbrains.kotlin.kapt.cli.KaptCli
set _KOTLIN_TOOL=kotlin-annotation-processing-cli.jar
call %~dps0kotlinc.bat %*
+7 -1
View File
@@ -68,7 +68,13 @@ else
[ -n "$KOTLIN_COMPILER" ] || KOTLIN_COMPILER=org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
java_args=("${java_args[@]}" "-noverify")
kotlin_app=("${KOTLIN_HOME}/lib/kotlin-preloader.jar" "org.jetbrains.kotlin.preloading.Preloader" "-cp" "${KOTLIN_HOME}/lib/kotlin-compiler.jar" $KOTLIN_COMPILER)
declare additional_classpath=""
if [ -n "$KOTLIN_TOOL" ];
then
additional_classpath=":${KOTLIN_HOME}/lib/${KOTLIN_TOOL}"
fi
kotlin_app=("${KOTLIN_HOME}/lib/kotlin-preloader.jar" "org.jetbrains.kotlin.preloading.Preloader" "-cp" "${KOTLIN_HOME}/lib/kotlin-compiler.jar${additional_classpath}" $KOTLIN_COMPILER)
fi
"${JAVACMD:=java}" $JAVA_OPTS "${java_args[@]}" -cp "${kotlin_app[@]}" "${kotlin_args[@]}"
+7 -1
View File
@@ -31,8 +31,14 @@ if not "%_KOTLIN_RUNNER%"=="" (
"%_JAVACMD%" %JAVA_OPTS% "-Dkotlin.home=%_KOTLIN_HOME%" -cp "%_KOTLIN_HOME%\lib\kotlin-runner.jar" ^
org.jetbrains.kotlin.runner.Main %*
) else (
SET _ADDITIONAL_CLASSPATH=""
if not "%_KOTLIN_TOOL%"=="" (
set _ADDITIONAL_CLASSPATH=;%_KOTLIN_HOME%\lib\%_KOTLIN_TOOL%
)
"%_JAVACMD%" %JAVA_OPTS% -noverify -cp "%_KOTLIN_HOME%\lib\kotlin-preloader.jar" ^
org.jetbrains.kotlin.preloading.Preloader -cp "%_KOTLIN_HOME%\lib\kotlin-compiler.jar" ^
org.jetbrains.kotlin.preloading.Preloader -cp "%_KOTLIN_HOME%\lib\kotlin-compiler.jar%_ADDITIONAL_CLASSPATH%" ^
%_KOTLIN_COMPILER% %*
)
@@ -22,7 +22,7 @@ private const val BACKSLASH = '\\'
* This is done prior to *any* arguments parsing, and result of preprocessing
* will be used instead of actual passed arguments.
*/
internal fun preprocessCommandLineArguments(args: List<String>, errors: ArgumentParseErrors): List<String> =
fun preprocessCommandLineArguments(args: List<String>, errors: ArgumentParseErrors): List<String> =
args.flatMap { arg ->
if (arg.isArgfileArgument) {
File(arg.argfilePath).expand(errors)
@@ -24,6 +24,9 @@ interface AbstractCliOption {
val description: String
val required: Boolean
val allowMultipleOccurrences: Boolean
val deprecatedName: String?
get() = null
}
class CliOption(
@@ -7,6 +7,7 @@
<properties>
<maven.version>3.0.4</maven.version>
<annotation-processing.src>${basedir}/../../../plugins/kapt3/kapt3-compiler/src</annotation-processing.src>
<annotation-processing.cli.src>${basedir}/../../../plugins/kapt3/kapt3-cli/src</annotation-processing.cli.src>
<annotation-processing.base.src>${basedir}/../../../plugins/kapt3/kapt3-base/src</annotation-processing.base.src>
<annotation-processing.runtime.src>${basedir}/../../../plugins/kapt3/kapt3-runtime/src</annotation-processing.runtime.src>
<annotation-processing.target-src>${basedir}/target/src/main/kotlin</annotation-processing.target-src>
@@ -70,6 +71,7 @@
<outputDirectory>${annotation-processing.target-src}</outputDirectory>
<resources>
<resource><directory>${annotation-processing.src}</directory></resource>
<resource><directory>${annotation-processing.cli.src}</directory></resource>
<resource><directory>${annotation-processing.base.src}</directory></resource>
<resource><directory>${annotation-processing.runtime.src}</directory></resource>
</resources>
+22
View File
@@ -0,0 +1,22 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compile(project(":compiler:cli"))
}
sourceSets {
"main" { projectDefault() }
"test" { }
}
testsJar {}
dist()
projectTest {
workingDir = rootDir
dependsOn(":dist")
}
+178
View File
@@ -0,0 +1,178 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@file:JvmName("KaptCli")
package org.jetbrains.kotlin.kapt.cli
import com.intellij.util.PathUtil
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.arguments.ArgumentParseErrors
import org.jetbrains.kotlin.cli.common.arguments.preprocessCommandLineArguments
import org.jetbrains.kotlin.cli.common.arguments.validateArguments
import org.jetbrains.kotlin.cli.common.messages.*
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.cli.jvm.modules.isAtLeastJava9
import org.jetbrains.kotlin.kapt.cli.CliToolOption.Format.*
import java.io.File
fun main(args: Array<String>) {
val messageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_RELATIVE_PATHS, false)
if (args.isEmpty() || args.contains("-help")) {
printHelp()
return
}
val kaptTransformed = transformArgs(args.asList(), messageCollector, false)
if (messageCollector.hasErrors()) {
System.exit(ExitCode.COMPILATION_ERROR.code)
return
}
K2JVMCompiler.main(kaptTransformed.toTypedArray())
}
@TestOnly
internal fun transformArgs(args: List<String>, messageCollector: MessageCollector, isTest: Boolean): List<String> {
val parseErrors = ArgumentParseErrors()
val kotlincTransformed = preprocessCommandLineArguments(args, parseErrors)
val errorMessage = validateArguments(parseErrors)
if (errorMessage != null) {
messageCollector.report(CompilerMessageSeverity.ERROR, errorMessage)
return emptyList()
}
return try {
transformKaptToolArgs(kotlincTransformed, messageCollector, isTest)
} catch (e: IllegalArgumentException) {
messageCollector.report(CompilerMessageSeverity.ERROR, e.localizedMessage)
emptyList()
}
}
private const val KAPT_COMPILER_PLUGIN_JAR_NAME = "kotlin-annotation-processing.jar"
private fun transformKaptToolArgs(args: List<String>, messageCollector: MessageCollector, isTest: Boolean): List<String> {
val transformed = mutableListOf<String>()
if (!isTest) {
val kaptCompilerPluginFile = findKaptCompilerPlugin()
?: throw IllegalStateException("Can't find $KAPT_COMPILER_PLUGIN_JAR_NAME")
transformed += "-Xplugin=${kaptCompilerPluginFile.absolutePath}"
}
var toolsJarPassed = false
var aptModePassed = false
var kaptVerboseModePassed = false
data class Option(val cliToolOption: CliToolOption, val pluginOption: KaptCliOption)
val cliOptions = KaptCliOption.values().mapNotNull { Option(it.cliToolOption ?: return@mapNotNull null, it) }
val iterator = args.asIterable().iterator()
loop@ while (iterator.hasNext()) {
val arg = iterator.next()
if (arg == "--") {
transformed += arg
iterator.forEach { transformed += it }
break
}
if (arg == "-help") {
throw IllegalStateException("-help option should be already processed")
}
val option = cliOptions.firstOrNull { it.cliToolOption.matches(arg) }
if (option == null) {
transformed += arg
continue
}
val transformedOption = option.cliToolOption.transform(arg)
when (option.pluginOption) {
KaptCliOption.TOOLS_JAR_OPTION -> {
// TOOLS_JAR option is not passed as other compiler plugin options.
// It is only used in kapt-cli, and we add a -Xplugin compiler option instead.
toolsJarPassed = true
transformed.add(0, "-Xplugin=$transformedOption")
continue@loop
}
KaptCliOption.APT_MODE_OPTION -> aptModePassed = true
KaptCliOption.VERBOSE_MODE_OPTION -> kaptVerboseModePassed = true
else -> {}
}
transformed += kaptArg(option.pluginOption, transformedOption)
}
if (!aptModePassed) {
transformed.addAll(0, kaptArg(KaptCliOption.APT_MODE_OPTION, "compile"))
}
if (!isTest && !isAtLeastJava9() && !areJavacComponentsAvailable() && !toolsJarPassed) {
val toolsJarFile = findToolsJar()
?: argError("'tools.jar' location should be specified (${KaptCliOption.TOOLS_JAR_OPTION.cliToolOption!!.name}=<path>)")
transformed.add(0, "-Xplugin=" + toolsJarFile.absolutePath)
}
if (kaptVerboseModePassed) {
messageCollector.report(CompilerMessageSeverity.INFO, "Options passed to kotlinc: " + transformed.joinToString(" "))
}
return transformed
}
private fun CliToolOption.matches(arg: String) = when (format) {
FLAG, VALUE -> arg.startsWith(name + "=")
KEY_VALUE -> arg.startsWith(name + ":")
}
private fun CliToolOption.transform(arg: String): String {
val optionName = name
return when (format) {
FLAG -> {
fun err(): Nothing = argError("Invalid option format, should be $optionName=true/false")
if (arg.length < (optionName.length + 2)) err()
arg.drop(optionName.length + 1).takeIf { it == "true" || it == "false" } ?: err()
}
VALUE -> {
fun err(): Nothing = argError("Invalid option format, should be $optionName=<value>")
if (arg.length < (optionName.length + 2)) err()
arg.drop(optionName.length + 1)
}
KEY_VALUE -> {
fun err(): Nothing = argError("Invalid option format, should be $optionName:<key>=<value>")
if (arg.length < (optionName.length + 3) || arg[optionName.length] != ':') err()
arg.drop(optionName.length + 1).takeIf { it.contains('=') } ?: err()
}
}
}
private fun kaptArg(option: KaptCliOption, value: String): List<String> {
return listOf("-P", "plugin:" + KaptCliOption.ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID + ":" + option.optionName + "=" + value)
}
private fun argError(text: String): Nothing {
throw IllegalArgumentException(text)
}
private fun findKaptCompilerPlugin(): File? {
val pathToThisJar = File(PathUtil.getJarPathForClass(CliToolOption::class.java))
if (pathToThisJar.extension.toLowerCase() != "jar") {
return null
}
return File(pathToThisJar.parentFile, KAPT_COMPILER_PLUGIN_JAR_NAME).takeIf { it.exists() }
}
@@ -0,0 +1,160 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.kapt.cli
import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption
import org.jetbrains.kotlin.kapt.cli.CliToolOption.Format.*
class CliToolOption(val name: String, val format: Format) {
enum class Format {
/**
* A boolean flag.
* Example: '-option=true'
* */
FLAG,
/**
* An option with value.
* Example: '-option=some/path'
*/
VALUE,
/**
* A key-value pair option.
* Example: '-option:key=value'
*/
KEY_VALUE
}
}
enum class KaptCliOption(
override val optionName: String,
override val valueDescription: String,
override val description: String,
override val allowMultipleOccurrences: Boolean = false,
val cliToolOption: CliToolOption? = null
) : AbstractCliOption {
APT_MODE_OPTION(
"aptMode", "<apt|stubs|stubsAndApt|compile>",
"Annotation processing mode: only apt, only stub generation, both, or with the subsequent compilation",
cliToolOption = CliToolOption("-Kapt-mode", VALUE)
),
@Deprecated("Do not use in CLI")
CONFIGURATION("configuration", "<encoded>", "Encoded configuration"),
SOURCE_OUTPUT_DIR_OPTION(
"sources",
"<path>",
"Output path for generated sources",
cliToolOption = CliToolOption("-Kapt-sources", VALUE)
),
CLASS_OUTPUT_DIR_OPTION(
"classes",
"<path>",
"Output path for generated classes",
cliToolOption = CliToolOption("-Kapt-classes", VALUE)
),
STUBS_OUTPUT_DIR_OPTION(
"stubs",
"<path>",
"Output path for Java stubs",
cliToolOption = CliToolOption("-Kapt-stubs", VALUE)
),
INCREMENTAL_DATA_OUTPUT_DIR_OPTION("incrementalData", "<path>", "Output path for incremental data"),
ANNOTATION_PROCESSOR_CLASSPATH_OPTION(
"apclasspath",
"<classpath>",
"Annotation processor classpath",
true,
cliToolOption = CliToolOption("-Kapt-classpath", VALUE)
),
ANNOTATION_PROCESSORS_OPTION(
"processors",
"<fqname,[fqname2,...]>",
"Annotation processor qualified names",
true,
cliToolOption = CliToolOption("-Kapt-processors", VALUE)
),
APT_OPTION_OPTION(
"apOption",
":<key>=<value>",
"Annotation processor options",
cliToolOption = CliToolOption("-Kapt-option", KEY_VALUE)
),
JAVAC_OPTION_OPTION(
"javacOption",
":<key>=<value>",
"Javac options",
cliToolOption = CliToolOption("-Kapt-javac-option", KEY_VALUE)
),
TOOLS_JAR_OPTION(
"toolsJarLocation",
"<path>",
"tools.jar file location (for JDK versions up to 1.8)",
cliToolOption = CliToolOption("-Kapt-tools-jar-location", VALUE)
),
USE_LIGHT_ANALYSIS_OPTION(
"useLightAnalysis",
"true | false",
"Skip body analysis if possible",
cliToolOption = CliToolOption("-Kapt-use-light-analysis", FLAG)
),
CORRECT_ERROR_TYPES_OPTION(
"correctErrorTypes",
"true | false",
"Replace generated or error types with ones from the generated sources",
cliToolOption = CliToolOption("-Kapt-correct-error-types", FLAG)
),
MAP_DIAGNOSTIC_LOCATIONS_OPTION(
"mapDiagnosticLocations",
"true | false",
"Map diagnostic reported on kapt stubs to original locations in Kotlin sources",
cliToolOption = CliToolOption("-Kapt-map-diagnostic-locations", FLAG)
),
VERBOSE_MODE_OPTION(
"verbose",
"true | false",
"Enable verbose output",
cliToolOption = CliToolOption("-Kapt-verbose", FLAG)
),
STRICT_MODE_OPTION(
"strict",
"true | false",
"Show errors on incompatibilities during stub generation",
cliToolOption = CliToolOption("-Kapt-strict", FLAG)
),
INFO_AS_WARNINGS_OPTION("infoAsWarnings", "true | false", "Show information messages as warnings"),
@Deprecated("Do not use in CLI")
APT_OPTIONS_OPTION("apoptions", "options map", "Encoded annotation processor options", false),
@Deprecated("Do not use in CLI")
JAVAC_CLI_OPTIONS_OPTION("javacArguments", "javac CLI options map", "Encoded javac CLI options", false),
@Deprecated("Use APT_MODE_OPTION instead.")
APT_ONLY_OPTION("aptOnly", "true | false", "Run only annotation processing, do not compile Kotlin files");
override val required: Boolean = false
companion object {
const val ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.kapt3"
}
}
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.kapt.cli
import org.jetbrains.kotlin.kapt.cli.CliToolOption.Format.*
internal fun printHelp() {
class OptionToRender(nameArgs: String, val description: String) {
val nameArgs = nameArgs.trim()
fun render(width: Int) = " " + nameArgs + " ".repeat(width - nameArgs.length) + description
}
val options = KaptCliOption.values()
.filter { it.cliToolOption != null }
.map { OptionToRender(it.nameArgs(), it.description) }
val optionNameColumnWidth = options.asSequence().map { it.nameArgs.length }.max()!! + 2
val renderedOptions = options.joinToString("\n|") { it.render(optionNameColumnWidth) }
val message = """
|kapt: Run annotation processing over the specified Kotlin source files.
|Usage: kapt <options> <source files>
|Options related to annotation processing:
|$renderedOptions
|You can also pass all valid Kotlin compiler options.
|Run 'kotlinc -help' to show them.
""".trimMargin()
println(message)
}
private fun KaptCliOption.nameArgs(): String {
val cliToolOption = this.cliToolOption!!
return when (cliToolOption.format) {
FLAG -> cliToolOption.name + "=<true|false>"
VALUE -> cliToolOption.name + "=" + valueDescription
KEY_VALUE -> cliToolOption.name + valueDescription
}
}
+37
View File
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.kapt.cli
import java.io.File
internal const val JAVAC_CONTEXT_CLASS = "com.sun.tools.javac.util.Context"
internal fun areJavacComponentsAvailable(): Boolean {
return try {
Class.forName(JAVAC_CONTEXT_CLASS)
true
} catch (e: ClassNotFoundException) {
false
}
}
internal fun findToolsJar(): File? {
val currentJavaHome = System.getProperty("java.home")
?.takeIf { it.isNotEmpty() }
?.let(::File)
?.takeIf { it.exists() }
?: return null
fun getToolsJar(javaHome: File) = File(javaHome, "lib/tools.jar").takeIf { it.exists() }
getToolsJar(currentJavaHome)?.let { return it}
if (currentJavaHome.name == "jre") {
getToolsJar(currentJavaHome.parentFile)?.let { return it}
}
return null
}
@@ -21,6 +21,7 @@ dependencies {
compile(project(":compiler:frontend"))
compile(project(":compiler:frontend.java"))
compile(project(":compiler:plugin-api"))
compileOnly(project(":kotlin-annotation-processing-cli"))
compileOnly(project(":kotlin-annotation-processing-base"))
compileOnly(project(":kotlin-annotation-processing-runtime"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
@@ -33,6 +34,7 @@ dependencies {
testCompile(project(":kotlin-annotation-processing-runtime"))
embeddedComponents(project(":kotlin-annotation-processing-runtime")) { isTransitive = false }
embeddedComponents(project(":kotlin-annotation-processing-cli")) { isTransitive = false }
embeddedComponents(project(":kotlin-annotation-processing-base")) { isTransitive = false }
}
@@ -35,11 +35,14 @@ import org.jetbrains.kotlin.container.useInstance
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.kapt3.KaptCliOptions.*
import org.jetbrains.kotlin.kapt.cli.KaptCliOption
import org.jetbrains.kotlin.kapt.cli.KaptCliOption.Companion.ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
import org.jetbrains.kotlin.kapt.cli.KaptCliOption.*
import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH
import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.APT_OPTION
import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.APT_OPTIONS
import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.JAVAC_CLI_OPTIONS
import org.jetbrains.kotlin.kapt3.KaptCliOptions.Companion.ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.JAVAC_OPTION
import org.jetbrains.kotlin.kapt3.base.Kapt
import org.jetbrains.kotlin.kapt3.base.KaptPaths
import org.jetbrains.kotlin.kapt3.base.log
@@ -71,12 +74,20 @@ object Kapt3ConfigurationKeys {
val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> =
CompilerConfigurationKey.create<List<String>>(ANNOTATION_PROCESSOR_CLASSPATH_OPTION.description)
@Deprecated("Use APT_OPTION instead.")
val APT_OPTIONS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(APT_OPTIONS_OPTION.description)
val APT_OPTION: CompilerConfigurationKey<Map<String, String>> =
CompilerConfigurationKey.create<Map<String, String>>(APT_OPTION_OPTION.description)
@Deprecated("Use JAVAC_OPTION instead.")
val JAVAC_CLI_OPTIONS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(JAVAC_CLI_OPTIONS_OPTION.description)
val JAVAC_OPTION: CompilerConfigurationKey<Map<String, String>> =
CompilerConfigurationKey.create<Map<String, String>>(JAVAC_OPTION_OPTION.description)
val ANNOTATION_PROCESSORS: CompilerConfigurationKey<List<String>> =
CompilerConfigurationKey.create<List<String>>(ANNOTATION_PROCESSORS_OPTION.description)
@@ -106,61 +117,13 @@ object Kapt3ConfigurationKeys {
CompilerConfigurationKey.create<String>(STRICT_MODE_OPTION.description)
}
enum class KaptCliOptions(
override val optionName: String,
override val valueDescription: String,
override val description: String,
override val allowMultipleOccurrences: Boolean = false
) : AbstractCliOption {
CONFIGURATION("configuration", "<encoded>", "Encoded configuration"),
SOURCE_OUTPUT_DIR_OPTION("sources", "<path>", "Output path for the generated files"),
CLASS_OUTPUT_DIR_OPTION("classes", "<path>", "Output path for the class files"),
STUBS_OUTPUT_DIR_OPTION("stubs", "<path>", "Output path for the Java stubs"),
INCREMENTAL_DATA_OUTPUT_DIR_OPTION("incrementalData", "<path>", "Output path for the incremental data"),
ANNOTATION_PROCESSOR_CLASSPATH_OPTION("apclasspath", "<classpath>", "Annotation processor classpath", true),
APT_OPTIONS_OPTION("apoptions", "options map", "Encoded annotation processor options", false),
JAVAC_CLI_OPTIONS_OPTION("javacArguments", "javac CLI options map", "Encoded javac CLI options", false),
ANNOTATION_PROCESSORS_OPTION("processors", "<fqname,[fqname2,...]>", "Annotation processor qualified names", true),
VERBOSE_MODE_OPTION("verbose", "true | false", "Enable verbose output"),
INFO_AS_WARNINGS_OPTION("infoAsWarnings", "true | false", "Show information messages as warnings"),
STRICT_MODE_OPTION("strict", "true | false", "Show errors on incompatibilities during stub generation"),
APT_MODE_OPTION(
"aptMode", "apt | stubs | stubsAndApt | compile",
"Annotation processing mode: only apt, only stub generation, both, or with the subsequent compilation"
),
USE_LIGHT_ANALYSIS_OPTION(
"useLightAnalysis",
"true | false",
"Do not analyze declaration bodies if can"
),
CORRECT_ERROR_TYPES_OPTION(
"correctErrorTypes",
"true | false",
"Replace generated or error types with ones from the generated sources"
),
MAP_DIAGNOSTIC_LOCATIONS_OPTION(
"mapDiagnosticLocations",
"true | false",
"Map diagnostic reported on kapt stubs to original locations in Kotlin sources"
),
@Deprecated("Use APT_MODE_OPTION instead.")
APT_ONLY_OPTION("aptOnly", "true | false", "Run only annotation processing, do not compile Kotlin files");
override val required: Boolean = false
companion object {
const val ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.kapt3"
}
}
class Kapt3CommandLineProcessor : CommandLineProcessor {
override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
override val pluginOptions: Collection<AbstractCliOption> = KaptCliOptions.values().asList()
override val pluginOptions: Collection<AbstractCliOption> = values().asList()
override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) {
if (option !is KaptCliOptions) {
if (option !is KaptCliOption) {
throw CliOptionProcessingException("Unknown option: ${option.optionName}")
}
@@ -168,8 +131,10 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
ANNOTATION_PROCESSOR_CLASSPATH_OPTION -> configuration.appendList(ANNOTATION_PROCESSOR_CLASSPATH, value)
ANNOTATION_PROCESSORS_OPTION -> configuration.appendList(
Kapt3ConfigurationKeys.ANNOTATION_PROCESSORS, value.split(',').map { it.trim() }.filter { it.isNotEmpty() })
APT_OPTIONS_OPTION -> configuration.put(Kapt3ConfigurationKeys.APT_OPTIONS, value)
JAVAC_CLI_OPTIONS_OPTION -> configuration.put(Kapt3ConfigurationKeys.JAVAC_CLI_OPTIONS, value)
APT_OPTIONS_OPTION -> configuration.put(APT_OPTIONS, value)
JAVAC_CLI_OPTIONS_OPTION -> configuration.put(JAVAC_CLI_OPTIONS, value)
APT_OPTION_OPTION -> configuration.appendMap(APT_OPTION, option, value)
JAVAC_OPTION_OPTION -> configuration.appendMap(JAVAC_OPTION, option, 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)
@@ -183,12 +148,34 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
INFO_AS_WARNINGS_OPTION -> configuration.put(Kapt3ConfigurationKeys.INFO_AS_WARNINGS, value)
STRICT_MODE_OPTION -> configuration.put(Kapt3ConfigurationKeys.STRICT_MODE, value)
CONFIGURATION -> configuration.applyOptionsFrom(decodePluginOptions(value), pluginOptions)
TOOLS_JAR_OPTION -> throw CliOptionProcessingException("'${TOOLS_JAR_OPTION.optionName}' is only supported in the kapt CLI tool")
}
}
private fun CompilerConfiguration.appendMap(
key: CompilerConfigurationKey<Map<String, String>>,
option: AbstractCliOption,
keyValuePair: String
) {
val keyValueDecoded = keyValuePair.split('=', limit = 2)
if (keyValueDecoded.size != 2) {
throw CliOptionProcessingException("Invalid option format for ${option.optionName}: key=value expected")
}
val oldMap = getMap(key)
val newMap = (oldMap as? MutableMap<String, String>) ?: oldMap.toMutableMap()
newMap[keyValueDecoded[0]] = keyValueDecoded[1]
put(key, newMap)
}
}
class Kapt3ComponentRegistrar : ComponentRegistrar {
private fun decodeList(options: String): Map<String, String> {
private fun decodeMap(options: String): Map<String, String> {
if (options.isEmpty()) {
return emptyMap()
}
val map = LinkedHashMap<String, String>()
val decodedBytes = Base64.getDecoder().decode(options)
@@ -264,8 +251,11 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
return
}
val apOptions = configuration.get(APT_OPTIONS)?.let { decodeList(it) } ?: emptyMap()
val javacCliOptions = configuration.get(JAVAC_CLI_OPTIONS)?.let { decodeList(it) } ?: emptyMap()
val apOptions = (configuration.get(APT_OPTIONS)?.let { decodeMap(it) } ?: emptyMap()).toMutableMap()
configuration.get(APT_OPTION)?.let { apOptions += it }
val javacOptions = (configuration.get(JAVAC_CLI_OPTIONS)?.let { decodeMap(it) } ?: emptyMap()).toMutableMap()
configuration.get(JAVAC_OPTION)?.let { javacOptions += it }
sourcesOutputDir.mkdirs()
@@ -300,7 +290,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
}
val kapt3AnalysisCompletedHandlerExtension = ClasspathBasedKapt3Extension(
paths, apOptions, javacCliOptions, annotationProcessors,
paths, apOptions, javacOptions, annotationProcessors,
aptMode, useLightAnalysis, correctErrorTypes, mapDiagnosticLocations, strictMode,
System.currentTimeMillis(), logger, configuration
)
@@ -359,6 +349,8 @@ enum class AptMode(val optionName: String) {
get() = this != APT_ONLY
companion object {
fun supports(mode: String?) = AptMode.values().any { it.optionName == mode }
// Supports both deprecated APT_ONLY and new APT_MODE options
fun parse(mode: String?): AptMode {
return when (mode) {
+2
View File
@@ -168,6 +168,7 @@ include ":kotlin-build-common",
":examples:annotation-processor-example",
":kotlin-script-util",
":kotlin-annotation-processing",
":kotlin-annotation-processing-cli",
":kotlin-annotation-processing-base",
":kotlin-annotation-processing-runtime",
":kotlin-annotation-processing-gradle",
@@ -305,6 +306,7 @@ project(':kotlin-script-util').projectDir = "$rootDir/libraries/tools/kotlin-scr
project(':kotlin-annotation-processing-gradle').projectDir = "$rootDir/libraries/tools/kotlin-annotation-processing" as File
project(':kotlin-annotation-processing-embeddable').projectDir = "$rootDir/prepare/kotlin-annotation-processing-embeddable" as File
project(':kotlin-annotation-processing').projectDir = "$rootDir/plugins/kapt3/kapt3-compiler" as File
project(':kotlin-annotation-processing-cli').projectDir = "$rootDir/plugins/kapt3/kapt3-cli" as File
project(':kotlin-annotation-processing-base').projectDir = "$rootDir/plugins/kapt3/kapt3-base" as File
project(':kotlin-annotation-processing-runtime').projectDir = "$rootDir/plugins/kapt3/kapt3-runtime" as File
project(':plugins:kapt3-idea').projectDir = "$rootDir/plugins/kapt3/kapt3-idea" as File