Kapt: verbose output mode
(cherry picked from commit e6067d5)
This commit is contained in:
committed by
Yan Zhulanow
parent
f5d58d9944
commit
399059729d
+38
-10
@@ -34,13 +34,15 @@ import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
import java.util.*
|
||||
import javax.annotation.processing.Processor
|
||||
import javax.tools.Diagnostic
|
||||
|
||||
class ClasspathBasedAnnotationProcessingExtension(
|
||||
val annotationProcessingClasspath: List<String>,
|
||||
generatedSourcesOutputDir: File,
|
||||
classesOutputDir: File,
|
||||
javaSourceRoots: List<File>
|
||||
) : AbstractAnnotationProcessingExtension(generatedSourcesOutputDir, classesOutputDir, javaSourceRoots) {
|
||||
javaSourceRoots: List<File>,
|
||||
verboseOutput: Boolean
|
||||
) : AbstractAnnotationProcessingExtension(generatedSourcesOutputDir, classesOutputDir, javaSourceRoots, verboseOutput) {
|
||||
override fun loadAnnotationProcessors(): List<Processor> {
|
||||
val classLoader = URLClassLoader(annotationProcessingClasspath.map { File(it).toURI().toURL() }.toTypedArray())
|
||||
return ServiceLoader.load(Processor::class.java, classLoader).toList()
|
||||
@@ -50,10 +52,16 @@ class ClasspathBasedAnnotationProcessingExtension(
|
||||
abstract class AbstractAnnotationProcessingExtension(
|
||||
val generatedSourcesOutputDir: File,
|
||||
val classesOutputDir: File,
|
||||
val javaSourceRoots: List<File>
|
||||
val javaSourceRoots: List<File>,
|
||||
val verboseOutput: Boolean
|
||||
) : AnalysisCompletedHandlerExtension {
|
||||
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(
|
||||
project: Project,
|
||||
module: ModuleDescriptor,
|
||||
@@ -63,13 +71,20 @@ abstract class AbstractAnnotationProcessingExtension(
|
||||
if (annotationProcessingComplete) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
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())
|
||||
analysisContext.analyzeFiles(files)
|
||||
|
||||
log { "Analysing Java source roots: $javaSourceRoots" }
|
||||
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
for (javaSourceRoot in javaSourceRoots) {
|
||||
javaSourceRoot.walk().filter { it.isFile && it.extension == "java" }.forEach {
|
||||
@@ -84,19 +99,21 @@ abstract class AbstractAnnotationProcessingExtension(
|
||||
}
|
||||
|
||||
val options = emptyMap<String, String>()
|
||||
log { "Options: $options" }
|
||||
|
||||
val javaPsiFacade = JavaPsiFacade.getInstance(project)
|
||||
val projectScope = GlobalSearchScope.projectScope(project)
|
||||
|
||||
val filer = KotlinFiler(generatedSourcesOutputDir, classesOutputDir)
|
||||
val messages = KotlinMessager()
|
||||
val types = KotlinTypes(javaPsiFacade, PsiManager.getInstance(project), 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) }
|
||||
|
||||
// Round 1
|
||||
log { "Initialized processors: " + processors.joinToString { it.javaClass.name } }
|
||||
|
||||
log { "Starting round 1" }
|
||||
val round1Environment = KotlinRoundEnvironment(analysisContext)
|
||||
for (processor in processors) {
|
||||
val supportedAnnotationNames = processor.supportedAnnotationTypes
|
||||
@@ -107,20 +124,31 @@ abstract class AbstractAnnotationProcessingExtension(
|
||||
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
|
||||
.map { javaPsiFacade.findClass(it, projectScope)?.let { JeTypeElement(it) } }
|
||||
.filterNotNullTo(hashSetOf())
|
||||
|
||||
log {
|
||||
val annotationNames = applicableAnnotations.joinToString { it.qualifiedName.toString() }
|
||||
"Processing with " + processor.javaClass.name + " (annotations: " + annotationNames + ")"
|
||||
}
|
||||
|
||||
processor.process(applicableAnnotations, round1Environment)
|
||||
}
|
||||
|
||||
// Round 2
|
||||
log { "Starting round 2 (final)" }
|
||||
val round2Environment = KotlinRoundEnvironment(AnalysisContext(hashMapOf()), isProcessingOver = true)
|
||||
for (processor in processors) {
|
||||
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
|
||||
return AnalysisResult.RetryWithAdditionalJavaRoots(bindingContext, module, listOf(generatedSourcesOutputDir))
|
||||
|
||||
+11
-2
@@ -37,6 +37,9 @@ object AnnotationProcessingConfigurationKeys {
|
||||
|
||||
val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> =
|
||||
CompilerConfigurationKey.create<List<String>>("annotation processor classpath")
|
||||
|
||||
val VERBOSE_MODE: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>("verbose mode")
|
||||
}
|
||||
|
||||
class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
|
||||
@@ -52,12 +55,15 @@ class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
|
||||
val ANNOTATION_PROCESSOR_CLASSPATH_OPTION: CliOption =
|
||||
CliOption("apclasspath", "<classpath>", "Annotation processor classpath",
|
||||
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 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) {
|
||||
when (option) {
|
||||
@@ -68,6 +74,7 @@ class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
|
||||
}
|
||||
GENERATED_OUTPUT_DIR_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.GENERATED_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}")
|
||||
}
|
||||
}
|
||||
@@ -88,8 +95,10 @@ class AnnotationProcessingComponentRegistrar : ComponentRegistrar {
|
||||
val classesOutputDir = File(configuration.get(AnnotationProcessingConfigurationKeys.CLASS_FILES_OUTPUT_DIR)
|
||||
?: configuration[JVMConfigurationKeys.MODULES]!!.first().getOutputDirectory())
|
||||
|
||||
val verboseOutput = configuration.get(AnnotationProcessingConfigurationKeys.VERBOSE_MODE) == "true"
|
||||
|
||||
val annotationProcessingExtension = ClasspathBasedAnnotationProcessingExtension(
|
||||
classpath, generatedOutputDirFile, classesOutputDir, javaRoots)
|
||||
classpath, generatedOutputDirFile, classesOutputDir, javaRoots, verboseOutput)
|
||||
AnalysisCompletedHandlerExtension.registerExtension(project, annotationProcessingExtension)
|
||||
}
|
||||
}
|
||||
+14
-1
@@ -24,6 +24,12 @@ import javax.tools.Diagnostic
|
||||
import javax.tools.Diagnostic.Kind
|
||||
|
||||
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, 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?) {
|
||||
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
|
||||
}
|
||||
output.println(msg)
|
||||
|
||||
Reference in New Issue
Block a user