Kapt, Refactoring: Introduce 'KaptOptions'
1. Use 'KaptOptions' for all kapt options, including paths and flags. 2. Use a single 'KAPT_OPTIONS' compiler configuration key for setting all options (using a mutable KaptOptions.Builder). 3. Pass 'KaptOptions' instead of separate flags. 4. Remove 'KaptPaths'. 5. Remove deprecated 'aptOnly' CLI option.
This commit is contained in:
+1
-1
@@ -94,7 +94,7 @@ public class KaptJVMCompilerMojo extends K2JVMCompileMojo {
|
||||
) {
|
||||
List<KaptOption> options = new ArrayList<>();
|
||||
|
||||
options.add(new KaptOption("aptOnly", true));
|
||||
options.add(new KaptOption("aptMode", "stubsAndApt"));
|
||||
options.add(new KaptOption("useLightAnalysis", useLightAnalysis));
|
||||
options.add(new KaptOption("correctErrorTypes", correctErrorTypes));
|
||||
options.add(new KaptOption("mapDiagnosticLocations", mapDiagnosticLocations));
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.kapt3.base
|
||||
|
||||
import com.sun.tools.javac.util.Context
|
||||
import org.jetbrains.kotlin.base.kapt3.*
|
||||
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
|
||||
import org.jetbrains.kotlin.kapt3.base.util.WriterBackedKaptLogger
|
||||
import org.jetbrains.kotlin.kapt3.base.util.info
|
||||
@@ -16,32 +17,26 @@ object Kapt {
|
||||
|
||||
@JvmStatic
|
||||
@Suppress("unused")
|
||||
fun kapt(
|
||||
paths: KaptPaths,
|
||||
isVerbose: Boolean,
|
||||
mapDiagnosticLocations: Boolean,
|
||||
annotationProcessorFqNames: List<String>,
|
||||
processorOptions: Map<String, String>,
|
||||
javacOptions: Map<String, String>
|
||||
): Boolean {
|
||||
val logger = WriterBackedKaptLogger(isVerbose)
|
||||
fun kaptFlags(rawFlags: Set<String>): KaptFlags {
|
||||
return KaptFlags.fromSet(KaptFlag.values().filterTo(mutableSetOf()) { it.name in rawFlags })
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Suppress("unused")
|
||||
fun kapt(options: KaptOptions): Boolean {
|
||||
val logger = WriterBackedKaptLogger(options[KaptFlag.VERBOSE])
|
||||
|
||||
if (!Kapt.checkJavacComponentsAccess(logger)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val kaptContext = KaptContext(paths, false, logger, mapDiagnosticLocations, processorOptions, javacOptions)
|
||||
val kaptContext = KaptContext(options, false, logger)
|
||||
|
||||
logger.info { "Kapt3 is enabled (stand-alone mode)." }
|
||||
logger.info { "Map diagnostic locations: $mapDiagnosticLocations" }
|
||||
paths.log(logger)
|
||||
logger.info { "Javac options: $javacOptions" }
|
||||
logger.info { "AP options: $processorOptions" }
|
||||
logger.info { options.logString("stand-alone mode") }
|
||||
|
||||
val javaSourceFiles = paths.collectJavaSourceFiles()
|
||||
logger.info { "Java source files: " + javaSourceFiles.joinToString { it.canonicalPath } }
|
||||
val javaSourceFiles = options.collectJavaSourceFiles()
|
||||
|
||||
val processorLoader = ProcessorLoader(paths, annotationProcessorFqNames, logger)
|
||||
val processorLoader = ProcessorLoader(options, logger)
|
||||
|
||||
processorLoader.use {
|
||||
val processors = processorLoader.loadProcessors(findClassLoaderWithJavac())
|
||||
|
||||
@@ -11,6 +11,8 @@ import com.sun.tools.javac.main.Option
|
||||
import com.sun.tools.javac.util.Context
|
||||
import com.sun.tools.javac.util.Log
|
||||
import com.sun.tools.javac.util.Options
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptFlag
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptOptions
|
||||
import org.jetbrains.kotlin.kapt3.base.javac.KaptJavaCompiler
|
||||
import org.jetbrains.kotlin.kapt3.base.javac.KaptJavaFileManager
|
||||
import org.jetbrains.kotlin.kapt3.base.javac.KaptJavaLog
|
||||
@@ -21,18 +23,11 @@ import java.io.Closeable
|
||||
import java.io.File
|
||||
import javax.tools.JavaFileManager
|
||||
|
||||
open class KaptContext(
|
||||
val paths: KaptPaths,
|
||||
val withJdk: Boolean,
|
||||
val logger: KaptLogger,
|
||||
private val mapDiagnosticLocations: Boolean,
|
||||
processorOptions: Map<String, String>,
|
||||
javacOptions: Map<String, String> = emptyMap()
|
||||
) : Closeable {
|
||||
open class KaptContext(val options: KaptOptions, val withJdk: Boolean, val logger: KaptLogger) : Closeable {
|
||||
val context = Context()
|
||||
val compiler: KaptJavaCompiler
|
||||
val fileManager: KaptJavaFileManager
|
||||
val options: Options
|
||||
private val javacOptions: Options
|
||||
val javaLog: KaptJavaLog
|
||||
|
||||
protected open fun preregisterTreeMaker(context: Context) {}
|
||||
@@ -41,8 +36,8 @@ open class KaptContext(
|
||||
val interceptorData = KaptJavaLog.DiagnosticInterceptorData()
|
||||
context.put(Log.logKey, Context.Factory<Log> { newContext ->
|
||||
KaptJavaLog(
|
||||
paths.projectBaseDir, newContext, logger.errorWriter, logger.warnWriter, logger.infoWriter,
|
||||
interceptorData, mapDiagnosticLocations
|
||||
options.projectBaseDir, newContext, logger.errorWriter, logger.warnWriter, logger.infoWriter,
|
||||
interceptorData, options[KaptFlag.MAP_DIAGNOSTIC_LOCATIONS]
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -56,13 +51,13 @@ open class KaptContext(
|
||||
|
||||
KaptJavaCompiler.preRegister(context)
|
||||
|
||||
options = Options.instance(context).apply {
|
||||
for ((key, value) in processorOptions) {
|
||||
javacOptions = Options.instance(context).apply {
|
||||
for ((key, value) in options.processingOptions) {
|
||||
val option = if (value.isEmpty()) "-A$key" else "-A$key=$value"
|
||||
put(option, option) // key == value: it's intentional
|
||||
}
|
||||
|
||||
for ((key, value) in javacOptions) {
|
||||
for ((key, value) in options.javacOptions) {
|
||||
if (value.isNotEmpty()) {
|
||||
put(key, value)
|
||||
} else {
|
||||
@@ -82,26 +77,26 @@ open class KaptContext(
|
||||
}
|
||||
|
||||
putJavacOption("CLASSPATH", "CLASS_PATH",
|
||||
paths.compileClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
|
||||
options.compileClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
putJavacOption("PROCESSORPATH", "PROCESSOR_PATH",
|
||||
paths.annotationProcessingClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
|
||||
options.processingClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
|
||||
|
||||
put(Option.S, paths.sourcesOutputDir.canonicalPath)
|
||||
put(Option.D, paths.classFilesOutputDir.canonicalPath)
|
||||
put(Option.S, options.sourcesOutputDir.canonicalPath)
|
||||
put(Option.D, options.classesOutputDir.canonicalPath)
|
||||
put(Option.ENCODING, "UTF-8")
|
||||
}
|
||||
|
||||
if (logger.isVerbose) {
|
||||
logger.info("All Javac options: " + options.keySet().associateBy({ it }) { key -> options[key] ?: "" })
|
||||
logger.info("All Javac options: " + javacOptions.keySet().associateBy({ it }) { key -> javacOptions[key] ?: "" })
|
||||
}
|
||||
|
||||
fileManager = context.get(JavaFileManager::class.java) as KaptJavaFileManager
|
||||
|
||||
if (isJava9OrLater()) {
|
||||
for (option in Option.getJavacFileManagerOptions()) {
|
||||
val value = options.get(option) ?: continue
|
||||
val value = javacOptions.get(option) ?: continue
|
||||
fileManager.handleOptionJavac9(option, value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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.base.kapt3
|
||||
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
|
||||
class KaptOptions(
|
||||
val projectBaseDir: File?,
|
||||
val compileClasspath: List<File>,
|
||||
val javaSourceRoots: List<File>,
|
||||
|
||||
val sourcesOutputDir: File,
|
||||
val classesOutputDir: File,
|
||||
val stubsOutputDir: File,
|
||||
val incrementalDataOutputDir: File?,
|
||||
|
||||
val processingClasspath: List<File>,
|
||||
val processors: List<String>,
|
||||
|
||||
val processingOptions: Map<String, String>,
|
||||
val javacOptions: Map<String, String>,
|
||||
|
||||
val flags: KaptFlags,
|
||||
|
||||
val mode: AptMode,
|
||||
val detectMemoryLeaks: DetectMemoryLeaksMode
|
||||
) : KaptFlags {
|
||||
override fun get(flag: KaptFlag) = flags[flag]
|
||||
|
||||
class Builder {
|
||||
var projectBaseDir: File? = null
|
||||
val compileClasspath: MutableList<File> = mutableListOf()
|
||||
val javaSourceRoots: MutableList<File> = mutableListOf()
|
||||
|
||||
var sourcesOutputDir: File? = null
|
||||
var classesOutputDir: File? = null
|
||||
var stubsOutputDir: File? = null
|
||||
var incrementalDataOutputDir: File? = null
|
||||
|
||||
val processingClasspath: MutableList<File> = mutableListOf()
|
||||
val processors: MutableList<String> = mutableListOf()
|
||||
|
||||
val processingOptions: MutableMap<String, String> = mutableMapOf()
|
||||
val javacOptions: MutableMap<String, String> = mutableMapOf()
|
||||
|
||||
val flags: MutableSet<KaptFlag> = mutableSetOf(KaptFlag.USE_LIGHT_ANALYSIS)
|
||||
|
||||
var mode: AptMode = AptMode.WITH_COMPILATION
|
||||
var detectMemoryLeaks: DetectMemoryLeaksMode = DetectMemoryLeaksMode.DEFAULT
|
||||
|
||||
fun build(): KaptOptions {
|
||||
val sourcesOutputDir = this.sourcesOutputDir ?: error("'sourcesOutputDir' must be set")
|
||||
val classesOutputDir = this.classesOutputDir ?: error("'classesOutputDir' must be set")
|
||||
val stubsOutputDir = this.stubsOutputDir ?: error("'stubsOutputDir' must be set")
|
||||
|
||||
return KaptOptions(
|
||||
projectBaseDir, compileClasspath, javaSourceRoots,
|
||||
sourcesOutputDir, classesOutputDir, stubsOutputDir, incrementalDataOutputDir,
|
||||
processingClasspath, processors, processingOptions, javacOptions, KaptFlags.fromSet(flags),
|
||||
mode, detectMemoryLeaks
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface KaptFlags {
|
||||
operator fun get(flag: KaptFlag): Boolean
|
||||
|
||||
companion object {
|
||||
fun fromSet(flags: Set<KaptFlag>) = object : KaptFlags {
|
||||
override fun get(flag: KaptFlag) = flag in flags
|
||||
}
|
||||
}
|
||||
|
||||
object Empty : KaptFlags {
|
||||
override fun get(flag: KaptFlag) = false
|
||||
}
|
||||
}
|
||||
|
||||
enum class KaptFlag(val description: String) {
|
||||
VERBOSE("Verbose mode"),
|
||||
INFO_AS_WARNINGS("Info as warnings"),
|
||||
USE_LIGHT_ANALYSIS("Use light analysis"),
|
||||
CORRECT_ERROR_TYPES("Correct error types"),
|
||||
MAP_DIAGNOSTIC_LOCATIONS("Map diagnostic locations"),
|
||||
STRICT("Strict mode");
|
||||
}
|
||||
|
||||
interface KaptSelector {
|
||||
val stringValue: String
|
||||
}
|
||||
|
||||
enum class DetectMemoryLeaksMode(override val stringValue: String) : KaptSelector {
|
||||
DEFAULT("default"), PARANOID("paranoid"), NONE("none")
|
||||
}
|
||||
|
||||
enum class AptMode(override val stringValue: String) : KaptSelector {
|
||||
WITH_COMPILATION("compile"),
|
||||
STUBS_AND_APT("stubsAndApt"),
|
||||
STUBS_ONLY("stubs"),
|
||||
APT_ONLY("apt");
|
||||
|
||||
val runAnnotationProcessing
|
||||
get() = this != STUBS_ONLY
|
||||
|
||||
val generateStubs
|
||||
get() = this != APT_ONLY
|
||||
}
|
||||
|
||||
fun KaptOptions.collectJavaSourceFiles(): List<File> {
|
||||
return (javaSourceRoots + stubsOutputDir)
|
||||
.sortedBy { Files.isSymbolicLink(it.toPath()) } // Get non-symbolic paths first
|
||||
.flatMap { root -> root.walk().filter { it.isFile && it.extension == "java" }.toList() }
|
||||
.sortedBy { Files.isSymbolicLink(it.toPath()) } // This time is for .java files
|
||||
.distinctBy { it.canonicalPath }
|
||||
}
|
||||
|
||||
fun KaptOptions.logString(additionalInfo: String = "") = buildString {
|
||||
val additionalInfoRendered = if (additionalInfo.isEmpty()) "" else " ($additionalInfo)"
|
||||
appendln("Kapt3 is enabled$additionalInfoRendered.")
|
||||
|
||||
appendln("Annotation processing mode: ${mode.stringValue}")
|
||||
appendln("Memory leak detection mode: ${detectMemoryLeaks.stringValue}")
|
||||
KaptFlag.values().forEach { appendln(it.description + ": " + this@logString[it]) }
|
||||
|
||||
appendln("Project base dir: $projectBaseDir")
|
||||
appendln("Compile classpath: " + compileClasspath.joinToString())
|
||||
appendln("Java source roots: " + javaSourceRoots.joinToString())
|
||||
|
||||
appendln("Sources output directory: $sourcesOutputDir")
|
||||
appendln("Class files output directory: $classesOutputDir")
|
||||
appendln("Stubs output directory: $stubsOutputDir")
|
||||
appendln("Incremental data output directory: $incrementalDataOutputDir")
|
||||
|
||||
appendln("Annotation processing classpath: " + processingClasspath.joinToString())
|
||||
appendln("Annotation processors: " + processors.joinToString())
|
||||
|
||||
appendln("AP options: $processingOptions")
|
||||
appendln("Javac options: $javacOptions")
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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.kapt3.base
|
||||
|
||||
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
|
||||
class KaptPaths(
|
||||
val projectBaseDir: File?,
|
||||
compileClasspath: List<File>,
|
||||
annotationProcessingClasspath: List<File>,
|
||||
val javaSourceRoots: List<File>,
|
||||
val sourcesOutputDir: File,
|
||||
val classFilesOutputDir: File,
|
||||
val stubsOutputDir: File,
|
||||
val incrementalDataOutputDir: File?
|
||||
) {
|
||||
val compileClasspath = compileClasspath.distinct()
|
||||
val annotationProcessingClasspath = annotationProcessingClasspath.distinct()
|
||||
|
||||
fun collectJavaSourceFiles(): List<File> {
|
||||
return (javaSourceRoots + stubsOutputDir)
|
||||
.sortedBy { Files.isSymbolicLink(it.toPath()) } // Get non-symbolic paths first
|
||||
.flatMap { root -> root.walk().filter { it.isFile && it.extension == "java" }.toList() }
|
||||
.sortedBy { Files.isSymbolicLink(it.toPath()) } // This time is for .java files
|
||||
.distinctBy { it.canonicalPath }
|
||||
}
|
||||
}
|
||||
|
||||
fun KaptPaths.log(logger: KaptLogger) {
|
||||
if (!logger.isVerbose) return
|
||||
|
||||
logger.info("Project base dir: $projectBaseDir")
|
||||
logger.info("Compile classpath: ${compileClasspath.joinToString()}")
|
||||
logger.info("Annotation processing classpath: ${annotationProcessingClasspath.joinToString()}")
|
||||
logger.info("Java source roots: ${javaSourceRoots.joinToString()}")
|
||||
logger.info("Sources output directory: $sourcesOutputDir")
|
||||
logger.info("Class files output directory: $classFilesOutputDir")
|
||||
logger.info("Stubs output directory: $stubsOutputDir")
|
||||
logger.info("Incremental data output directory: $incrementalDataOutputDir")
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.kapt3.base
|
||||
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptOptions
|
||||
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
|
||||
import org.jetbrains.kotlin.kapt3.base.util.info
|
||||
import java.io.Closeable
|
||||
@@ -16,23 +17,19 @@ import javax.annotation.processing.Processor
|
||||
|
||||
class LoadedProcessors(val processors: List<Processor>, val classLoader: ClassLoader)
|
||||
|
||||
open class ProcessorLoader(
|
||||
private val paths: KaptPaths,
|
||||
private val annotationProcessorFqNames: List<String>,
|
||||
private val logger: KaptLogger
|
||||
) : Closeable {
|
||||
open class ProcessorLoader(private val options: KaptOptions, private val logger: KaptLogger) : Closeable {
|
||||
private var annotationProcessingClassLoader: URLClassLoader? = null
|
||||
|
||||
fun loadProcessors(parentClassLoader: ClassLoader = ClassLoader.getSystemClassLoader()): LoadedProcessors {
|
||||
clearJarURLCache()
|
||||
|
||||
val classpath = (paths.annotationProcessingClasspath + paths.compileClasspath).distinct()
|
||||
val classpath = (options.processingClasspath + options.compileClasspath).distinct()
|
||||
val classLoader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray(), parentClassLoader)
|
||||
this.annotationProcessingClassLoader = classLoader
|
||||
|
||||
val processors = if (annotationProcessorFqNames.isNotEmpty()) {
|
||||
val processors = if (options.processors.isNotEmpty()) {
|
||||
logger.info("Annotation processor class names are set, skip AP discovery")
|
||||
annotationProcessorFqNames.mapNotNull { tryLoadProcessor(it, classLoader) }
|
||||
options.processors.mapNotNull { tryLoadProcessor(it, classLoader) }
|
||||
} else {
|
||||
logger.info("Need to discovery annotation processors in the AP classpath")
|
||||
doLoadProcessors(classLoader)
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
package org.jetbrains.kotlin.kapt.base.test
|
||||
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.base.kapt3.DetectMemoryLeaksMode
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptFlag
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptOptions
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptContext
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptPaths
|
||||
import org.jetbrains.kotlin.kapt3.base.doAnnotationProcessing
|
||||
import org.jetbrains.kotlin.kapt3.base.util.KaptBaseError
|
||||
import org.jetbrains.kotlin.kapt3.base.util.WriterBackedKaptLogger
|
||||
@@ -49,22 +51,20 @@ class JavaKaptContextTest : TestCase() {
|
||||
}
|
||||
|
||||
private fun doAnnotationProcessing(javaSourceFile: File, processor: Processor, outputDir: File) {
|
||||
KaptContext(
|
||||
KaptPaths(
|
||||
projectBaseDir = javaSourceFile.parentFile,
|
||||
compileClasspath = emptyList(),
|
||||
annotationProcessingClasspath = emptyList(),
|
||||
javaSourceRoots = emptyList(),
|
||||
sourcesOutputDir = outputDir,
|
||||
classFilesOutputDir = outputDir,
|
||||
stubsOutputDir = outputDir,
|
||||
incrementalDataOutputDir = outputDir
|
||||
),
|
||||
withJdk = true,
|
||||
logger = WriterBackedKaptLogger(isVerbose = true),
|
||||
mapDiagnosticLocations = true,
|
||||
processorOptions = emptyMap()
|
||||
).doAnnotationProcessing(listOf(javaSourceFile), listOf(processor))
|
||||
val options = KaptOptions.Builder().apply {
|
||||
projectBaseDir = javaSourceFile.parentFile
|
||||
|
||||
sourcesOutputDir = outputDir
|
||||
classesOutputDir = outputDir
|
||||
stubsOutputDir = outputDir
|
||||
incrementalDataOutputDir = outputDir
|
||||
|
||||
flags.add(KaptFlag.MAP_DIAGNOSTIC_LOCATIONS)
|
||||
detectMemoryLeaks = DetectMemoryLeaksMode.NONE
|
||||
}.build()
|
||||
|
||||
val logger = WriterBackedKaptLogger(isVerbose = true)
|
||||
KaptContext(options, true, logger).doAnnotationProcessing(listOf(javaSourceFile), listOf(processor))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
package org.jetbrains.kotlin.kapt.base.test
|
||||
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptPaths
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptOptions
|
||||
import org.jetbrains.kotlin.base.kapt3.collectJavaSourceFiles
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
@@ -36,16 +37,12 @@ class KaptPathsTest : TestCase() {
|
||||
|
||||
val javaRoots = listOf(simpleJava, symlinkToOtherJava, symlinkToNotJava, symlinkToJavaRootDir, javaRootDir)
|
||||
|
||||
val paths = KaptPaths(
|
||||
projectBaseDir = null,
|
||||
compileClasspath = emptyList(),
|
||||
annotationProcessingClasspath = emptyList(),
|
||||
javaSourceRoots = javaRoots,
|
||||
sourcesOutputDir = outputDir,
|
||||
classFilesOutputDir = outputDir,
|
||||
stubsOutputDir = outputDir,
|
||||
incrementalDataOutputDir = null
|
||||
)
|
||||
val paths = KaptOptions.Builder().apply {
|
||||
javaSourceRoots.addAll(javaRoots)
|
||||
sourcesOutputDir = outputDir
|
||||
classesOutputDir = outputDir
|
||||
stubsOutputDir = outputDir
|
||||
}.build()
|
||||
|
||||
val javaSourceFiles = paths.collectJavaSourceFiles()
|
||||
|
||||
|
||||
@@ -149,10 +149,7 @@ enum class KaptCliOption(
|
||||
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");
|
||||
JAVAC_CLI_OPTIONS_OPTION("javacArguments", "javac CLI options map", "Encoded javac CLI options", false);
|
||||
|
||||
override val required: Boolean = false
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.sun.tools.javac.tree.TreeMaker
|
||||
import com.sun.tools.javac.util.Context
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFile
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptOptions
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.OUTPUT
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
|
||||
@@ -39,8 +40,11 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.container.ComponentProvider
|
||||
import org.jetbrains.kotlin.context.ProjectContext
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.kapt3.AptMode.APT_ONLY
|
||||
import org.jetbrains.kotlin.kapt3.AptMode.WITH_COMPILATION
|
||||
import org.jetbrains.kotlin.base.kapt3.AptMode.APT_ONLY
|
||||
import org.jetbrains.kotlin.base.kapt3.AptMode.WITH_COMPILATION
|
||||
import org.jetbrains.kotlin.base.kapt3.DetectMemoryLeaksMode
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptFlag
|
||||
import org.jetbrains.kotlin.base.kapt3.collectJavaSourceFiles
|
||||
import org.jetbrains.kotlin.kapt3.base.*
|
||||
import org.jetbrains.kotlin.kapt3.base.stubs.KaptStubLineInformation.Companion.KAPT_METADATA_EXTENSION
|
||||
import org.jetbrains.kotlin.kapt3.base.util.KaptBaseError
|
||||
@@ -64,31 +68,17 @@ import javax.annotation.processing.Processor
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
|
||||
class ClasspathBasedKapt3Extension(
|
||||
paths: KaptPaths,
|
||||
options: Map<String, String>,
|
||||
javacOptions: Map<String, String>,
|
||||
annotationProcessorFqNames: List<String>,
|
||||
aptMode: AptMode,
|
||||
private val useLightAnalysis: Boolean,
|
||||
correctErrorTypes: Boolean,
|
||||
mapDiagnosticLocations: Boolean,
|
||||
strictMode: Boolean,
|
||||
detectMemoryLeaks: Boolean,
|
||||
pluginInitializedTime: Long,
|
||||
options: KaptOptions,
|
||||
logger: MessageCollectorBackedKaptLogger,
|
||||
compilerConfiguration: CompilerConfiguration
|
||||
) : AbstractKapt3Extension(
|
||||
paths, options, javacOptions, annotationProcessorFqNames,
|
||||
aptMode, pluginInitializedTime, logger, correctErrorTypes, mapDiagnosticLocations, strictMode, detectMemoryLeaks,
|
||||
compilerConfiguration
|
||||
) {
|
||||
) : AbstractKapt3Extension(options, logger, compilerConfiguration) {
|
||||
override val analyzePartially: Boolean
|
||||
get() = useLightAnalysis && super.analyzePartially
|
||||
get() = options[KaptFlag.USE_LIGHT_ANALYSIS] && super.analyzePartially
|
||||
|
||||
private var processorLoader: ProcessorLoader? = null
|
||||
|
||||
override fun loadProcessors(): LoadedProcessors {
|
||||
val efficientProcessorLoader = object : ProcessorLoader(paths, annotationProcessorFqNames, logger) {
|
||||
val efficientProcessorLoader = object : ProcessorLoader(options, logger) {
|
||||
override fun doLoadProcessors(classLoader: URLClassLoader): List<Processor> {
|
||||
return ServiceLoaderLite.loadImplementations(Processor::class.java, classLoader)
|
||||
}
|
||||
@@ -122,19 +112,12 @@ class ClasspathBasedKapt3Extension(
|
||||
}
|
||||
|
||||
abstract class AbstractKapt3Extension(
|
||||
val paths: KaptPaths,
|
||||
private val options: Map<String, String>,
|
||||
private val javacOptions: Map<String, String>,
|
||||
val annotationProcessorFqNames: List<String>,
|
||||
private val aptMode: AptMode,
|
||||
private val pluginInitializedTime: Long,
|
||||
val options: KaptOptions,
|
||||
val logger: MessageCollectorBackedKaptLogger,
|
||||
val correctErrorTypes: Boolean,
|
||||
val mapDiagnosticLocations: Boolean,
|
||||
val strictMode: Boolean,
|
||||
val detectMemoryLeaks: Boolean,
|
||||
val compilerConfiguration: CompilerConfiguration
|
||||
) : PartialAnalysisHandlerExtension() {
|
||||
private val pluginInitializedTime: Long = System.currentTimeMillis()
|
||||
|
||||
private var annotationProcessingComplete = false
|
||||
|
||||
private fun setAnnotationProcessingComplete(): Boolean {
|
||||
@@ -155,7 +138,7 @@ abstract class AbstractKapt3Extension(
|
||||
bindingTrace: BindingTrace,
|
||||
componentProvider: ComponentProvider
|
||||
): AnalysisResult? {
|
||||
if (aptMode == APT_ONLY) {
|
||||
if (options.mode == APT_ONLY) {
|
||||
return AnalysisResult.EMPTY
|
||||
}
|
||||
|
||||
@@ -175,7 +158,7 @@ abstract class AbstractKapt3Extension(
|
||||
logger.info { "Initial analysis took ${System.currentTimeMillis() - pluginInitializedTime} ms" }
|
||||
|
||||
val bindingContext = bindingTrace.bindingContext
|
||||
if (aptMode.generateStubs) {
|
||||
if (options.mode.generateStubs) {
|
||||
logger.info { "Kotlin files to compile: " + files.map { it.virtualFile?.name ?: "<in memory ${it.hashCode()}>" } }
|
||||
|
||||
contextForStubGeneration(project, module, bindingContext, files.toList()).use { context ->
|
||||
@@ -183,12 +166,12 @@ abstract class AbstractKapt3Extension(
|
||||
}
|
||||
}
|
||||
|
||||
if (!aptMode.runAnnotationProcessing) return doNotGenerateCode()
|
||||
if (!options.mode.runAnnotationProcessing) return doNotGenerateCode()
|
||||
|
||||
val processors = loadProcessors()
|
||||
if (processors.processors.isEmpty()) return if (aptMode != WITH_COMPILATION) doNotGenerateCode() else null
|
||||
if (processors.processors.isEmpty()) return if (options.mode != WITH_COMPILATION) doNotGenerateCode() else null
|
||||
|
||||
val kaptContext = KaptContext(paths, false, logger, mapDiagnosticLocations, options, javacOptions)
|
||||
val kaptContext = KaptContext(options, false, logger)
|
||||
|
||||
fun handleKaptError(error: KaptError): AnalysisResult {
|
||||
val cause = error.cause
|
||||
@@ -218,22 +201,22 @@ abstract class AbstractKapt3Extension(
|
||||
kaptContext.close()
|
||||
}
|
||||
|
||||
return if (aptMode != WITH_COMPILATION) {
|
||||
return if (options.mode != WITH_COMPILATION) {
|
||||
doNotGenerateCode()
|
||||
} else {
|
||||
AnalysisResult.RetryWithAdditionalJavaRoots(
|
||||
bindingTrace.bindingContext,
|
||||
module,
|
||||
listOf(paths.sourcesOutputDir),
|
||||
listOf(options.sourcesOutputDir),
|
||||
addToEnvironment = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun runAnnotationProcessing(kaptContext: KaptContext, processors: LoadedProcessors) {
|
||||
if (!aptMode.runAnnotationProcessing) return
|
||||
if (!options.mode.runAnnotationProcessing) return
|
||||
|
||||
val javaSourceFiles = paths.collectJavaSourceFiles()
|
||||
val javaSourceFiles = options.collectJavaSourceFiles()
|
||||
logger.info { "Java source files: " + javaSourceFiles.joinToString { it.canonicalPath } }
|
||||
|
||||
val (annotationProcessingTime) = measureTimeMillis {
|
||||
@@ -242,7 +225,7 @@ abstract class AbstractKapt3Extension(
|
||||
|
||||
logger.info { "Annotation processing took $annotationProcessingTime ms" }
|
||||
|
||||
if (detectMemoryLeaks) {
|
||||
if (options.detectMemoryLeaks != DetectMemoryLeaksMode.NONE) {
|
||||
MemoryLeakDetector.add(processors.classLoader)
|
||||
|
||||
val (leakDetectionTime, leaks) = measureTimeMillis { MemoryLeakDetector.process() }
|
||||
@@ -291,18 +274,13 @@ abstract class AbstractKapt3Extension(
|
||||
logger.info { "Compiled classes: " + compiledClasses.joinToString { it.name } }
|
||||
|
||||
return KaptContextForStubGeneration(
|
||||
paths, false, logger, project, bindingContext, compiledClasses, origins, generationState,
|
||||
mapDiagnosticLocations, options, javacOptions
|
||||
options, false, logger, project, bindingContext,
|
||||
compiledClasses, origins, generationState
|
||||
)
|
||||
}
|
||||
|
||||
private fun generateKotlinSourceStubs(kaptContext: KaptContextForStubGeneration) {
|
||||
val converter = ClassFileToSourceStubConverter(
|
||||
kaptContext,
|
||||
generateNonExistentClass = true,
|
||||
correctErrorTypes = correctErrorTypes,
|
||||
strictMode = strictMode
|
||||
)
|
||||
val converter = ClassFileToSourceStubConverter(kaptContext, generateNonExistentClass = true)
|
||||
|
||||
val (stubGenerationTime, kaptStubs) = measureTimeMillis {
|
||||
converter.convert()
|
||||
@@ -321,7 +299,7 @@ abstract class AbstractKapt3Extension(
|
||||
val className = (stub.defs.first { it is JCTree.JCClassDecl } as JCTree.JCClassDecl).simpleName.toString()
|
||||
|
||||
val packageName = stub.getPackageNameJava9Aware()?.toString() ?: ""
|
||||
val packageDir = if (packageName.isEmpty()) paths.stubsOutputDir else File(paths.stubsOutputDir, packageName.replace('.', '/'))
|
||||
val packageDir = if (packageName.isEmpty()) options.stubsOutputDir else File(options.stubsOutputDir, packageName.replace('.', '/'))
|
||||
packageDir.mkdirs()
|
||||
|
||||
val sourceFile = File(packageDir, "$className.java")
|
||||
@@ -336,7 +314,7 @@ abstract class AbstractKapt3Extension(
|
||||
messageCollector: MessageCollector,
|
||||
converter: ClassFileToSourceStubConverter
|
||||
) {
|
||||
val incrementalDataOutputDir = paths.incrementalDataOutputDir ?: return
|
||||
val incrementalDataOutputDir = options.incrementalDataOutputDir ?: return
|
||||
|
||||
val reportOutputFiles = kaptContext.generationState.configuration.getBoolean(CommonConfigurationKeys.REPORT_OUTPUT_FILES)
|
||||
kaptContext.generationState.factory.writeAll(
|
||||
@@ -344,7 +322,7 @@ abstract class AbstractKapt3Extension(
|
||||
if (!reportOutputFiles) null else fun(file: OutputFile, sources: List<File>, output: File) {
|
||||
val stubFileObject = converter.bindings[file.relativePath.substringBeforeLast(".class", missingDelimiterValue = "")]
|
||||
if (stubFileObject != null) {
|
||||
val stubFile = File(paths.stubsOutputDir, stubFileObject.name)
|
||||
val stubFile = File(options.stubsOutputDir, stubFileObject.name)
|
||||
val lineMappingsFile = File(stubFile.parentFile, stubFile.nameWithoutExtension + KAPT_METADATA_EXTENSION)
|
||||
|
||||
for (outputFile in listOf(stubFile, lineMappingsFile)) {
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.kapt3
|
||||
import com.intellij.mock.MockProject
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.base.kapt3.*
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
|
||||
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
|
||||
@@ -38,14 +39,8 @@ import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
|
||||
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.Kapt3ConfigurationKeys.JAVAC_OPTION
|
||||
import org.jetbrains.kotlin.kapt3.base.Kapt
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptPaths
|
||||
import org.jetbrains.kotlin.kapt3.base.log
|
||||
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
|
||||
import org.jetbrains.kotlin.kapt3.util.MessageCollectorBackedKaptLogger
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
@@ -58,70 +53,7 @@ import java.io.File
|
||||
import java.io.ObjectInputStream
|
||||
import java.util.*
|
||||
|
||||
object Kapt3ConfigurationKeys {
|
||||
val SOURCE_OUTPUT_DIR: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(SOURCE_OUTPUT_DIR_OPTION.description)
|
||||
|
||||
val CLASS_OUTPUT_DIR: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(CLASS_OUTPUT_DIR_OPTION.description)
|
||||
|
||||
val STUBS_OUTPUT_DIR: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(STUBS_OUTPUT_DIR_OPTION.description)
|
||||
|
||||
val INCREMENTAL_DATA_OUTPUT_DIR: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(INCREMENTAL_DATA_OUTPUT_DIR_OPTION.description)
|
||||
|
||||
val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> =
|
||||
CompilerConfigurationKey.create<List<String>>(ANNOTATION_PROCESSOR_CLASSPATH_OPTION.description)
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@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)
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@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)
|
||||
|
||||
val VERBOSE_MODE: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(VERBOSE_MODE_OPTION.description)
|
||||
|
||||
val INFO_AS_WARNINGS: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(INFO_AS_WARNINGS_OPTION.description)
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Deprecated("Use APT_MODE instead.")
|
||||
val APT_ONLY: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(APT_ONLY_OPTION.description)
|
||||
|
||||
val APT_MODE: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(APT_MODE_OPTION.description)
|
||||
|
||||
val USE_LIGHT_ANALYSIS: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(USE_LIGHT_ANALYSIS_OPTION.description)
|
||||
|
||||
val CORRECT_ERROR_TYPES: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(CORRECT_ERROR_TYPES_OPTION.description)
|
||||
|
||||
val MAP_DIAGNOSTIC_LOCATIONS: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(MAP_DIAGNOSTIC_LOCATIONS_OPTION.description)
|
||||
|
||||
val STRICT_MODE: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(STRICT_MODE_OPTION.description)
|
||||
|
||||
val DETECT_MEMORY_LEAKS: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(DETECT_MEMORY_LEAKS_OPTION.description)
|
||||
}
|
||||
private val KAPT_OPTIONS = CompilerConfigurationKey.create<KaptOptions.Builder>("Kapt options")
|
||||
|
||||
class Kapt3CommandLineProcessor : CommandLineProcessor {
|
||||
override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
|
||||
@@ -133,52 +65,61 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
|
||||
throw CliOptionProcessingException("Unknown option: ${option.optionName}")
|
||||
}
|
||||
|
||||
val kaptOptions = configuration[KAPT_OPTIONS]
|
||||
?: KaptOptions.Builder().also { configuration.put(KAPT_OPTIONS, it) }
|
||||
|
||||
if (option == @Suppress("DEPRECATION") KaptCliOption.CONFIGURATION) {
|
||||
configuration.applyOptionsFrom(decodePluginOptions(value), pluginOptions)
|
||||
} else {
|
||||
kaptOptions.processOption(option, value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KaptOptions.Builder.processOption(option: KaptCliOption, value: String) {
|
||||
fun setFlag(flag: KaptFlag, value: String) = if (value == "true") flags.add(flag) else flags.remove(flag)
|
||||
|
||||
fun <T : KaptSelector> setSelector(values: Array<T>, rawValue: String, selector: (T) -> Unit) {
|
||||
selector(values.firstOrNull { it.stringValue == rawValue }
|
||||
?: throw CliOptionProcessingException("Unknown value $rawValue for option ${option.optionName}"))
|
||||
}
|
||||
|
||||
fun setKeyValue(rawValue: String, apply: (String, String) -> Unit) {
|
||||
val keyValuePair = rawValue.split('=', limit = 2).takeIf { it.size == 2 }
|
||||
?: throw CliOptionProcessingException("Invalid option format for ${option.optionName}: key=value expected")
|
||||
apply(keyValuePair[0], keyValuePair[1])
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
return when (option) {
|
||||
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(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)
|
||||
INCREMENTAL_DATA_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.INCREMENTAL_DATA_OUTPUT_DIR, value)
|
||||
VERBOSE_MODE_OPTION -> configuration.put(Kapt3ConfigurationKeys.VERBOSE_MODE, value)
|
||||
APT_ONLY_OPTION -> configuration.put(Kapt3ConfigurationKeys.APT_ONLY, value)
|
||||
APT_MODE_OPTION -> configuration.put(Kapt3ConfigurationKeys.APT_MODE, value)
|
||||
USE_LIGHT_ANALYSIS_OPTION -> configuration.put(Kapt3ConfigurationKeys.USE_LIGHT_ANALYSIS, value)
|
||||
CORRECT_ERROR_TYPES_OPTION -> configuration.put(Kapt3ConfigurationKeys.CORRECT_ERROR_TYPES, value)
|
||||
MAP_DIAGNOSTIC_LOCATIONS_OPTION -> configuration.put(Kapt3ConfigurationKeys.MAP_DIAGNOSTIC_LOCATIONS, value)
|
||||
INFO_AS_WARNINGS_OPTION -> configuration.put(Kapt3ConfigurationKeys.INFO_AS_WARNINGS, value)
|
||||
STRICT_MODE_OPTION -> configuration.put(Kapt3ConfigurationKeys.STRICT_MODE, value)
|
||||
DETECT_MEMORY_LEAKS_OPTION -> configuration.put(Kapt3ConfigurationKeys.DETECT_MEMORY_LEAKS, value)
|
||||
CONFIGURATION -> configuration.applyOptionsFrom(decodePluginOptions(value), pluginOptions)
|
||||
when (option) {
|
||||
SOURCE_OUTPUT_DIR_OPTION -> sourcesOutputDir = File(value)
|
||||
CLASS_OUTPUT_DIR_OPTION -> classesOutputDir = File(value)
|
||||
STUBS_OUTPUT_DIR_OPTION -> stubsOutputDir = File(value)
|
||||
INCREMENTAL_DATA_OUTPUT_DIR_OPTION -> incrementalDataOutputDir = File(value)
|
||||
|
||||
ANNOTATION_PROCESSOR_CLASSPATH_OPTION -> processingClasspath += File(value)
|
||||
ANNOTATION_PROCESSORS_OPTION -> processors.addAll(value.split(',').map { it.trim() }.filter { it.isNotEmpty() })
|
||||
|
||||
APT_OPTION_OPTION -> setKeyValue(value) { k, v -> processingOptions[k] = v }
|
||||
JAVAC_OPTION_OPTION -> setKeyValue(value) { k, v -> javacOptions[k] = v }
|
||||
|
||||
VERBOSE_MODE_OPTION -> setFlag(KaptFlag.VERBOSE, value)
|
||||
USE_LIGHT_ANALYSIS_OPTION -> setFlag(KaptFlag.USE_LIGHT_ANALYSIS, value)
|
||||
CORRECT_ERROR_TYPES_OPTION -> setFlag(KaptFlag.CORRECT_ERROR_TYPES, value)
|
||||
MAP_DIAGNOSTIC_LOCATIONS_OPTION -> setFlag(KaptFlag.MAP_DIAGNOSTIC_LOCATIONS, value)
|
||||
INFO_AS_WARNINGS_OPTION -> setFlag(KaptFlag.INFO_AS_WARNINGS, value)
|
||||
STRICT_MODE_OPTION -> setFlag(KaptFlag.STRICT, value)
|
||||
|
||||
DETECT_MEMORY_LEAKS_OPTION -> setSelector(enumValues<DetectMemoryLeaksMode>(), value) { detectMemoryLeaks = it }
|
||||
APT_MODE_OPTION -> setSelector(enumValues<AptMode>(), value) { mode = it }
|
||||
|
||||
APT_OPTIONS_OPTION -> processingOptions.putAll(decodeMap(value))
|
||||
JAVAC_CLI_OPTIONS_OPTION -> javacOptions.putAll(decodeMap(value))
|
||||
CONFIGURATION -> throw CliOptionProcessingException("${CONFIGURATION.optionName} should be handled earlier")
|
||||
|
||||
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 decodeMap(options: String): Map<String, String> {
|
||||
if (options.isEmpty()) {
|
||||
return emptyMap()
|
||||
@@ -200,115 +141,90 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
|
||||
|
||||
return map
|
||||
}
|
||||
}
|
||||
|
||||
class Kapt3ComponentRegistrar : ComponentRegistrar {
|
||||
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
|
||||
@Suppress("DEPRECATION")
|
||||
val aptMode = AptMode.parse(configuration.get(Kapt3ConfigurationKeys.APT_MODE) ?: configuration.get(Kapt3ConfigurationKeys.APT_ONLY))
|
||||
val contentRoots = configuration[CLIConfigurationKeys.CONTENT_ROOTS] ?: emptyList()
|
||||
|
||||
val optionsBuilder = (configuration[KAPT_OPTIONS] ?: KaptOptions.Builder()).apply {
|
||||
projectBaseDir = project.basePath?.let(::File)
|
||||
compileClasspath.addAll(contentRoots.filterIsInstance<JvmClasspathRoot>().map { it.file })
|
||||
javaSourceRoots.addAll(contentRoots.filterIsInstance<JavaSourceRoot>().map { it.file })
|
||||
classesOutputDir = classesOutputDir ?: configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY)
|
||||
}
|
||||
|
||||
val isVerbose = configuration.get(Kapt3ConfigurationKeys.VERBOSE_MODE) == "true"
|
||||
val infoAsWarnings = configuration.get(Kapt3ConfigurationKeys.INFO_AS_WARNINGS) == "true"
|
||||
val strictMode = configuration.get(Kapt3ConfigurationKeys.STRICT_MODE) == "true"
|
||||
val detectMemoryLeaks = configuration.get(Kapt3ConfigurationKeys.DETECT_MEMORY_LEAKS) != "false"
|
||||
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
?: PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, isVerbose)
|
||||
val logger = MessageCollectorBackedKaptLogger(isVerbose, infoAsWarnings, messageCollector)
|
||||
?: PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, optionsBuilder.flags.contains(KaptFlag.VERBOSE))
|
||||
|
||||
val logger = MessageCollectorBackedKaptLogger(
|
||||
optionsBuilder.flags.contains(KaptFlag.VERBOSE),
|
||||
optionsBuilder.flags.contains(KaptFlag.INFO_AS_WARNINGS),
|
||||
messageCollector
|
||||
)
|
||||
|
||||
if (!optionsBuilder.checkOptions(project, logger, configuration)) {
|
||||
return
|
||||
}
|
||||
|
||||
val options = optionsBuilder.build()
|
||||
|
||||
options.sourcesOutputDir.mkdirs()
|
||||
|
||||
if (options[KaptFlag.VERBOSE]) {
|
||||
logger.info(options.logString())
|
||||
}
|
||||
|
||||
val kapt3AnalysisCompletedHandlerExtension = ClasspathBasedKapt3Extension(options, logger, configuration)
|
||||
|
||||
AnalysisHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension)
|
||||
StorageComponentContainerContributor.registerExtension(project, KaptComponentContributor())
|
||||
}
|
||||
|
||||
private fun KaptOptions.Builder.checkOptions(project: MockProject, logger: KaptLogger, configuration: CompilerConfiguration): Boolean {
|
||||
fun abortAnalysis() = AnalysisHandlerExtension.registerExtension(project, AbortAnalysisHandlerExtension())
|
||||
|
||||
if (!Kapt.checkJavacComponentsAccess(logger)) {
|
||||
abortAnalysis()
|
||||
return
|
||||
if (classesOutputDir == null) {
|
||||
if (configuration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) {
|
||||
logger.error("Kapt does not support specifying JAR file outputs. Please specify the classes output directory explicitly.")
|
||||
abortAnalysis()
|
||||
return false
|
||||
} else {
|
||||
classesOutputDir = configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY)
|
||||
}
|
||||
}
|
||||
|
||||
val sourcesOutputDir = configuration.get(Kapt3ConfigurationKeys.SOURCE_OUTPUT_DIR)?.let(::File)
|
||||
val stubsOutputDir = configuration.get(Kapt3ConfigurationKeys.STUBS_OUTPUT_DIR)?.let(::File)
|
||||
val incrementalDataOutputDir = configuration.get(Kapt3ConfigurationKeys.INCREMENTAL_DATA_OUTPUT_DIR)?.let(::File)
|
||||
|
||||
val classFilesOutputDir = configuration.get(Kapt3ConfigurationKeys.CLASS_OUTPUT_DIR)?.let(::File)
|
||||
?: configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY)
|
||||
|
||||
if (classFilesOutputDir == null && configuration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) {
|
||||
logger.error("Kapt does not support specifying JAR file outputs. Please specify the classes output directory explicitly.")
|
||||
abortAnalysis()
|
||||
return
|
||||
}
|
||||
|
||||
val annotationProcessors = configuration.get(Kapt3ConfigurationKeys.ANNOTATION_PROCESSORS) ?: emptyList()
|
||||
|
||||
val apClasspath = configuration.get(ANNOTATION_PROCESSOR_CLASSPATH)?.map(::File) ?: emptyList()
|
||||
|
||||
if (apClasspath.isEmpty()) {
|
||||
if (processingClasspath.isEmpty()) {
|
||||
// Skip annotation processing if no annotation processors were provided
|
||||
if (aptMode != AptMode.WITH_COMPILATION) {
|
||||
if (mode != AptMode.WITH_COMPILATION) {
|
||||
abortAnalysis()
|
||||
}
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
if (sourcesOutputDir == null || classFilesOutputDir == null || stubsOutputDir == null) {
|
||||
if (aptMode != AptMode.WITH_COMPILATION) {
|
||||
if (sourcesOutputDir == null || classesOutputDir == null || stubsOutputDir == null) {
|
||||
if (mode != AptMode.WITH_COMPILATION) {
|
||||
val nonExistentOptionName = when {
|
||||
sourcesOutputDir == null -> "Sources output directory"
|
||||
classFilesOutputDir == null -> "Classes output directory"
|
||||
classesOutputDir == null -> "Classes output directory"
|
||||
stubsOutputDir == null -> "Stubs output directory"
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
val moduleName = configuration.get(CommonConfigurationKeys.MODULE_NAME)
|
||||
?: configuration.get(JVMConfigurationKeys.MODULES).orEmpty().joinToString()
|
||||
?: configuration.get(JVMConfigurationKeys.MODULES).orEmpty().joinToString()
|
||||
|
||||
logger.warn("$nonExistentOptionName is not specified for $moduleName, skipping annotation processing")
|
||||
abortAnalysis()
|
||||
}
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
val apOptions = decodeMap(configuration.get(APT_OPTIONS).orEmpty()).toMutableMap()
|
||||
configuration.get(APT_OPTION)?.let { apOptions += it }
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
val javacOptions = decodeMap(configuration.get(JAVAC_CLI_OPTIONS).orEmpty()).toMutableMap()
|
||||
configuration.get(JAVAC_OPTION)?.let { javacOptions += it }
|
||||
|
||||
sourcesOutputDir.mkdirs()
|
||||
|
||||
val contentRoots = configuration[CLIConfigurationKeys.CONTENT_ROOTS] ?: emptyList()
|
||||
|
||||
val compileClasspath = contentRoots.filterIsInstance<JvmClasspathRoot>().map { it.file }
|
||||
|
||||
val javaSourceRoots = contentRoots.filterIsInstance<JavaSourceRoot>().map { it.file }
|
||||
|
||||
val useLightAnalysis = configuration.get(Kapt3ConfigurationKeys.USE_LIGHT_ANALYSIS) != "false"
|
||||
val correctErrorTypes = configuration.get(Kapt3ConfigurationKeys.CORRECT_ERROR_TYPES) == "true"
|
||||
val mapDiagnosticLocations = configuration.get(Kapt3ConfigurationKeys.MAP_DIAGNOSTIC_LOCATIONS) == "true"
|
||||
|
||||
val paths = KaptPaths(
|
||||
project.basePath?.let(::File),
|
||||
compileClasspath, apClasspath, javaSourceRoots, sourcesOutputDir, classFilesOutputDir,
|
||||
stubsOutputDir, incrementalDataOutputDir
|
||||
)
|
||||
|
||||
if (isVerbose) {
|
||||
logger.info("Kapt3 is enabled.")
|
||||
logger.info("Annotation processing mode: $aptMode")
|
||||
logger.info("Use light analysis: $useLightAnalysis")
|
||||
logger.info("Correct error types: $correctErrorTypes")
|
||||
logger.info("Map diagnostic locations: $mapDiagnosticLocations")
|
||||
logger.info("Info as warnings: $infoAsWarnings")
|
||||
logger.info("Strict mode: $strictMode")
|
||||
paths.log(logger)
|
||||
logger.info("Annotation processors: " + annotationProcessors.joinToString())
|
||||
logger.info("Javac options: $apOptions")
|
||||
logger.info("AP options: $apOptions")
|
||||
if (!Kapt.checkJavacComponentsAccess(logger)) {
|
||||
abortAnalysis()
|
||||
return false
|
||||
}
|
||||
|
||||
val kapt3AnalysisCompletedHandlerExtension = ClasspathBasedKapt3Extension(
|
||||
paths, apOptions, javacOptions, annotationProcessors,
|
||||
aptMode, useLightAnalysis, correctErrorTypes, mapDiagnosticLocations, strictMode, detectMemoryLeaks,
|
||||
System.currentTimeMillis(), logger, configuration
|
||||
)
|
||||
|
||||
AnalysisHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension)
|
||||
StorageComponentContainerContributor.registerExtension(project, KaptComponentContributor())
|
||||
return true
|
||||
}
|
||||
|
||||
class KaptComponentContributor : StorageComponentContainerContributor {
|
||||
@@ -327,47 +243,23 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
|
||||
* */
|
||||
private class AbortAnalysisHandlerExtension : AnalysisHandlerExtension {
|
||||
override fun doAnalysis(
|
||||
project: Project,
|
||||
module: ModuleDescriptor,
|
||||
projectContext: ProjectContext,
|
||||
files: Collection<KtFile>,
|
||||
bindingTrace: BindingTrace,
|
||||
componentProvider: ComponentProvider
|
||||
project: Project,
|
||||
module: ModuleDescriptor,
|
||||
projectContext: ProjectContext,
|
||||
files: Collection<KtFile>,
|
||||
bindingTrace: BindingTrace,
|
||||
componentProvider: ComponentProvider
|
||||
): AnalysisResult? {
|
||||
return AnalysisResult.success(bindingTrace.bindingContext, module, shouldGenerateCode = false)
|
||||
}
|
||||
|
||||
override fun analysisCompleted(
|
||||
project: Project,
|
||||
module: ModuleDescriptor,
|
||||
bindingTrace: BindingTrace,
|
||||
files: Collection<KtFile>
|
||||
project: Project,
|
||||
module: ModuleDescriptor,
|
||||
bindingTrace: BindingTrace,
|
||||
files: Collection<KtFile>
|
||||
): AnalysisResult? {
|
||||
return AnalysisResult.success(bindingTrace.bindingContext, module, shouldGenerateCode = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class AptMode(val optionName: String) {
|
||||
WITH_COMPILATION("compile"),
|
||||
STUBS_AND_APT("stubsAndApt"),
|
||||
STUBS_ONLY("stubs"),
|
||||
APT_ONLY("apt");
|
||||
|
||||
val runAnnotationProcessing
|
||||
get() = this != STUBS_ONLY
|
||||
|
||||
val generateStubs
|
||||
get() = this != APT_ONLY
|
||||
|
||||
companion object {
|
||||
// Supports both deprecated APT_ONLY and new APT_MODE options
|
||||
fun parse(mode: String?): AptMode {
|
||||
return when (mode) {
|
||||
"true" -> STUBS_AND_APT
|
||||
"false" -> WITH_COMPILATION
|
||||
else -> AptMode.values().firstOrNull { it.optionName == mode } ?: WITH_COMPILATION
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-7
@@ -19,9 +19,9 @@ package org.jetbrains.kotlin.kapt3
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.sun.tools.javac.tree.TreeMaker
|
||||
import com.sun.tools.javac.util.Context
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptOptions
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptContext
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptPaths
|
||||
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
|
||||
import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -29,18 +29,15 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.tree.ClassNode
|
||||
|
||||
class KaptContextForStubGeneration(
|
||||
paths: KaptPaths,
|
||||
options: KaptOptions,
|
||||
withJdk: Boolean,
|
||||
logger: KaptLogger,
|
||||
val project: Project,
|
||||
val bindingContext: BindingContext,
|
||||
val compiledClasses: List<ClassNode>,
|
||||
val origins: Map<Any, JvmDeclarationOrigin>,
|
||||
val generationState: GenerationState,
|
||||
mapDiagnosticLocations: Boolean,
|
||||
processorOptions: Map<String, String>,
|
||||
javacOptions: Map<String, String> = emptyMap()
|
||||
) : KaptContext(paths, withJdk, logger, mapDiagnosticLocations, processorOptions, javacOptions) {
|
||||
val generationState: GenerationState
|
||||
) : KaptContext(options, withJdk, logger) {
|
||||
private val treeMaker = TreeMaker.instance(context)
|
||||
|
||||
override fun preregisterTreeMaker(context: Context) {
|
||||
|
||||
+9
-9
@@ -24,6 +24,7 @@ import com.sun.tools.javac.tree.JCTree.*
|
||||
import com.sun.tools.javac.tree.TreeMaker
|
||||
import com.sun.tools.javac.tree.TreeScanner
|
||||
import kotlinx.kapt.KaptIgnored
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptFlag
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
@@ -63,12 +64,7 @@ import java.io.File
|
||||
import javax.lang.model.element.ElementKind
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
|
||||
class ClassFileToSourceStubConverter(
|
||||
val kaptContext: KaptContextForStubGeneration,
|
||||
val generateNonExistentClass: Boolean,
|
||||
val correctErrorTypes: Boolean,
|
||||
val strictMode: Boolean
|
||||
) {
|
||||
class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGeneration, val generateNonExistentClass: Boolean) {
|
||||
private companion object {
|
||||
private const val VISIBILITY_MODIFIERS = (Opcodes.ACC_PUBLIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED).toLong()
|
||||
private const val MODALITY_MODIFIERS = (Opcodes.ACC_FINAL or Opcodes.ACC_ABSTRACT).toLong()
|
||||
@@ -95,15 +91,19 @@ class ClassFileToSourceStubConverter(
|
||||
|
||||
private val JAVA_KEYWORD_FILTER_REGEX = "[a-z]+".toRegex()
|
||||
|
||||
@Suppress("UselessCallOnNotNull") // nullable toString(), KT-27724
|
||||
private val JAVA_KEYWORDS = Tokens.TokenKind.values()
|
||||
.filter { JAVA_KEYWORD_FILTER_REGEX.matches(it.toString().orEmpty()) }
|
||||
.mapTo(hashSetOf(), Any::toString)
|
||||
}
|
||||
|
||||
private val _bindings = mutableMapOf<String, KaptJavaFileObject>()
|
||||
private val correctErrorTypes = kaptContext.options[KaptFlag.CORRECT_ERROR_TYPES]
|
||||
private val strictMode = kaptContext.options[KaptFlag.STRICT]
|
||||
|
||||
private val mutableBindings = mutableMapOf<String, KaptJavaFileObject>()
|
||||
|
||||
val bindings: Map<String, KaptJavaFileObject>
|
||||
get() = _bindings
|
||||
get() = mutableBindings
|
||||
|
||||
private val typeMapper
|
||||
get() = kaptContext.generationState.typeMapper
|
||||
@@ -193,7 +193,7 @@ class ClassFileToSourceStubConverter(
|
||||
|
||||
KaptJavaFileObject(topLevel, classDeclaration).apply {
|
||||
topLevel.sourcefile = this
|
||||
_bindings[clazz.name] = this
|
||||
mutableBindings[clazz.name] = this
|
||||
}
|
||||
|
||||
postProcess(topLevel)
|
||||
|
||||
+10
-4
@@ -5,10 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.kapt3.util
|
||||
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptFlag
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptFlags
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer.PLAIN_FULL_PATHS
|
||||
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
|
||||
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
|
||||
import java.io.PrintWriter
|
||||
@@ -16,16 +18,20 @@ import java.io.StringWriter
|
||||
|
||||
class MessageCollectorBackedKaptLogger(
|
||||
override val isVerbose: Boolean,
|
||||
infoAsWarnings: Boolean = true,
|
||||
val messageCollector: MessageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, isVerbose)
|
||||
isInfoAsWarnings: Boolean,
|
||||
val messageCollector: MessageCollector = defaultMessageCollector(isVerbose)
|
||||
) : KaptLogger {
|
||||
constructor(flags: KaptFlags, messageCollector: MessageCollector = defaultMessageCollector(flags[KaptFlag.VERBOSE]))
|
||||
: this(flags[KaptFlag.VERBOSE], flags[KaptFlag.INFO_AS_WARNINGS], messageCollector)
|
||||
|
||||
private companion object {
|
||||
const val PREFIX = "[kapt] "
|
||||
fun defaultMessageCollector(isVerbose: Boolean) = PrintingMessageCollector(System.err, PLAIN_FULL_PATHS, isVerbose)
|
||||
}
|
||||
|
||||
override val errorWriter = makeWriter(ERROR)
|
||||
override val warnWriter = makeWriter(STRONG_WARNING)
|
||||
override val infoWriter = makeWriter(if (infoAsWarnings) WARNING else INFO)
|
||||
override val infoWriter = makeWriter(if (isInfoAsWarnings) WARNING else INFO)
|
||||
|
||||
override fun info(message: String) {
|
||||
if (isVerbose) {
|
||||
|
||||
+24
-34
@@ -16,8 +16,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.kapt3.test
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.base.kapt3.DetectMemoryLeaksMode
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptOptions
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderMode
|
||||
import org.jetbrains.kotlin.codegen.CodegenTestCase
|
||||
@@ -25,9 +26,7 @@ import org.jetbrains.kotlin.codegen.GenerationUtils
|
||||
import org.jetbrains.kotlin.codegen.OriginCollectingClassBuilderFactory
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.kapt3.*
|
||||
import org.jetbrains.kotlin.kapt3.AptMode.STUBS_AND_APT
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptContext
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptPaths
|
||||
import org.jetbrains.kotlin.kapt3.base.LoadedProcessors
|
||||
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
|
||||
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter
|
||||
@@ -59,12 +58,11 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
|
||||
private var _processors: List<Processor>? = null
|
||||
private val processors get() = _processors!!
|
||||
|
||||
private var _options: Map<String, String>? = null
|
||||
private val options get() = _options!!
|
||||
private var mutableOptions: Map<String, String>? = null
|
||||
|
||||
override fun tearDown() {
|
||||
_processors = null
|
||||
_options = null
|
||||
mutableOptions = null
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
@@ -82,7 +80,7 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
|
||||
process: (Set<TypeElement>, RoundEnvironment, ProcessingEnvironment) -> Unit,
|
||||
vararg supportedAnnotations: String
|
||||
) {
|
||||
this._options = options
|
||||
this.mutableOptions = options
|
||||
|
||||
val ktFileName = File(TEST_DATA_DIR, "$name.kt")
|
||||
var started = false
|
||||
@@ -128,18 +126,25 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
|
||||
val javaSources = javaFilesDir?.let { arrayOf(it) } ?: emptyArray()
|
||||
|
||||
val txtFile = File(wholeFile.parentFile, wholeFile.nameWithoutExtension + ".it.txt")
|
||||
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
|
||||
val stubsDir = Files.createTempDirectory("kaptStubs").toFile()
|
||||
val incrementalDataDir = Files.createTempDirectory("kaptIncrementalData").toFile()
|
||||
|
||||
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL, *javaSources)
|
||||
|
||||
val project = myEnvironment.project
|
||||
val kapt3Extension = Kapt3ExtensionForTests(
|
||||
project, processors, javaSources.toList(), sourceOutputDir, this.options,
|
||||
stubsOutputDir = stubsDir, incrementalDataOutputDir = incrementalDataDir
|
||||
)
|
||||
|
||||
val options = KaptOptions.Builder().apply {
|
||||
projectBaseDir = project.basePath?.let(::File)
|
||||
compileClasspath.addAll(PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath)
|
||||
javaSourceRoots.addAll(javaSources)
|
||||
|
||||
sourcesOutputDir = Files.createTempDirectory("kaptRunner").toFile()
|
||||
classesOutputDir = sourcesOutputDir
|
||||
stubsOutputDir = Files.createTempDirectory("kaptStubs").toFile()
|
||||
incrementalDataOutputDir = Files.createTempDirectory("kaptIncrementalData").toFile()
|
||||
|
||||
mutableOptions?.let { processingOptions.putAll(it) }
|
||||
detectMemoryLeaks = DetectMemoryLeaksMode.NONE
|
||||
}.build()
|
||||
|
||||
val kapt3Extension = Kapt3ExtensionForTests(options, processors)
|
||||
AnalysisHandlerExtension.registerExtension(project, kapt3Extension)
|
||||
|
||||
try {
|
||||
@@ -155,28 +160,13 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
|
||||
|
||||
KotlinTestUtils.assertEqualsToFile(txtFile, actual)
|
||||
} finally {
|
||||
sourceOutputDir.deleteRecursively()
|
||||
incrementalDataDir.deleteRecursively()
|
||||
options.sourcesOutputDir.deleteRecursively()
|
||||
options.incrementalDataOutputDir?.deleteRecursively()
|
||||
}
|
||||
}
|
||||
|
||||
protected class Kapt3ExtensionForTests(
|
||||
project: Project,
|
||||
private val processors: List<Processor>,
|
||||
javaSourceRoots: List<File>,
|
||||
outputDir: File,
|
||||
options: Map<String, String>,
|
||||
stubsOutputDir: File,
|
||||
incrementalDataOutputDir: File
|
||||
) : AbstractKapt3Extension(
|
||||
KaptPaths(
|
||||
project.basePath?.let(::File),
|
||||
PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath,
|
||||
emptyList(), javaSourceRoots, outputDir, outputDir, stubsOutputDir, incrementalDataOutputDir
|
||||
), options, emptyMap(), emptyList(), STUBS_AND_APT, System.currentTimeMillis(),
|
||||
MessageCollectorBackedKaptLogger(true),
|
||||
correctErrorTypes = true, mapDiagnosticLocations = true, strictMode = true, detectMemoryLeaks = false,
|
||||
compilerConfiguration = CompilerConfiguration.EMPTY
|
||||
protected class Kapt3ExtensionForTests(options: KaptOptions, private val processors: List<Processor>) : AbstractKapt3Extension(
|
||||
options, MessageCollectorBackedKaptLogger(options), compilerConfiguration = CompilerConfiguration.EMPTY
|
||||
) {
|
||||
internal var savedStubs: String? = null
|
||||
internal var savedBindings: Map<String, KaptJavaFileObject>? = null
|
||||
|
||||
+55
-30
@@ -24,6 +24,9 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit
|
||||
import com.sun.tools.javac.util.JCDiagnostic
|
||||
import com.sun.tools.javac.util.Log
|
||||
import junit.framework.ComparisonFailure
|
||||
import org.jetbrains.kotlin.base.kapt3.DetectMemoryLeaksMode
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptFlag
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptOptions
|
||||
import org.jetbrains.kotlin.checkers.CheckerTestUtil
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
|
||||
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
|
||||
@@ -35,7 +38,6 @@ import org.jetbrains.kotlin.kapt.base.test.JavaKaptContextTest
|
||||
import org.jetbrains.kotlin.kapt3.*
|
||||
import org.jetbrains.kotlin.kapt3.Kapt3ComponentRegistrar.KaptComponentContributor
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptContext
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptPaths
|
||||
import org.jetbrains.kotlin.kapt3.base.doAnnotationProcessing
|
||||
import org.jetbrains.kotlin.kapt3.base.javac.KaptJavaLog
|
||||
import org.jetbrains.kotlin.kapt3.base.parseJavaFiles
|
||||
@@ -57,7 +59,6 @@ import java.nio.file.Files
|
||||
import java.util.*
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
|
||||
|
||||
abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
||||
companion object {
|
||||
const val FILE_SEPARATOR = "\n\n////////////////////\n\n"
|
||||
@@ -67,8 +68,14 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
||||
val messageCollector = PrintingMessageCollector(ERR_PRINT_STREAM, MessageRenderer.PLAIN_FULL_PATHS, false)
|
||||
}
|
||||
|
||||
val kaptFlags = mutableListOf<KaptFlag>()
|
||||
private val tempFiles = mutableListOf<File>()
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
kaptFlags.clear()
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
ERR_BYTE_STREAM.reset()
|
||||
super.tearDown()
|
||||
@@ -81,12 +88,15 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTempDir(prefix: String): File {
|
||||
return Files.createTempDirectory(prefix).toFile().apply { tempFiles += this }
|
||||
}
|
||||
|
||||
override fun loadMultiFiles(files: List<TestFile>) {
|
||||
val project = myEnvironment.project
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
|
||||
val tmpDir = Files.createTempDirectory("kaptTest").toFile()
|
||||
tempFiles += tmpDir
|
||||
val tmpDir = createTempDir("kaptTest")
|
||||
|
||||
val ktFiles = ArrayList<KtFile>(files.size)
|
||||
for (file in files.sorted()) {
|
||||
@@ -118,7 +128,7 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
||||
val classBuilderFactory = OriginCollectingClassBuilderFactory(ClassBuilderMode.KAPT3)
|
||||
val generationState = GenerationUtils.compileFiles(myFiles.psiFiles, myEnvironment, classBuilderFactory)
|
||||
|
||||
val logger = MessageCollectorBackedKaptLogger(isVerbose = true, messageCollector = messageCollector)
|
||||
val logger = MessageCollectorBackedKaptLogger(isVerbose = true, isInfoAsWarnings = false, messageCollector = messageCollector)
|
||||
|
||||
val javacOptions = wholeFile.getOptionValues("JAVAC_OPTION")
|
||||
.map { opt ->
|
||||
@@ -130,21 +140,25 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
||||
var kaptContext: KaptContext? = null
|
||||
|
||||
try {
|
||||
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
|
||||
val options = KaptOptions.Builder().apply {
|
||||
projectBaseDir = generationState.project.basePath?.let(::File)
|
||||
compileClasspath.addAll(PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath)
|
||||
|
||||
val paths = KaptPaths(
|
||||
generationState.project.basePath?.let(::File),
|
||||
compileClasspath = PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath,
|
||||
annotationProcessingClasspath = emptyList(), javaSourceRoots = emptyList(),
|
||||
sourcesOutputDir = sourceOutputDir, classFilesOutputDir = sourceOutputDir,
|
||||
stubsOutputDir = sourceOutputDir, incrementalDataOutputDir = sourceOutputDir
|
||||
)
|
||||
sourcesOutputDir = createTempDir("kaptRunner")
|
||||
classesOutputDir = sourcesOutputDir
|
||||
stubsOutputDir = sourcesOutputDir
|
||||
incrementalDataOutputDir = sourcesOutputDir
|
||||
|
||||
this.javacOptions.putAll(javacOptions)
|
||||
flags.addAll(kaptFlags)
|
||||
|
||||
detectMemoryLeaks = DetectMemoryLeaksMode.NONE
|
||||
}.build()
|
||||
|
||||
kaptContext = KaptContextForStubGeneration(
|
||||
paths, true,
|
||||
logger, generationState.project, generationState.bindingContext, classBuilderFactory.compiledClasses,
|
||||
classBuilderFactory.origins, generationState, mapDiagnosticLocations = true,
|
||||
processorOptions = emptyMap(), javacOptions = javacOptions
|
||||
options, true, logger,
|
||||
generationState.project, generationState.bindingContext, classBuilderFactory.compiledClasses,
|
||||
classBuilderFactory.origins, generationState
|
||||
)
|
||||
|
||||
javaFiles = files
|
||||
@@ -165,11 +179,9 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
||||
protected fun convert(
|
||||
kaptContext: KaptContextForStubGeneration,
|
||||
javaFiles: List<File>,
|
||||
generateNonExistentClass: Boolean,
|
||||
correctErrorTypes: Boolean,
|
||||
strictMode: Boolean
|
||||
generateNonExistentClass: Boolean
|
||||
): JavacList<JCCompilationUnit> {
|
||||
val converter = ClassFileToSourceStubConverter(kaptContext, generateNonExistentClass, correctErrorTypes, strictMode)
|
||||
val converter = ClassFileToSourceStubConverter(kaptContext, generateNonExistentClass)
|
||||
|
||||
val kaptStubs = converter.convert()
|
||||
val convertedFiles = kaptStubs.map { stub ->
|
||||
@@ -245,18 +257,28 @@ open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test(
|
||||
fun testSuppressWarning() {}
|
||||
|
||||
override fun doTest(filePath: String) {
|
||||
val wholeFile = File(filePath)
|
||||
|
||||
kaptFlags.add(KaptFlag.MAP_DIAGNOSTIC_LOCATIONS)
|
||||
|
||||
if (wholeFile.isOptionSet("CORRECT_ERROR_TYPES")) {
|
||||
kaptFlags.add(KaptFlag.CORRECT_ERROR_TYPES)
|
||||
}
|
||||
|
||||
if (wholeFile.isOptionSet("STRICT_MODE")) {
|
||||
kaptFlags.add(KaptFlag.STRICT)
|
||||
}
|
||||
|
||||
super.doTest(filePath)
|
||||
doTestWithJdk9(AbstractClassFileToSourceStubConverterTest::class.java, filePath)
|
||||
}
|
||||
|
||||
override fun check(kaptContext: KaptContextForStubGeneration, javaFiles: List<File>, txtFile: File, wholeFile: File) {
|
||||
val generateNonExistentClass = wholeFile.isOptionSet("NON_EXISTENT_CLASS")
|
||||
val correctErrorTypes = wholeFile.isOptionSet("CORRECT_ERROR_TYPES")
|
||||
val validate = !wholeFile.isOptionSet("NO_VALIDATION")
|
||||
val strictMode = wholeFile.isOptionSet("STRICT_MODE")
|
||||
val expectedErrors = wholeFile.getRawOptionValues(EXPECTED_ERROR).sorted()
|
||||
|
||||
val convertedFiles = convert(kaptContext, javaFiles, generateNonExistentClass, correctErrorTypes, strictMode)
|
||||
val convertedFiles = convert(kaptContext, javaFiles, generateNonExistentClass)
|
||||
|
||||
kaptContext.javaLog.interceptorData.files = convertedFiles.map { it.sourceFile to it }.toMap()
|
||||
if (validate) kaptContext.compiler.enterTrees(convertedFiles)
|
||||
@@ -309,19 +331,22 @@ open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test(
|
||||
}
|
||||
|
||||
abstract class AbstractKotlinKaptContextTest : AbstractKotlinKapt3Test() {
|
||||
override fun check(kaptContext: KaptContextForStubGeneration, javaFiles: List<File>, txtFile: File, wholeFile: File) {
|
||||
val compilationUnits = convert(
|
||||
kaptContext, javaFiles,
|
||||
generateNonExistentClass = false, correctErrorTypes = true, strictMode = false
|
||||
)
|
||||
override fun doTest(filePath: String?) {
|
||||
kaptFlags.add(KaptFlag.CORRECT_ERROR_TYPES)
|
||||
kaptFlags.add(KaptFlag.STRICT)
|
||||
kaptFlags.add(KaptFlag.MAP_DIAGNOSTIC_LOCATIONS)
|
||||
super.doTest(filePath)
|
||||
}
|
||||
|
||||
override fun check(kaptContext: KaptContextForStubGeneration, javaFiles: List<File>, txtFile: File, wholeFile: File) {
|
||||
val compilationUnits = convert(kaptContext, javaFiles, generateNonExistentClass = false)
|
||||
kaptContext.doAnnotationProcessing(
|
||||
emptyList(),
|
||||
listOf(JavaKaptContextTest.simpleProcessor()),
|
||||
additionalSources = compilationUnits
|
||||
)
|
||||
|
||||
val stubJavaFiles = kaptContext.paths.sourcesOutputDir.walkTopDown().filter { it.isFile && it.extension == "java" }
|
||||
val stubJavaFiles = kaptContext.options.sourcesOutputDir.walkTopDown().filter { it.isFile && it.extension == "java" }
|
||||
val actualRaw = stubJavaFiles.sortedBy { it.name }.joinToString(FILE_SEPARATOR) { it.name + ":\n\n" + it.readText() }
|
||||
val actual = StringUtil.convertLineSeparators(actualRaw.trim({ it <= ' ' })).trimTrailingWhitespacesAndAddNewlineAtEOF()
|
||||
KotlinTestUtils.assertEqualsToFile(txtFile, actual)
|
||||
|
||||
+2
-2
@@ -96,8 +96,8 @@ class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), Java9T
|
||||
test(name, "test.MyAnnotation") { _, _, _ ->
|
||||
val kaptExtension = AnalysisHandlerExtension.getInstances(myEnvironment.project).firstIsInstance<Kapt3ExtensionForTests>()
|
||||
|
||||
val stubsOutputDir = kaptExtension.paths.stubsOutputDir
|
||||
val incrementalDataOutputDir = kaptExtension.paths.incrementalDataOutputDir
|
||||
val stubsOutputDir = kaptExtension.options.stubsOutputDir
|
||||
val incrementalDataOutputDir = kaptExtension.options.incrementalDataOutputDir
|
||||
|
||||
val bindings = kaptExtension.savedBindings!!
|
||||
|
||||
|
||||
Reference in New Issue
Block a user