Kapt3: Output stubs to .java files in verbose mode

This commit is contained in:
Yan Zhulanow
2016-10-29 05:02:31 +03:00
committed by Yan Zhulanow
parent aa15e0ad67
commit 6b1fc6fc39
4 changed files with 101 additions and 44 deletions
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.kapt3
import com.intellij.openapi.project.Project
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.state.GenerationState
@@ -36,12 +37,14 @@ import java.io.File
import java.net.URLClassLoader
import java.util.*
import javax.annotation.processing.Processor
import com.sun.tools.javac.util.List as JavacList
class Kapt3AnalysisCompletedHandlerExtension(
val annotationProcessingClasspath: List<File>,
val javaSourceRoots: List<File>,
val sourcesOutputDir: File,
val classesOutputDir: File,
val classFilesOutputDir: File,
val stubsOutputDir: File?,
val options: Map<String, String>, //TODO
val aptOnly: Boolean,
val logger: Logger
@@ -102,9 +105,13 @@ class Kapt3AnalysisCompletedHandlerExtension(
val jcCompilationUnitsForKotlinClasses = treeConverter.convert()
logger.info { "Stubs for Kotlin classes: " + jcCompilationUnitsForKotlinClasses.joinToString { it.sourcefile.name } }
if (stubsOutputDir != null) {
saveStubs(stubsOutputDir, jcCompilationUnitsForKotlinClasses)
}
kaptRunner.doAnnotationProcessing(
javaFilesFromJavaSourceRoots, processors,
annotationProcessingClasspath, sourcesOutputDir, classesOutputDir, jcCompilationUnitsForKotlinClasses)
annotationProcessingClasspath, sourcesOutputDir, classFilesOutputDir, jcCompilationUnitsForKotlinClasses)
} catch (thr: Throwable) {
if (thr !is KaptError || thr.kind != KaptError.Kind.ERROR_RAISED) {
logger.exception(thr)
@@ -126,6 +133,17 @@ class Kapt3AnalysisCompletedHandlerExtension(
}
}
private fun saveStubs(outputDir: File, stubs: JavacList<JCTree.JCCompilationUnit>) {
for (stub in stubs) {
val className = (stub.defs.first { it is JCTree.JCClassDecl } as JCTree.JCClassDecl).simpleName.toString()
val packageName = stub.packageName?.toString() ?: ""
val packageDir = if (packageName.isEmpty()) outputDir else File(outputDir, packageName.replace('.', '/'))
packageDir.mkdirs()
File(packageDir, className + ".java").writeText(stub.toString())
}
}
private fun loadProcessors(classpath: List<File>): List<Processor> {
val classLoader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray())
return ServiceLoader.load(Processor::class.java, classLoader).toList()
@@ -30,18 +30,20 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.CompilerConfigurationKey
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.APT_ONLY
import org.jetbrains.kotlin.kapt3.diagnostic.DefaultErrorMessagesKapt3
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
import java.io.File
object Kapt3ConfigurationKeys {
val GENERATED_OUTPUT_DIR: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("generated files output directory")
val SOURCE_OUTPUT_DIR: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("source files output directory")
val CLASS_FILES_OUTPUT_DIR: CompilerConfigurationKey<String> =
val CLASS_OUTPUT_DIR: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("class files output directory")
val STUBS_OUTPUT_DIR: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("stubs output directory")
val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> =
CompilerConfigurationKey.create<List<String>>("annotation processor classpath")
@@ -59,12 +61,15 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
companion object {
val ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.kapt3"
val GENERATED_OUTPUT_DIR_OPTION: CliOption =
CliOption("generated", "<path>", "Output path for the generated files", required = false)
val SOURCE_OUTPUT_DIR_OPTION: CliOption =
CliOption("sources", "<path>", "Output path for the generated files", required = false)
val CLASS_FILES_OUTPUT_DIR_OPTION: CliOption =
val CLASS_OUTPUT_DIR_OPTION: CliOption =
CliOption("classes", "<path>", "Output path for the class files", required = false)
val STUBS_OUTPUT_DIR_OPTION: CliOption =
CliOption("stubs", "<path>", "Output path for the Java stubs", required = false)
val ANNOTATION_PROCESSOR_CLASSPATH_OPTION: CliOption =
CliOption("apclasspath", "<classpath>", "Annotation processor classpath",
required = false, allowMultipleOccurrences = true)
@@ -83,8 +88,8 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
override val pluginOptions: Collection<CliOption> =
listOf(GENERATED_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION, APT_OPTIONS_OPTION,
CLASS_FILES_OUTPUT_DIR_OPTION, VERBOSE_MODE_OPTION)
listOf(SOURCE_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION, APT_OPTIONS_OPTION,
CLASS_OUTPUT_DIR_OPTION, VERBOSE_MODE_OPTION, STUBS_OUTPUT_DIR_OPTION)
private fun <T> CompilerConfiguration.appendList(option: CompilerConfigurationKey<List<T>>, value: T) {
val paths = getList(option).toMutableList()
@@ -96,8 +101,9 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
when (option) {
ANNOTATION_PROCESSOR_CLASSPATH_OPTION -> configuration.appendList(ANNOTATION_PROCESSOR_CLASSPATH, value)
APT_OPTIONS_OPTION -> configuration.appendList(APT_OPTIONS, value)
GENERATED_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.GENERATED_OUTPUT_DIR, value)
CLASS_FILES_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.CLASS_FILES_OUTPUT_DIR, 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)
VERBOSE_MODE_OPTION -> configuration.put(Kapt3ConfigurationKeys.VERBOSE_MODE, value)
APT_ONLY_OPTION -> configuration.put(Kapt3ConfigurationKeys.APT_ONLY, value)
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
@@ -107,7 +113,10 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
class Kapt3ComponentRegistrar : ComponentRegistrar {
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
val generatedOutputDir = configuration.get(Kapt3ConfigurationKeys.GENERATED_OUTPUT_DIR) ?: return
val sourcesOutputDir = configuration.get(Kapt3ConfigurationKeys.SOURCE_OUTPUT_DIR)?.let(::File) ?: return
val classFilesOutputDir = configuration.get(Kapt3ConfigurationKeys.CLASS_OUTPUT_DIR)?.let(::File) ?: return
val stubsOutputDir = configuration.get(Kapt3ConfigurationKeys.STUBS_OUTPUT_DIR)?.let(::File)
val apClasspath = configuration.get(ANNOTATION_PROCESSOR_CLASSPATH)?.map(::File) ?: return
val apOptions = (configuration.get(APT_OPTIONS) ?: listOf())
@@ -116,7 +125,6 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
.map { it[0] to it[1] }
.toMap()
val sourcesOutputDir = File(generatedOutputDir)
sourcesOutputDir.mkdirs()
val contentRoots = configuration[JVMConfigurationKeys.CONTENT_ROOTS] ?: emptyList()
@@ -126,9 +134,6 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
val javaSourceRoots = contentRoots.filterIsInstance<JavaSourceRoot>().map { it.file }
val classesOutputDir = File(configuration.get(Kapt3ConfigurationKeys.CLASS_FILES_OUTPUT_DIR)
?: configuration[JVMConfigurationKeys.MODULES]!!.first().getOutputDirectory())
val isVerbose = configuration.get(Kapt3ConfigurationKeys.VERBOSE_MODE) == "true"
val isAptOnly = configuration.get(Kapt3ConfigurationKeys.APT_ONLY) == "true"
@@ -139,14 +144,15 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
logger.info("Kapt3 is enabled.")
logger.info("Do annotation processing only: $isAptOnly")
logger.info("Source output directory: $sourcesOutputDir")
logger.info("Classes output directory: $classesOutputDir")
logger.info("Classes output directory: $classFilesOutputDir")
logger.info("Stubs output directory: $stubsOutputDir")
logger.info("Annotation processing classpath: " + classpath.joinToString())
logger.info("Java source roots: " + javaSourceRoots.joinToString())
logger.info("Options: $apOptions")
}
val kapt3AnalysisCompletedHandlerExtension = Kapt3AnalysisCompletedHandlerExtension(
classpath, javaSourceRoots, sourcesOutputDir, classesOutputDir, apOptions, isAptOnly, logger)
classpath, javaSourceRoots, sourcesOutputDir, classFilesOutputDir, stubsOutputDir, apOptions, isAptOnly, logger)
AnalysisCompletedHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension)
}
}