Kapt: verbose output mode
(cherry picked from commit e6067d5)
This commit is contained in:
committed by
Yan Zhulanow
parent
f5d58d9944
commit
399059729d
+37
-9
@@ -34,13 +34,15 @@ import java.io.File
|
|||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.annotation.processing.Processor
|
import javax.annotation.processing.Processor
|
||||||
|
import javax.tools.Diagnostic
|
||||||
|
|
||||||
class ClasspathBasedAnnotationProcessingExtension(
|
class ClasspathBasedAnnotationProcessingExtension(
|
||||||
val annotationProcessingClasspath: List<String>,
|
val annotationProcessingClasspath: List<String>,
|
||||||
generatedSourcesOutputDir: File,
|
generatedSourcesOutputDir: File,
|
||||||
classesOutputDir: File,
|
classesOutputDir: File,
|
||||||
javaSourceRoots: List<File>
|
javaSourceRoots: List<File>,
|
||||||
) : AbstractAnnotationProcessingExtension(generatedSourcesOutputDir, classesOutputDir, javaSourceRoots) {
|
verboseOutput: Boolean
|
||||||
|
) : AbstractAnnotationProcessingExtension(generatedSourcesOutputDir, classesOutputDir, javaSourceRoots, verboseOutput) {
|
||||||
override fun loadAnnotationProcessors(): List<Processor> {
|
override fun loadAnnotationProcessors(): List<Processor> {
|
||||||
val classLoader = URLClassLoader(annotationProcessingClasspath.map { File(it).toURI().toURL() }.toTypedArray())
|
val classLoader = URLClassLoader(annotationProcessingClasspath.map { File(it).toURI().toURL() }.toTypedArray())
|
||||||
return ServiceLoader.load(Processor::class.java, classLoader).toList()
|
return ServiceLoader.load(Processor::class.java, classLoader).toList()
|
||||||
@@ -50,9 +52,15 @@ class ClasspathBasedAnnotationProcessingExtension(
|
|||||||
abstract class AbstractAnnotationProcessingExtension(
|
abstract class AbstractAnnotationProcessingExtension(
|
||||||
val generatedSourcesOutputDir: File,
|
val generatedSourcesOutputDir: File,
|
||||||
val classesOutputDir: File,
|
val classesOutputDir: File,
|
||||||
val javaSourceRoots: List<File>
|
val javaSourceRoots: List<File>,
|
||||||
|
val verboseOutput: Boolean
|
||||||
) : AnalysisCompletedHandlerExtension {
|
) : AnalysisCompletedHandlerExtension {
|
||||||
private var annotationProcessingComplete = false
|
private var annotationProcessingComplete = false
|
||||||
|
private val messager = KotlinMessager()
|
||||||
|
|
||||||
|
private inline fun log(message: () -> String) {
|
||||||
|
if (verboseOutput) messager.printMessage(Diagnostic.Kind.OTHER, "Kapt: " + message())
|
||||||
|
}
|
||||||
|
|
||||||
override fun analysisCompleted(
|
override fun analysisCompleted(
|
||||||
project: Project,
|
project: Project,
|
||||||
@@ -65,11 +73,18 @@ abstract class AbstractAnnotationProcessingExtension(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val processors = loadAnnotationProcessors()
|
val processors = loadAnnotationProcessors()
|
||||||
if (processors.isEmpty()) return null
|
if (processors.isEmpty()) {
|
||||||
|
log { "No annotation processors detected, exiting" }
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
log { "Analysing Kotlin files: " + files.map { it.virtualFile.path } }
|
||||||
|
|
||||||
val analysisContext = AnalysisContext(hashMapOf())
|
val analysisContext = AnalysisContext(hashMapOf())
|
||||||
analysisContext.analyzeFiles(files)
|
analysisContext.analyzeFiles(files)
|
||||||
|
|
||||||
|
log { "Analysing Java source roots: $javaSourceRoots" }
|
||||||
|
|
||||||
val psiManager = PsiManager.getInstance(project)
|
val psiManager = PsiManager.getInstance(project)
|
||||||
for (javaSourceRoot in javaSourceRoots) {
|
for (javaSourceRoot in javaSourceRoots) {
|
||||||
javaSourceRoot.walk().filter { it.isFile && it.extension == "java" }.forEach {
|
javaSourceRoot.walk().filter { it.isFile && it.extension == "java" }.forEach {
|
||||||
@@ -84,19 +99,21 @@ abstract class AbstractAnnotationProcessingExtension(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val options = emptyMap<String, String>()
|
val options = emptyMap<String, String>()
|
||||||
|
log { "Options: $options" }
|
||||||
|
|
||||||
val javaPsiFacade = JavaPsiFacade.getInstance(project)
|
val javaPsiFacade = JavaPsiFacade.getInstance(project)
|
||||||
val projectScope = GlobalSearchScope.projectScope(project)
|
val projectScope = GlobalSearchScope.projectScope(project)
|
||||||
|
|
||||||
val filer = KotlinFiler(generatedSourcesOutputDir, classesOutputDir)
|
val filer = KotlinFiler(generatedSourcesOutputDir, classesOutputDir)
|
||||||
val messages = KotlinMessager()
|
|
||||||
val types = KotlinTypes(javaPsiFacade, PsiManager.getInstance(project), projectScope)
|
val types = KotlinTypes(javaPsiFacade, PsiManager.getInstance(project), projectScope)
|
||||||
val elements = KotlinElements(javaPsiFacade, projectScope)
|
val elements = KotlinElements(javaPsiFacade, projectScope)
|
||||||
|
|
||||||
val processingEnvironment = KotlinProcessingEnvironment(elements, types, messages, options, filer)
|
val processingEnvironment = KotlinProcessingEnvironment(elements, types, messager, options, filer)
|
||||||
processors.forEach { it.init(processingEnvironment) }
|
processors.forEach { it.init(processingEnvironment) }
|
||||||
|
|
||||||
// Round 1
|
log { "Initialized processors: " + processors.joinToString { it.javaClass.name } }
|
||||||
|
|
||||||
|
log { "Starting round 1" }
|
||||||
val round1Environment = KotlinRoundEnvironment(analysisContext)
|
val round1Environment = KotlinRoundEnvironment(analysisContext)
|
||||||
for (processor in processors) {
|
for (processor in processors) {
|
||||||
val supportedAnnotationNames = processor.supportedAnnotationTypes
|
val supportedAnnotationNames = processor.supportedAnnotationTypes
|
||||||
@@ -107,21 +124,32 @@ abstract class AbstractAnnotationProcessingExtension(
|
|||||||
false -> processor.supportedAnnotationTypes.filter { it in analysisContext.annotationsMap }
|
false -> processor.supportedAnnotationTypes.filter { it in analysisContext.annotationsMap }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (applicableAnnotationNames.isEmpty()) continue
|
if (applicableAnnotationNames.isEmpty()) {
|
||||||
|
log { "Skipping processor " + processor.javaClass.name + ": no relevant annotations" }
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
val applicableAnnotations = applicableAnnotationNames
|
val applicableAnnotations = applicableAnnotationNames
|
||||||
.map { javaPsiFacade.findClass(it, projectScope)?.let { JeTypeElement(it) } }
|
.map { javaPsiFacade.findClass(it, projectScope)?.let { JeTypeElement(it) } }
|
||||||
.filterNotNullTo(hashSetOf())
|
.filterNotNullTo(hashSetOf())
|
||||||
|
|
||||||
|
log {
|
||||||
|
val annotationNames = applicableAnnotations.joinToString { it.qualifiedName.toString() }
|
||||||
|
"Processing with " + processor.javaClass.name + " (annotations: " + annotationNames + ")"
|
||||||
|
}
|
||||||
|
|
||||||
processor.process(applicableAnnotations, round1Environment)
|
processor.process(applicableAnnotations, round1Environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Round 2
|
log { "Starting round 2 (final)" }
|
||||||
val round2Environment = KotlinRoundEnvironment(AnalysisContext(hashMapOf()), isProcessingOver = true)
|
val round2Environment = KotlinRoundEnvironment(AnalysisContext(hashMapOf()), isProcessingOver = true)
|
||||||
for (processor in processors) {
|
for (processor in processors) {
|
||||||
processor.process(emptySet(), round2Environment)
|
processor.process(emptySet(), round2Environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Int.count(noun: String) = if (this == 1) "$this $noun" else "$this ${noun}s"
|
||||||
|
log { "Annotation processing complete, ${messager.errorCount.count("error")}, ${messager.warningCount.count("warning")}" }
|
||||||
|
|
||||||
annotationProcessingComplete = true
|
annotationProcessingComplete = true
|
||||||
return AnalysisResult.RetryWithAdditionalJavaRoots(bindingContext, module, listOf(generatedSourcesOutputDir))
|
return AnalysisResult.RetryWithAdditionalJavaRoots(bindingContext, module, listOf(generatedSourcesOutputDir))
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-2
@@ -37,6 +37,9 @@ object AnnotationProcessingConfigurationKeys {
|
|||||||
|
|
||||||
val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> =
|
val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> =
|
||||||
CompilerConfigurationKey.create<List<String>>("annotation processor classpath")
|
CompilerConfigurationKey.create<List<String>>("annotation processor classpath")
|
||||||
|
|
||||||
|
val VERBOSE_MODE: CompilerConfigurationKey<String> =
|
||||||
|
CompilerConfigurationKey.create<String>("verbose mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
|
class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
|
||||||
@@ -52,12 +55,15 @@ class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
|
|||||||
val ANNOTATION_PROCESSOR_CLASSPATH_OPTION: CliOption =
|
val ANNOTATION_PROCESSOR_CLASSPATH_OPTION: CliOption =
|
||||||
CliOption("apclasspath", "<classpath>", "Annotation processor classpath",
|
CliOption("apclasspath", "<classpath>", "Annotation processor classpath",
|
||||||
required = false, allowMultipleOccurrences = true)
|
required = false, allowMultipleOccurrences = true)
|
||||||
|
|
||||||
|
val VERBOSE_MODE_OPTION: CliOption =
|
||||||
|
CliOption("verbose", "true | false", "Enable verbose output", required = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
|
override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
|
||||||
|
|
||||||
override val pluginOptions: Collection<CliOption> =
|
override val pluginOptions: Collection<CliOption> =
|
||||||
listOf(GENERATED_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION, CLASS_FILES_OUTPUT_DIR_OPTION)
|
listOf(GENERATED_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION, CLASS_FILES_OUTPUT_DIR_OPTION, VERBOSE_MODE_OPTION)
|
||||||
|
|
||||||
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
|
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
|
||||||
when (option) {
|
when (option) {
|
||||||
@@ -68,6 +74,7 @@ class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
|
|||||||
}
|
}
|
||||||
GENERATED_OUTPUT_DIR_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.GENERATED_OUTPUT_DIR, value)
|
GENERATED_OUTPUT_DIR_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.GENERATED_OUTPUT_DIR, value)
|
||||||
CLASS_FILES_OUTPUT_DIR_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.CLASS_FILES_OUTPUT_DIR, value)
|
CLASS_FILES_OUTPUT_DIR_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.CLASS_FILES_OUTPUT_DIR, value)
|
||||||
|
VERBOSE_MODE_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.VERBOSE_MODE, value)
|
||||||
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
|
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,8 +95,10 @@ class AnnotationProcessingComponentRegistrar : ComponentRegistrar {
|
|||||||
val classesOutputDir = File(configuration.get(AnnotationProcessingConfigurationKeys.CLASS_FILES_OUTPUT_DIR)
|
val classesOutputDir = File(configuration.get(AnnotationProcessingConfigurationKeys.CLASS_FILES_OUTPUT_DIR)
|
||||||
?: configuration[JVMConfigurationKeys.MODULES]!!.first().getOutputDirectory())
|
?: configuration[JVMConfigurationKeys.MODULES]!!.first().getOutputDirectory())
|
||||||
|
|
||||||
|
val verboseOutput = configuration.get(AnnotationProcessingConfigurationKeys.VERBOSE_MODE) == "true"
|
||||||
|
|
||||||
val annotationProcessingExtension = ClasspathBasedAnnotationProcessingExtension(
|
val annotationProcessingExtension = ClasspathBasedAnnotationProcessingExtension(
|
||||||
classpath, generatedOutputDirFile, classesOutputDir, javaRoots)
|
classpath, generatedOutputDirFile, classesOutputDir, javaRoots, verboseOutput)
|
||||||
AnalysisCompletedHandlerExtension.registerExtension(project, annotationProcessingExtension)
|
AnalysisCompletedHandlerExtension.registerExtension(project, annotationProcessingExtension)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+14
-1
@@ -24,6 +24,12 @@ import javax.tools.Diagnostic
|
|||||||
import javax.tools.Diagnostic.Kind
|
import javax.tools.Diagnostic.Kind
|
||||||
|
|
||||||
class KotlinMessager : Messager {
|
class KotlinMessager : Messager {
|
||||||
|
var errorCount: Int = 0
|
||||||
|
private set
|
||||||
|
|
||||||
|
var warningCount: Int = 0
|
||||||
|
private set
|
||||||
|
|
||||||
override fun printMessage(kind: Diagnostic.Kind, msg: CharSequence) = printMessage(kind, msg, null)
|
override fun printMessage(kind: Diagnostic.Kind, msg: CharSequence) = printMessage(kind, msg, null)
|
||||||
|
|
||||||
override fun printMessage(kind: Diagnostic.Kind, msg: CharSequence, e: Element?) = printMessage(kind, msg, e, null)
|
override fun printMessage(kind: Diagnostic.Kind, msg: CharSequence, e: Element?) = printMessage(kind, msg, e, null)
|
||||||
@@ -34,7 +40,14 @@ class KotlinMessager : Messager {
|
|||||||
|
|
||||||
override fun printMessage(kind: Diagnostic.Kind, msg: CharSequence, e: Element?, a: AnnotationMirror?, v: AnnotationValue?) {
|
override fun printMessage(kind: Diagnostic.Kind, msg: CharSequence, e: Element?, a: AnnotationMirror?, v: AnnotationValue?) {
|
||||||
val output = when (kind) {
|
val output = when (kind) {
|
||||||
Kind.ERROR, Kind.WARNING, Kind.MANDATORY_WARNING -> System.err
|
Kind.ERROR -> {
|
||||||
|
errorCount++
|
||||||
|
System.err
|
||||||
|
}
|
||||||
|
Kind.WARNING, Kind.MANDATORY_WARNING -> {
|
||||||
|
warningCount++
|
||||||
|
System.err
|
||||||
|
}
|
||||||
else -> System.out
|
else -> System.out
|
||||||
}
|
}
|
||||||
output.println(msg)
|
output.println(msg)
|
||||||
|
|||||||
+1
-1
@@ -40,7 +40,7 @@ import javax.lang.model.element.*
|
|||||||
|
|
||||||
class AnnotationProcessingExtensionForTests(
|
class AnnotationProcessingExtensionForTests(
|
||||||
val processors: List<Processor>
|
val processors: List<Processor>
|
||||||
) : AbstractAnnotationProcessingExtension(createTempDir(), createTempDir(), listOf()) {
|
) : AbstractAnnotationProcessingExtension(createTempDir(), createTempDir(), listOf(), true) {
|
||||||
override fun loadAnnotationProcessors() = processors
|
override fun loadAnnotationProcessors() = processors
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
|||||||
Reference in New Issue
Block a user