Kapt: verbose output mode

(cherry picked from commit e6067d5)
This commit is contained in:
Yan Zhulanow
2016-08-04 22:41:01 +03:00
committed by Yan Zhulanow
parent f5d58d9944
commit 399059729d
4 changed files with 64 additions and 14 deletions
@@ -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,10 +52,16 @@ 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,
module: ModuleDescriptor, module: ModuleDescriptor,
@@ -63,13 +71,20 @@ abstract class AbstractAnnotationProcessingExtension(
if (annotationProcessingComplete) { if (annotationProcessingComplete) {
return null return null
} }
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,20 +124,31 @@ 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))
@@ -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)
} }
} }
@@ -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)
@@ -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 {