Kapt: Fix compatibility with Java 9

1. Move option set up to one place, before using any of Java context components;
2. Set Javac file manager options (new to Java 9)
This commit is contained in:
Yan Zhulanow
2018-04-27 18:27:59 +03:00
parent 386f05bb91
commit eb4492394e
10 changed files with 181 additions and 124 deletions
@@ -59,14 +59,21 @@ import java.util.*
import javax.annotation.processing.Processor import javax.annotation.processing.Processor
import com.sun.tools.javac.util.List as JavacList import com.sun.tools.javac.util.List as JavacList
class KaptPaths(
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()
}
class ClasspathBasedKapt3Extension( class ClasspathBasedKapt3Extension(
compileClasspath: List<File>, paths: KaptPaths,
annotationProcessingClasspath: List<File>,
javaSourceRoots: List<File>,
sourcesOutputDir: File,
classFilesOutputDir: File,
stubsOutputDir: File,
incrementalDataOutputDir: File?,
options: Map<String, String>, options: Map<String, String>,
javacOptions: Map<String, String>, javacOptions: Map<String, String>,
annotationProcessorFqNames: List<String>, annotationProcessorFqNames: List<String>,
@@ -77,8 +84,7 @@ class ClasspathBasedKapt3Extension(
pluginInitializedTime: Long, pluginInitializedTime: Long,
logger: KaptLogger, logger: KaptLogger,
compilerConfiguration: CompilerConfiguration compilerConfiguration: CompilerConfiguration
) : AbstractKapt3Extension(compileClasspath, annotationProcessingClasspath, javaSourceRoots, sourcesOutputDir, ) : AbstractKapt3Extension(paths, options, javacOptions, annotationProcessorFqNames,
classFilesOutputDir, stubsOutputDir, incrementalDataOutputDir, options, javacOptions, annotationProcessorFqNames,
aptMode, pluginInitializedTime, logger, correctErrorTypes, mapDiagnosticLocations, compilerConfiguration) { aptMode, pluginInitializedTime, logger, correctErrorTypes, mapDiagnosticLocations, compilerConfiguration) {
override val analyzePartially: Boolean override val analyzePartially: Boolean
get() = useLightAnalysis get() = useLightAnalysis
@@ -102,7 +108,7 @@ class ClasspathBasedKapt3Extension(
override fun loadProcessors(): List<Processor> { override fun loadProcessors(): List<Processor> {
ClassUtilCore.clearJarURLCache() ClassUtilCore.clearJarURLCache()
val classpath = (annotationProcessingClasspath + compileClasspath).distinct() val classpath = (paths.annotationProcessingClasspath + paths.compileClasspath).distinct()
val classLoader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray()) val classLoader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray())
this.annotationProcessingClassLoader = classLoader this.annotationProcessingClassLoader = classLoader
@@ -147,13 +153,7 @@ class ClasspathBasedKapt3Extension(
} }
abstract class AbstractKapt3Extension( abstract class AbstractKapt3Extension(
compileClasspath: List<File>, val paths: KaptPaths,
annotationProcessingClasspath: List<File>,
val javaSourceRoots: List<File>,
val sourcesOutputDir: File,
val classFilesOutputDir: File,
val stubsOutputDir: File,
val incrementalDataOutputDir: File?,
val options: Map<String, String>, val options: Map<String, String>,
val javacOptions: Map<String, String>, val javacOptions: Map<String, String>,
val annotationProcessorFqNames: List<String>, val annotationProcessorFqNames: List<String>,
@@ -164,9 +164,6 @@ abstract class AbstractKapt3Extension(
val mapDiagnosticLocations: Boolean, val mapDiagnosticLocations: Boolean,
val compilerConfiguration: CompilerConfiguration val compilerConfiguration: CompilerConfiguration
) : PartialAnalysisHandlerExtension() { ) : PartialAnalysisHandlerExtension() {
val compileClasspath = compileClasspath.distinct()
val annotationProcessingClasspath = annotationProcessingClasspath.distinct()
private var annotationProcessingComplete = false private var annotationProcessingComplete = false
private fun setAnnotationProcessingComplete(): Boolean { private fun setAnnotationProcessingComplete(): Boolean {
@@ -230,14 +227,14 @@ abstract class AbstractKapt3Extension(
AnalysisResult.RetryWithAdditionalJavaRoots( AnalysisResult.RetryWithAdditionalJavaRoots(
bindingTrace.bindingContext, bindingTrace.bindingContext,
module, module,
listOf(sourcesOutputDir), listOf(paths.sourcesOutputDir),
addToEnvironment = true) addToEnvironment = true)
} }
} }
private fun generateStubs(project: Project, module: ModuleDescriptor, context: BindingContext, files: Collection<KtFile>): KaptContext<*> { private fun generateStubs(project: Project, module: ModuleDescriptor, context: BindingContext, files: Collection<KtFile>): KaptContext<*> {
if (!aptMode.generateStubs) { if (!aptMode.generateStubs) {
return KaptContext(logger, project, BindingContext.EMPTY, emptyList(), emptyMap(), null, return KaptContext(paths, false, aptMode, logger, project, BindingContext.EMPTY, emptyList(), emptyMap(), null,
mapDiagnosticLocations, options, javacOptions) mapDiagnosticLocations, options, javacOptions)
} }
@@ -254,8 +251,7 @@ abstract class AbstractKapt3Extension(
val javaSourceFiles = collectJavaSourceFiles() val javaSourceFiles = collectJavaSourceFiles()
val (annotationProcessingTime) = measureTimeMillis { val (annotationProcessingTime) = measureTimeMillis {
kaptContext.doAnnotationProcessing( kaptContext.doAnnotationProcessing(javaSourceFiles, processors)
javaSourceFiles, processors, compileClasspath, annotationProcessingClasspath, sourcesOutputDir, classFilesOutputDir)
} }
logger.info { "Annotation processing took $annotationProcessingTime ms" } logger.info { "Annotation processing took $annotationProcessingTime ms" }
@@ -292,7 +288,7 @@ abstract class AbstractKapt3Extension(
logger.info { "Stubs compilation took $classFilesCompilationTime ms" } logger.info { "Stubs compilation took $classFilesCompilationTime ms" }
logger.info { "Compiled classes: " + compiledClasses.joinToString { it.name } } logger.info { "Compiled classes: " + compiledClasses.joinToString { it.name } }
return KaptContext(logger, project, bindingContext, compiledClasses, origins, generationState, return KaptContext(paths, false, aptMode, logger, project, bindingContext, compiledClasses, origins, generationState,
mapDiagnosticLocations, options, javacOptions) mapDiagnosticLocations, options, javacOptions)
} }
@@ -311,7 +307,7 @@ abstract class AbstractKapt3Extension(
} }
private fun collectJavaSourceFiles(): List<File> { private fun collectJavaSourceFiles(): List<File> {
val javaFilesFromJavaSourceRoots = (javaSourceRoots + stubsOutputDir).flatMap { val javaFilesFromJavaSourceRoots = (paths.javaSourceRoots + paths.stubsOutputDir).flatMap {
root -> root.walk().filter { it.isFile && it.extension == "java" }.toList() root -> root.walk().filter { it.isFile && it.extension == "java" }.toList()
} }
logger.info { "Java source files: " + javaFilesFromJavaSourceRoots.joinToString { it.canonicalPath } } logger.info { "Java source files: " + javaFilesFromJavaSourceRoots.joinToString { it.canonicalPath } }
@@ -325,10 +321,10 @@ abstract class AbstractKapt3Extension(
val className = (stub.defs.first { it is JCTree.JCClassDecl } as JCTree.JCClassDecl).simpleName.toString() val className = (stub.defs.first { it is JCTree.JCClassDecl } as JCTree.JCClassDecl).simpleName.toString()
val packageName = stub.getPackageNameJava9Aware()?.toString() ?: "" val packageName = stub.getPackageNameJava9Aware()?.toString() ?: ""
val packageDir = if (packageName.isEmpty()) stubsOutputDir else File(stubsOutputDir, packageName.replace('.', '/')) val packageDir = if (packageName.isEmpty()) paths.stubsOutputDir else File(paths.stubsOutputDir, packageName.replace('.', '/'))
packageDir.mkdirs() packageDir.mkdirs()
val sourceFile = File(packageDir, className + ".java") val sourceFile = File(packageDir, "$className.java")
sourceFile.writeText(stub.prettyPrint(kaptContext.context)) sourceFile.writeText(stub.prettyPrint(kaptContext.context))
kaptStub.writeMetadataIfNeeded(forSource = sourceFile) kaptStub.writeMetadataIfNeeded(forSource = sourceFile)
@@ -339,7 +335,7 @@ abstract class AbstractKapt3Extension(
kaptContext: KaptContext<GenerationState>, kaptContext: KaptContext<GenerationState>,
messageCollector: MessageCollector, messageCollector: MessageCollector,
converter: ClassFileToSourceStubConverter) { converter: ClassFileToSourceStubConverter) {
val incrementalDataOutputDir = this.incrementalDataOutputDir ?: return val incrementalDataOutputDir = paths.incrementalDataOutputDir ?: return
val reportOutputFiles = kaptContext.generationState.configuration.getBoolean(CommonConfigurationKeys.REPORT_OUTPUT_FILES) val reportOutputFiles = kaptContext.generationState.configuration.getBoolean(CommonConfigurationKeys.REPORT_OUTPUT_FILES)
kaptContext.generationState.factory.writeAll( kaptContext.generationState.factory.writeAll(
@@ -347,7 +343,7 @@ abstract class AbstractKapt3Extension(
if (!reportOutputFiles) null else fun(file: OutputFile, sources: List<File>, output: File) { if (!reportOutputFiles) null else fun(file: OutputFile, sources: List<File>, output: File) {
val stubFileObject = converter.bindings[file.relativePath.substringBeforeLast(".class", missingDelimiterValue = "")] val stubFileObject = converter.bindings[file.relativePath.substringBeforeLast(".class", missingDelimiterValue = "")]
if (stubFileObject != null) { if (stubFileObject != null) {
val stubFile = File(stubsOutputDir, stubFileObject.name) val stubFile = File(paths.stubsOutputDir, stubFileObject.name)
val lineMappingsFile = File(stubFile.parentFile, stubFile.nameWithoutExtension + KAPT_METADATA_EXTENSION) val lineMappingsFile = File(stubFile.parentFile, stubFile.nameWithoutExtension + KAPT_METADATA_EXTENSION)
for (file in listOf(stubFile, lineMappingsFile)) { for (file in listOf(stubFile, lineMappingsFile)) {
@@ -301,10 +301,16 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
logger.info("Options: $apOptions") logger.info("Options: $apOptions")
} }
val paths = KaptPaths(
compileClasspath, apClasspath, javaSourceRoots, sourcesOutputDir, classFilesOutputDir,
stubsOutputDir, incrementalDataOutputDir
)
val kapt3AnalysisCompletedHandlerExtension = ClasspathBasedKapt3Extension( val kapt3AnalysisCompletedHandlerExtension = ClasspathBasedKapt3Extension(
compileClasspath, apClasspath, javaSourceRoots, sourcesOutputDir, classFilesOutputDir, paths, apOptions, javacCliOptions, annotationProcessors,
stubsOutputDir, incrementalDataOutputDir, apOptions, javacCliOptions, annotationProcessors, aptMode, useLightAnalysis, correctErrorTypes, mapDiagnosticLocations, System.currentTimeMillis(), logger, configuration
aptMode, useLightAnalysis, correctErrorTypes, mapDiagnosticLocations, System.currentTimeMillis(), logger, configuration) )
AnalysisHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension) AnalysisHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension)
} }
@@ -17,24 +17,31 @@
package org.jetbrains.kotlin.kapt3 package org.jetbrains.kotlin.kapt3
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.sun.tools.javac.file.JavacFileManager
import com.sun.tools.javac.jvm.ClassReader import com.sun.tools.javac.jvm.ClassReader
import com.sun.tools.javac.main.JavaCompiler import com.sun.tools.javac.main.JavaCompiler
import com.sun.tools.javac.tree.TreeMaker import com.sun.tools.javac.tree.TreeMaker
import com.sun.tools.javac.main.Option
import com.sun.tools.javac.util.Context import com.sun.tools.javac.util.Context
import com.sun.tools.javac.util.Options import com.sun.tools.javac.util.Options
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.kapt3.javac.KaptJavaCompiler import org.jetbrains.kotlin.kapt3.javac.KaptJavaCompiler
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileManager
import org.jetbrains.kotlin.kapt3.javac.KaptJavaLog import org.jetbrains.kotlin.kapt3.javac.KaptJavaLog
import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
import org.jetbrains.kotlin.kapt3.util.KaptLogger import org.jetbrains.kotlin.kapt3.util.KaptLogger
import org.jetbrains.kotlin.kapt3.util.isJava9OrLater
import org.jetbrains.kotlin.kapt3.util.putJavacOption
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.kotlin.utils.keysToMap
import org.jetbrains.org.objectweb.asm.tree.ClassNode import org.jetbrains.org.objectweb.asm.tree.ClassNode
import java.io.File
import javax.tools.JavaFileManager import javax.tools.JavaFileManager
class KaptContext<out GState : GenerationState?>( class KaptContext<out GState : GenerationState?>(
val paths: KaptPaths,
private val withJdk: Boolean,
aptMode: AptMode,
val logger: KaptLogger, val logger: KaptLogger,
val project: Project, val project: Project,
val bindingContext: BindingContext, val bindingContext: BindingContext,
@@ -47,47 +54,77 @@ class KaptContext<out GState : GenerationState?>(
) : AutoCloseable { ) : AutoCloseable {
val context = Context() val context = Context()
val compiler: KaptJavaCompiler val compiler: KaptJavaCompiler
val fileManager: JavacFileManager val fileManager: KaptJavaFileManager
val options: Options val options: Options
val javaLog: KaptJavaLog val javaLog: KaptJavaLog
val treeMaker: KaptTreeMaker private val treeMaker: TreeMaker
init { init {
KaptJavaLog.preRegister(this, logger.messageCollector, mapDiagnosticLocations) KaptJavaLog.preRegister(this, logger.messageCollector, mapDiagnosticLocations)
JavacFileManager.preRegister(context) KaptJavaFileManager.preRegister(context)
KaptTreeMaker.preRegister(context, this) if (aptMode != AptMode.APT_ONLY) {
KaptTreeMaker.preRegister(context, this)
}
KaptJavaCompiler.preRegister(context) KaptJavaCompiler.preRegister(context)
options = Options.instance(context) options = Options.instance(context).apply {
for ((key, value) in processorOptions) { for ((key, value) in processorOptions) {
val option = if (value.isEmpty()) "-A$key" else "-A$key=$value" val option = if (value.isEmpty()) "-A$key" else "-A$key=$value"
options.put(option, option) // key == value: it's intentional put(option, option) // key == value: it's intentional
}
for ((key, value) in javacOptions) {
if (value.isNotEmpty()) {
options.put(key, value)
} else {
options.put(key, key)
} }
for ((key, value) in javacOptions) {
if (value.isNotEmpty()) {
put(key, value)
} else {
put(key, key)
}
}
put(Option.PROC, "only") // Only process annotations
if (!withJdk) {
putJavacOption("BOOTCLASSPATH", "BOOT_CLASS_PATH", "") // No boot classpath
}
if (isJava9OrLater) {
put("accessInternalAPI", "true")
}
putJavacOption("CLASSPATH", "CLASS_PATH",
paths.compileClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
putJavacOption("PROCESSORPATH", "PROCESSOR_PATH",
paths.annotationProcessingClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
put(Option.S, paths.sourcesOutputDir.canonicalPath)
put(Option.D, paths.classFilesOutputDir.canonicalPath)
put(Option.ENCODING, "UTF-8")
} }
if (logger.isVerbose) { if (logger.isVerbose) {
logger.info("Javac options: " + options.keySet().keysToMap { key -> options[key] ?: "" }) logger.info("Javac options: " + options.keySet().keysToMap { key -> options[key] ?: "" })
} }
fileManager = context.get(JavaFileManager::class.java) as JavacFileManager fileManager = context.get(JavaFileManager::class.java) as KaptJavaFileManager
if (isJava9OrLater) {
for (option in Option.getJavacFileManagerOptions()) {
val value = options.get(option) ?: continue
fileManager.handleOptionJavac9(option, value)
}
}
compiler = JavaCompiler.instance(context) as KaptJavaCompiler compiler = JavaCompiler.instance(context) as KaptJavaCompiler
compiler.keepComments = true compiler.keepComments = true
ClassReader.instance(context).saveParameterNames = true ClassReader.instance(context).saveParameterNames = true
javaLog = compiler.log as KaptJavaLog javaLog = compiler.log as KaptJavaLog
treeMaker = TreeMaker.instance(context) as KaptTreeMaker treeMaker = TreeMaker.instance(context)
} }
override fun close() { override fun close() {
treeMaker.dispose() (treeMaker as? KaptTreeMaker)?.dispose()
compiler.close() compiler.close()
fileManager.close() fileManager.close()
generationState?.destroy() generationState?.destroy()
@@ -37,27 +37,8 @@ import com.sun.tools.javac.util.List as JavacList
fun KaptContext<*>.doAnnotationProcessing( fun KaptContext<*>.doAnnotationProcessing(
javaSourceFiles: List<File>, javaSourceFiles: List<File>,
processors: List<Processor>, processors: List<Processor>,
compileClasspath: List<File>, additionalSources: JavacList<JCTree.JCCompilationUnit> = JavacList.nil()
annotationProcessingClasspath: List<File>,
sourcesOutputDir: File,
classesOutputDir: File,
additionalSources: JavacList<JCTree.JCCompilationUnit> = JavacList.nil(),
withJdk: Boolean = false
) { ) {
with (options) {
put(Option.PROC, "only") // Only process annotations
if (!withJdk) {
putJavacOption("BOOTCLASSPATH", "BOOT_CLASS_PATH", "") // No boot classpath
}
putJavacOption("CLASSPATH", "CLASS_PATH", compileClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
putJavacOption("PROCESSORPATH", "PROCESSOR_PATH", annotationProcessingClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
put(Option.S, sourcesOutputDir.canonicalPath)
put(Option.D, classesOutputDir.canonicalPath)
put(Option.ENCODING, "UTF-8")
}
val processingEnvironment = JavacProcessingEnvironment.instance(context) val processingEnvironment = JavacProcessingEnvironment.instance(context)
val wrappedProcessors = processors.map { ProcessorWrapper(it) } val wrappedProcessors = processors.map { ProcessorWrapper(it) }
@@ -0,0 +1,21 @@
package org.jetbrains.kotlin.kapt3.javac
import com.sun.tools.javac.file.JavacFileManager
import com.sun.tools.javac.main.Option
import com.sun.tools.javac.util.Context
import javax.tools.JavaFileManager
class KaptJavaFileManager(context: Context) : JavacFileManager(context, true, null) {
fun handleOptionJavac9(option: Option, value: String) {
val handleOptionMethod = JavacFileManager::class.java
.getMethod("handleOption", Option::class.java, String::class.java)
handleOptionMethod.invoke(this, option, value)
}
companion object {
internal fun preRegister(context: Context) {
context.put(JavaFileManager::class.java, Context.Factory<JavaFileManager> { KaptJavaFileManager(it) })
}
}
}
@@ -228,7 +228,9 @@ class KaptJavaLog(
"compiler.err.already.defined", "compiler.err.already.defined",
"compiler.err.annotation.type.not.applicable", "compiler.err.annotation.type.not.applicable",
"compiler.err.doesnt.exist", "compiler.err.doesnt.exist",
"compiler.err.duplicate.annotation.missing.container" "compiler.err.duplicate.annotation.missing.container",
"compiler.err.not.def.access.package.cant.access",
"compiler.err.package.not.visible"
) )
internal fun preRegister(kaptContext: KaptContext<*>, messageCollector: MessageCollector, mapDiagnosticLocations: Boolean) { internal fun preRegister(kaptContext: KaptContext<*>, messageCollector: MessageCollector, mapDiagnosticLocations: Boolean) {
@@ -23,11 +23,8 @@ import org.jetbrains.kotlin.codegen.CodegenTestCase
import org.jetbrains.kotlin.codegen.GenerationUtils import org.jetbrains.kotlin.codegen.GenerationUtils
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.kapt3.AbstractKapt3Extension import org.jetbrains.kotlin.kapt3.*
import org.jetbrains.kotlin.kapt3.AptMode.STUBS_AND_APT import org.jetbrains.kotlin.kapt3.AptMode.STUBS_AND_APT
import org.jetbrains.kotlin.kapt3.Kapt3BuilderFactory
import org.jetbrains.kotlin.kapt3.prettyPrint
import org.jetbrains.kotlin.kapt3.KaptContext
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter.KaptStub import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter.KaptStub
@@ -162,11 +159,13 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
options: Map<String, String>, options: Map<String, String>,
stubsOutputDir: File, stubsOutputDir: File,
incrementalDataOutputDir: File incrementalDataOutputDir: File
) : AbstractKapt3Extension(PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath, ) : AbstractKapt3Extension(
emptyList(), javaSourceRoots, outputDir, outputDir, KaptPaths(
stubsOutputDir, incrementalDataOutputDir, options, emptyMap(), emptyList(), STUBS_AND_APT, System.currentTimeMillis(), PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath,
KaptLogger(true), correctErrorTypes = true, mapDiagnosticLocations = true, emptyList(), javaSourceRoots, outputDir, outputDir, stubsOutputDir, incrementalDataOutputDir
compilerConfiguration = CompilerConfiguration.EMPTY ), options, emptyMap(), emptyList(), STUBS_AND_APT, System.currentTimeMillis(),
KaptLogger(true), correctErrorTypes = true, mapDiagnosticLocations = true,
compilerConfiguration = CompilerConfiguration.EMPTY
) { ) {
internal var savedStubs: String? = null internal var savedStubs: String? = null
internal var savedBindings: Map<String, KaptJavaFileObject>? = null internal var savedBindings: Map<String, KaptJavaFileObject>? = null
@@ -120,23 +120,36 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
key to value key to value
}.toMap() }.toMap()
val kaptContext = KaptContext(logger, generationState.project, generationState.bindingContext, classBuilderFactory.compiledClasses, var javaFiles: List<File>? = null
classBuilderFactory.origins, generationState, mapDiagnosticLocations = true, var kaptContext: KaptContext<*>? = null
processorOptions = emptyMap(), javacOptions = javacOptions)
val javaFiles = files
.filter { it.name.toLowerCase().endsWith(".java") }
.map { createTempFile(it.name.substringBeforeLast('.'), ".java", it.content) }
try { try {
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
val paths = KaptPaths(
compileClasspath = PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath,
annotationProcessingClasspath = emptyList(), javaSourceRoots = emptyList(),
sourcesOutputDir = sourceOutputDir, classFilesOutputDir = sourceOutputDir,
stubsOutputDir = sourceOutputDir, incrementalDataOutputDir = sourceOutputDir
)
kaptContext = KaptContext(paths, true, AptMode.STUBS_AND_APT,
logger, generationState.project, generationState.bindingContext, classBuilderFactory.compiledClasses,
classBuilderFactory.origins, generationState, mapDiagnosticLocations = true,
processorOptions = emptyMap(), javacOptions = javacOptions)
javaFiles = files
.filter { it.name.toLowerCase().endsWith(".java") }
.map { createTempFile(it.name.substringBeforeLast('.'), ".java", it.content) }
check(kaptContext, javaFiles, txtFile, wholeFile) check(kaptContext, javaFiles, txtFile, wholeFile)
} catch (e: Throwable) { } catch (e: Throwable) {
throw RuntimeException(e) throw RuntimeException(e)
} finally { } finally {
javaFiles.forEach { it.delete() } javaFiles?.forEach { it.delete() }
tempFiles.forEach { if (it.isFile) it.delete() else it.deleteRecursively() } tempFiles.forEach { if (it.isFile) it.delete() else it.deleteRecursively() }
tempFiles.clear() tempFiles.clear()
kaptContext.close() kaptContext?.close()
} }
} }
@@ -287,22 +300,17 @@ open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test(
abstract class AbstractKotlinKaptContextTest : AbstractKotlinKapt3Test() { abstract class AbstractKotlinKaptContextTest : AbstractKotlinKapt3Test() {
override fun check(kaptContext: KaptContext<GenerationState>, javaFiles: List<File>, txtFile: File, wholeFile: File) { override fun check(kaptContext: KaptContext<GenerationState>, javaFiles: List<File>, txtFile: File, wholeFile: File) {
val compilationUnits = convert(kaptContext, javaFiles, generateNonExistentClass = false, correctErrorTypes = true) val compilationUnits = convert(kaptContext, javaFiles, generateNonExistentClass = false, correctErrorTypes = true)
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
try {
kaptContext.doAnnotationProcessing(emptyList(), listOf(JavaKaptContextTest.simpleProcessor()),
compileClasspath = PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath,
annotationProcessingClasspath = emptyList(),
sourcesOutputDir = sourceOutputDir, classesOutputDir = sourceOutputDir,
additionalSources = compilationUnits, withJdk = true
)
val javaFiles = sourceOutputDir.walkTopDown().filter { it.isFile && it.extension == "java" } kaptContext.doAnnotationProcessing(
val actualRaw = javaFiles.sortedBy { it.name }.joinToString(FILE_SEPARATOR) { it.name + ":\n\n" + it.readText() } emptyList(),
val actual = StringUtil.convertLineSeparators(actualRaw.trim({ it <= ' ' })).trimTrailingWhitespacesAndAddNewlineAtEOF() listOf(JavaKaptContextTest.simpleProcessor()),
KotlinTestUtils.assertEqualsToFile(txtFile, actual) additionalSources = compilationUnits
} finally { )
sourceOutputDir.deleteRecursively()
} val stubJavaFiles = kaptContext.paths.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)
} }
} }
@@ -19,7 +19,9 @@ package org.jetbrains.kotlin.kapt3.test
import com.intellij.openapi.command.impl.DummyProject import com.intellij.openapi.command.impl.DummyProject
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.kapt3.AptMode
import org.jetbrains.kotlin.kapt3.KaptContext import org.jetbrains.kotlin.kapt3.KaptContext
import org.jetbrains.kotlin.kapt3.KaptPaths
import org.jetbrains.kotlin.kapt3.diagnostic.KaptError import org.jetbrains.kotlin.kapt3.diagnostic.KaptError
import org.jetbrains.kotlin.kapt3.doAnnotationProcessing import org.jetbrains.kotlin.kapt3.doAnnotationProcessing
import org.jetbrains.kotlin.kapt3.util.KaptLogger import org.jetbrains.kotlin.kapt3.util.KaptLogger
@@ -80,22 +82,27 @@ class JavaKaptContextTest {
} }
private fun doAnnotationProcessing(javaSourceFile: File, processor: Processor, outputDir: File) { private fun doAnnotationProcessing(javaSourceFile: File, processor: Processor, outputDir: File) {
KaptContext(KaptLogger(isVerbose = true, messageCollector = messageCollector), KaptContext(
DummyProject.getInstance(), KaptPaths(
bindingContext = BindingContext.EMPTY, compileClasspath = emptyList(),
compiledClasses = emptyList(), annotationProcessingClasspath = emptyList(),
origins = emptyMap(), javaSourceRoots = emptyList(),
generationState = null, sourcesOutputDir = outputDir,
mapDiagnosticLocations = true, classFilesOutputDir = outputDir,
processorOptions = emptyMap() stubsOutputDir = outputDir,
).doAnnotationProcessing( incrementalDataOutputDir = outputDir
listOf(javaSourceFile), ),
listOf(processor), withJdk = true,
emptyList(), // compile classpath aptMode = AptMode.STUBS_AND_APT,
emptyList(), // annotation processing classpath logger = KaptLogger(isVerbose = true, messageCollector = messageCollector),
outputDir, project = DummyProject.getInstance(),
outputDir, bindingContext = BindingContext.EMPTY,
withJdk = true) compiledClasses = emptyList(),
origins = emptyMap(),
generationState = null,
mapDiagnosticLocations = true,
processorOptions = emptyMap()
).doAnnotationProcessing(listOf(javaSourceFile), listOf(processor))
} }
@Test @Test
@@ -92,8 +92,8 @@ class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), Java9T
test(name, "test.MyAnnotation") { _, _, _ -> test(name, "test.MyAnnotation") { _, _, _ ->
val kaptExtension = AnalysisHandlerExtension.getInstances(myEnvironment.project).firstIsInstance<Kapt3ExtensionForTests>() val kaptExtension = AnalysisHandlerExtension.getInstances(myEnvironment.project).firstIsInstance<Kapt3ExtensionForTests>()
val stubsOutputDir = kaptExtension.stubsOutputDir val stubsOutputDir = kaptExtension.paths.stubsOutputDir
val incrementalDataOutputDir = kaptExtension.incrementalDataOutputDir val incrementalDataOutputDir = kaptExtension.paths.incrementalDataOutputDir
val bindings = kaptExtension.savedBindings!! val bindings = kaptExtension.savedBindings!!