From 7e4069f11491396e8a11b1f9f4a65aa4e2ea330f Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Tue, 6 Nov 2018 15:30:34 +0900 Subject: [PATCH] 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. --- .../maven/kapt/KaptJVMCompilerMojo.java | 2 +- .../org/jetbrains/kotlin/kapt3/base/Kapt.kt | 31 +- .../kotlin/kapt3/base/KaptContext.kt | 35 +- .../kotlin/kapt3/base/KaptOptions.kt | 144 ++++++++ .../jetbrains/kotlin/kapt3/base/KaptPaths.kt | 45 --- .../kotlin/kapt3/base/ProcessorLoader.kt | 13 +- .../kapt3-base/test/JavaKaptContextTest.kt | 34 +- .../kapt3/kapt3-base/test/KaptPathsTest.kt | 19 +- plugins/kapt3/kapt3-cli/src/KaptCliOption.kt | 5 +- .../jetbrains/kotlin/kapt3/Kapt3Extension.kt | 80 ++-- .../org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt | 348 ++++++------------ .../kapt3/KaptContextForStubGeneration.kt | 11 +- .../stubs/ClassFileToSourceStubConverter.kt | 18 +- .../util/MessageCollectorBackedKaptLogger.kt | 14 +- .../AbstractKotlinKapt3IntegrationTest.kt | 58 ++- .../kapt3/test/AbstractKotlinKapt3Test.kt | 85 +++-- .../kapt3/test/KotlinKapt3IntegrationTests.kt | 4 +- 17 files changed, 457 insertions(+), 489 deletions(-) create mode 100644 plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptOptions.kt delete mode 100644 plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptPaths.kt diff --git a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/KaptJVMCompilerMojo.java b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/KaptJVMCompilerMojo.java index b14696af70d..0ced57a7e60 100644 --- a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/KaptJVMCompilerMojo.java +++ b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/KaptJVMCompilerMojo.java @@ -94,7 +94,7 @@ public class KaptJVMCompilerMojo extends K2JVMCompileMojo { ) { List 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)); diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/Kapt.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/Kapt.kt index d64dd1f734a..e8efcaeb7e7 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/Kapt.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/Kapt.kt @@ -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, - processorOptions: Map, - javacOptions: Map - ): Boolean { - val logger = WriterBackedKaptLogger(isVerbose) + fun kaptFlags(rawFlags: Set): 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()) diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptContext.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptContext.kt index a4d8d8ccd51..77321a80323 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptContext.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptContext.kt @@ -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, - javacOptions: Map = 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 { 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) } } diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptOptions.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptOptions.kt new file mode 100644 index 00000000000..f2274d725e2 --- /dev/null +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptOptions.kt @@ -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, + val javaSourceRoots: List, + + val sourcesOutputDir: File, + val classesOutputDir: File, + val stubsOutputDir: File, + val incrementalDataOutputDir: File?, + + val processingClasspath: List, + val processors: List, + + val processingOptions: Map, + val javacOptions: Map, + + 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 = mutableListOf() + val javaSourceRoots: MutableList = mutableListOf() + + var sourcesOutputDir: File? = null + var classesOutputDir: File? = null + var stubsOutputDir: File? = null + var incrementalDataOutputDir: File? = null + + val processingClasspath: MutableList = mutableListOf() + val processors: MutableList = mutableListOf() + + val processingOptions: MutableMap = mutableMapOf() + val javacOptions: MutableMap = mutableMapOf() + + val flags: MutableSet = 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) = 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 { + 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") +} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptPaths.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptPaths.kt deleted file mode 100644 index 209bf146bb3..00000000000 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptPaths.kt +++ /dev/null @@ -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, - annotationProcessingClasspath: List, - val javaSourceRoots: List, - val sourcesOutputDir: File, - val classFilesOutputDir: File, - val stubsOutputDir: File, - val incrementalDataOutputDir: File? -) { - val compileClasspath = compileClasspath.distinct() - val annotationProcessingClasspath = annotationProcessingClasspath.distinct() - - fun collectJavaSourceFiles(): List { - 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") -} diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/ProcessorLoader.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/ProcessorLoader.kt index 6969dd686db..4387f601bf4 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/ProcessorLoader.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/ProcessorLoader.kt @@ -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, val classLoader: ClassLoader) -open class ProcessorLoader( - private val paths: KaptPaths, - private val annotationProcessorFqNames: List, - 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) diff --git a/plugins/kapt3/kapt3-base/test/JavaKaptContextTest.kt b/plugins/kapt3/kapt3-base/test/JavaKaptContextTest.kt index c601389ffa4..9ea8532bcfe 100644 --- a/plugins/kapt3/kapt3-base/test/JavaKaptContextTest.kt +++ b/plugins/kapt3/kapt3-base/test/JavaKaptContextTest.kt @@ -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 diff --git a/plugins/kapt3/kapt3-base/test/KaptPathsTest.kt b/plugins/kapt3/kapt3-base/test/KaptPathsTest.kt index 3676ffdae15..48f02c8e816 100644 --- a/plugins/kapt3/kapt3-base/test/KaptPathsTest.kt +++ b/plugins/kapt3/kapt3-base/test/KaptPathsTest.kt @@ -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() diff --git a/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt b/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt index 3037f4de7d2..2ba1b60d823 100644 --- a/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt +++ b/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt @@ -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 diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt index fd3a7cc3113..5ba95571f1f 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt @@ -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, - javacOptions: Map, - annotationProcessorFqNames: List, - 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 { return ServiceLoaderLite.loadImplementations(Processor::class.java, classLoader) } @@ -122,19 +112,12 @@ class ClasspathBasedKapt3Extension( } abstract class AbstractKapt3Extension( - val paths: KaptPaths, - private val options: Map, - private val javacOptions: Map, - val annotationProcessorFqNames: List, - 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 ?: "" } } 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, 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)) { diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt index 884cefcd8c6..7fd6b45d962 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt @@ -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 = - CompilerConfigurationKey.create(SOURCE_OUTPUT_DIR_OPTION.description) - - val CLASS_OUTPUT_DIR: CompilerConfigurationKey = - CompilerConfigurationKey.create(CLASS_OUTPUT_DIR_OPTION.description) - - val STUBS_OUTPUT_DIR: CompilerConfigurationKey = - CompilerConfigurationKey.create(STUBS_OUTPUT_DIR_OPTION.description) - - val INCREMENTAL_DATA_OUTPUT_DIR: CompilerConfigurationKey = - CompilerConfigurationKey.create(INCREMENTAL_DATA_OUTPUT_DIR_OPTION.description) - - val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey> = - CompilerConfigurationKey.create>(ANNOTATION_PROCESSOR_CLASSPATH_OPTION.description) - - @Suppress("DEPRECATION") - @Deprecated("Use APT_OPTION instead.") - val APT_OPTIONS: CompilerConfigurationKey = - CompilerConfigurationKey.create(APT_OPTIONS_OPTION.description) - - val APT_OPTION: CompilerConfigurationKey> = - CompilerConfigurationKey.create>(APT_OPTION_OPTION.description) - - @Suppress("DEPRECATION") - @Deprecated("Use JAVAC_OPTION instead.") - val JAVAC_CLI_OPTIONS: CompilerConfigurationKey = - CompilerConfigurationKey.create(JAVAC_CLI_OPTIONS_OPTION.description) - - val JAVAC_OPTION: CompilerConfigurationKey> = - CompilerConfigurationKey.create>(JAVAC_OPTION_OPTION.description) - - val ANNOTATION_PROCESSORS: CompilerConfigurationKey> = - CompilerConfigurationKey.create>(ANNOTATION_PROCESSORS_OPTION.description) - - val VERBOSE_MODE: CompilerConfigurationKey = - CompilerConfigurationKey.create(VERBOSE_MODE_OPTION.description) - - val INFO_AS_WARNINGS: CompilerConfigurationKey = - CompilerConfigurationKey.create(INFO_AS_WARNINGS_OPTION.description) - - @Suppress("DEPRECATION") - @Deprecated("Use APT_MODE instead.") - val APT_ONLY: CompilerConfigurationKey = - CompilerConfigurationKey.create(APT_ONLY_OPTION.description) - - val APT_MODE: CompilerConfigurationKey = - CompilerConfigurationKey.create(APT_MODE_OPTION.description) - - val USE_LIGHT_ANALYSIS: CompilerConfigurationKey = - CompilerConfigurationKey.create(USE_LIGHT_ANALYSIS_OPTION.description) - - val CORRECT_ERROR_TYPES: CompilerConfigurationKey = - CompilerConfigurationKey.create(CORRECT_ERROR_TYPES_OPTION.description) - - val MAP_DIAGNOSTIC_LOCATIONS: CompilerConfigurationKey = - CompilerConfigurationKey.create(MAP_DIAGNOSTIC_LOCATIONS_OPTION.description) - - val STRICT_MODE: CompilerConfigurationKey = - CompilerConfigurationKey.create(STRICT_MODE_OPTION.description) - - val DETECT_MEMORY_LEAKS: CompilerConfigurationKey = - CompilerConfigurationKey.create(DETECT_MEMORY_LEAKS_OPTION.description) -} +private val KAPT_OPTIONS = CompilerConfigurationKey.create("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 setSelector(values: Array, 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(), value) { detectMemoryLeaks = it } + APT_MODE_OPTION -> setSelector(enumValues(), 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>, - 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) ?: oldMap.toMutableMap() - - newMap[keyValueDecoded[0]] = keyValueDecoded[1] - put(key, newMap) - } -} - -class Kapt3ComponentRegistrar : ComponentRegistrar { private fun decodeMap(options: String): Map { 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().map { it.file }) + javaSourceRoots.addAll(contentRoots.filterIsInstance().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().map { it.file } - - val javaSourceRoots = contentRoots.filterIsInstance().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, - bindingTrace: BindingTrace, - componentProvider: ComponentProvider + project: Project, + module: ModuleDescriptor, + projectContext: ProjectContext, + files: Collection, + bindingTrace: BindingTrace, + componentProvider: ComponentProvider ): AnalysisResult? { return AnalysisResult.success(bindingTrace.bindingContext, module, shouldGenerateCode = false) } override fun analysisCompleted( - project: Project, - module: ModuleDescriptor, - bindingTrace: BindingTrace, - files: Collection + project: Project, + module: ModuleDescriptor, + bindingTrace: BindingTrace, + files: Collection ): 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 - } - } - } } \ No newline at end of file diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/KaptContextForStubGeneration.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/KaptContextForStubGeneration.kt index d4150ea65e8..f50b3a41709 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/KaptContextForStubGeneration.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/KaptContextForStubGeneration.kt @@ -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, val origins: Map, - val generationState: GenerationState, - mapDiagnosticLocations: Boolean, - processorOptions: Map, - javacOptions: Map = 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) { diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt index 7017b3f3e7d..9678c66c742 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt @@ -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() + private val correctErrorTypes = kaptContext.options[KaptFlag.CORRECT_ERROR_TYPES] + private val strictMode = kaptContext.options[KaptFlag.STRICT] + + private val mutableBindings = mutableMapOf() val bindings: Map - 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) diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/util/MessageCollectorBackedKaptLogger.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/util/MessageCollectorBackedKaptLogger.kt index 7368ef31900..8ed3d087b69 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/util/MessageCollectorBackedKaptLogger.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/util/MessageCollectorBackedKaptLogger.kt @@ -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) { diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt index 0025c1cc5c3..66bd700f034 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt @@ -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? = null private val processors get() = _processors!! - private var _options: Map? = null - private val options get() = _options!! + private var mutableOptions: Map? = null override fun tearDown() { _processors = null - _options = null + mutableOptions = null super.tearDown() } @@ -82,7 +80,7 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() { process: (Set, 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, - javaSourceRoots: List, - outputDir: File, - options: Map, - 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) : AbstractKapt3Extension( + options, MessageCollectorBackedKaptLogger(options), compilerConfiguration = CompilerConfiguration.EMPTY ) { internal var savedStubs: String? = null internal var savedBindings: Map? = null diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt index ee201fb80e0..70a868fd933 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt @@ -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() private val tempFiles = mutableListOf() + 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) { val project = myEnvironment.project val psiManager = PsiManager.getInstance(project) - val tmpDir = Files.createTempDirectory("kaptTest").toFile() - tempFiles += tmpDir + val tmpDir = createTempDir("kaptTest") val ktFiles = ArrayList(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, - generateNonExistentClass: Boolean, - correctErrorTypes: Boolean, - strictMode: Boolean + generateNonExistentClass: Boolean ): JavacList { - 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, 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, 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, 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) diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3IntegrationTests.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3IntegrationTests.kt index c3c417b42ef..15dc8ae56d4 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3IntegrationTests.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3IntegrationTests.kt @@ -96,8 +96,8 @@ class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), Java9T test(name, "test.MyAnnotation") { _, _, _ -> val kaptExtension = AnalysisHandlerExtension.getInstances(myEnvironment.project).firstIsInstance() - val stubsOutputDir = kaptExtension.paths.stubsOutputDir - val incrementalDataOutputDir = kaptExtension.paths.incrementalDataOutputDir + val stubsOutputDir = kaptExtension.options.stubsOutputDir + val incrementalDataOutputDir = kaptExtension.options.incrementalDataOutputDir val bindings = kaptExtension.savedBindings!!