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:
Yan Zhulanow
2018-11-06 15:30:34 +09:00
parent a621171d9b
commit 7e4069f114
17 changed files with 457 additions and 489 deletions
@@ -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
+8 -11
View File
@@ -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()
+1 -4
View File
@@ -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
}
}
}
}
@@ -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) {
@@ -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)
@@ -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) {
@@ -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
@@ -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)
@@ -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!!