Kapt: Provide SourceRetentionAnnotationHandler for incremental compilation.
Collect annotations with the "SOURCE" retention. (cherry picked from commit 6ef66e7)
This commit is contained in:
committed by
Yan Zhulanow
parent
c3ae66bc9c
commit
975364b2ed
+27
-9
@@ -25,9 +25,15 @@ import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.annotation.processing.RoundAnnotations
|
||||
import org.jetbrains.kotlin.annotation.processing.diagnostic.ErrorsAnnotationProcessing
|
||||
import org.jetbrains.kotlin.annotation.processing.impl.*
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderMode
|
||||
import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.config.APPEND_JAVA_SOURCE_ROOTS_HANDLER_KEY
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
|
||||
import org.jetbrains.kotlin.java.model.elements.JeTypeElement
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
|
||||
@@ -44,9 +50,11 @@ class ClasspathBasedAnnotationProcessingExtension(
|
||||
classesOutputDir: File,
|
||||
javaSourceRoots: List<File>,
|
||||
verboseOutput: Boolean,
|
||||
incrementalDataFile: File?
|
||||
incrementalDataFile: File?,
|
||||
incrementalCompilationComponents: IncrementalCompilationComponents?
|
||||
) : AbstractAnnotationProcessingExtension(generatedSourcesOutputDir,
|
||||
classesOutputDir, javaSourceRoots, verboseOutput, incrementalDataFile) {
|
||||
classesOutputDir, javaSourceRoots, verboseOutput,
|
||||
incrementalDataFile, incrementalCompilationComponents) {
|
||||
override fun loadAnnotationProcessors(): List<Processor> {
|
||||
val classLoader = URLClassLoader(annotationProcessingClasspath.map { it.toURI().toURL() }.toTypedArray())
|
||||
return ServiceLoader.load(Processor::class.java, classLoader).toList()
|
||||
@@ -58,7 +66,8 @@ abstract class AbstractAnnotationProcessingExtension(
|
||||
val classesOutputDir: File,
|
||||
val javaSourceRoots: List<File>,
|
||||
val verboseOutput: Boolean,
|
||||
val incrementalDataFile: File? = null
|
||||
val incrementalDataFile: File? = null,
|
||||
val incrementalCompilationComponents: IncrementalCompilationComponents? = null
|
||||
) : AnalysisCompletedHandlerExtension {
|
||||
private companion object {
|
||||
val LINE_SEPARATOR = System.getProperty("line.separator") ?: "\n"
|
||||
@@ -116,7 +125,7 @@ abstract class AbstractAnnotationProcessingExtension(
|
||||
|
||||
val processingEnvironment = KotlinProcessingEnvironment(
|
||||
elements, types, messager, options, filer, processors,
|
||||
project, psiManager, javaPsiFacade, projectScope, appendJavaSourceRootsHandler)
|
||||
project, psiManager, javaPsiFacade, projectScope, bindingTrace.bindingContext, appendJavaSourceRootsHandler)
|
||||
|
||||
val processingResult = processingEnvironment.doAnnotationProcessing(files)
|
||||
|
||||
@@ -148,6 +157,11 @@ abstract class AbstractAnnotationProcessingExtension(
|
||||
listOf(generatedSourcesOutputDir),
|
||||
addToEnvironment = false)
|
||||
}
|
||||
|
||||
private fun KotlinProcessingEnvironment.createTypeMapper(): KotlinTypeMapper {
|
||||
return KotlinTypeMapper(bindingContext, ClassBuilderMode.full(false), NoResolveFileClassesProvider,
|
||||
null, IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME)
|
||||
}
|
||||
|
||||
private fun KotlinProcessingEnvironment.doAnnotationProcessing(files: Collection<KtFile>): ProcessingResult {
|
||||
val allSupportedAnnotationFqNames = run initializeProcessors@ {
|
||||
@@ -156,7 +170,11 @@ abstract class AbstractAnnotationProcessingExtension(
|
||||
processors.flatMapTo(mutableSetOf()) { it.supportedAnnotationTypes }
|
||||
}
|
||||
|
||||
val firstRoundAnnotations = RoundAnnotations(allSupportedAnnotationFqNames)
|
||||
val firstRoundAnnotations = RoundAnnotations(
|
||||
allSupportedAnnotationFqNames,
|
||||
incrementalCompilationComponents?.getSourceRetentionAnnotationHandler(),
|
||||
bindingContext,
|
||||
createTypeMapper())
|
||||
|
||||
run analyzeFilesForFirstRound@ {
|
||||
log { "Analysing Kotlin files: " + files.map { it.virtualFile.path } }
|
||||
@@ -223,7 +241,7 @@ abstract class AbstractAnnotationProcessingExtension(
|
||||
} + 1
|
||||
|
||||
log { "Starting round $finalRoundNumber (final)" }
|
||||
val finalRoundEnvironment = KotlinRoundEnvironment(RoundAnnotations(allSupportedAnnotationFqNames), true, finalRoundNumber)
|
||||
val finalRoundEnvironment = KotlinRoundEnvironment(firstRoundAnnotations.copy(), true, finalRoundNumber)
|
||||
for (processor in processors) {
|
||||
processor.process(emptySet(), finalRoundEnvironment)
|
||||
}
|
||||
@@ -258,7 +276,7 @@ abstract class AbstractAnnotationProcessingExtension(
|
||||
}
|
||||
|
||||
// Start the next round
|
||||
val nextRoundAnnotations = RoundAnnotations(roundEnvironment.supportedAnnotationFqNames).apply { analyzeFiles(psiFiles) }
|
||||
val nextRoundAnnotations = roundEnvironment.roundAnnotations.copy().apply { analyzeFiles(psiFiles) }
|
||||
val nextRoundEnvironment = KotlinRoundEnvironment(nextRoundAnnotations, false, roundEnvironment.roundNumber + 1)
|
||||
return process(nextRoundEnvironment)
|
||||
}
|
||||
@@ -274,8 +292,8 @@ abstract class AbstractAnnotationProcessingExtension(
|
||||
val acceptsAnyAnnotation = supportedAnnotationNames.contains("*")
|
||||
|
||||
val applicableAnnotationNames = when (acceptsAnyAnnotation) {
|
||||
true -> roundEnvironment.annotationsMap.keys
|
||||
false -> processor.supportedAnnotationTypes.filter { it in roundEnvironment.annotationsMap }
|
||||
true -> roundEnvironment.roundAnnotations.annotationsMap.keys
|
||||
false -> processor.supportedAnnotationTypes.filter { it in roundEnvironment.roundAnnotations.annotationsMap }
|
||||
}
|
||||
|
||||
if (applicableAnnotationNames.isEmpty()) {
|
||||
|
||||
+4
-1
@@ -122,8 +122,11 @@ class AnnotationProcessingComponentRegistrar : ComponentRegistrar {
|
||||
// Annotations with the "SOURCE" retention will be written to class files
|
||||
project.putUserData(IS_KAPT2_ENABLED_KEY, true)
|
||||
|
||||
val incrementalCompilationComponents = configuration[JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS]
|
||||
|
||||
val annotationProcessingExtension = ClasspathBasedAnnotationProcessingExtension(
|
||||
classpath, generatedOutputDirFile, classesOutputDir, javaRoots, verboseOutput, incrementalDataFile)
|
||||
classpath, generatedOutputDirFile, classesOutputDir, javaRoots, verboseOutput,
|
||||
incrementalDataFile, incrementalCompilationComponents)
|
||||
|
||||
AnalysisCompletedHandlerExtension.registerExtension(project, annotationProcessingExtension)
|
||||
}
|
||||
|
||||
+34
-1
@@ -18,13 +18,22 @@ package org.jetbrains.kotlin.annotation.processing
|
||||
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotation
|
||||
import org.jetbrains.kotlin.asJava.findFacadeClass
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.incremental.components.SourceRetentionAnnotationHandler
|
||||
import org.jetbrains.kotlin.java.model.internal.getAnnotationsWithInherited
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
internal class RoundAnnotations(val supportedAnnotationFqNames: Set<String>) {
|
||||
internal class RoundAnnotations(
|
||||
val supportedAnnotationFqNames: Set<String>,
|
||||
val sourceRetentionAnnotationHandler: SourceRetentionAnnotationHandler?,
|
||||
val bindingContext: BindingContext,
|
||||
val typeMapper: KotlinTypeMapper
|
||||
) {
|
||||
private val mutableAnnotationsMap = mutableMapOf<String, MutableList<PsiModifierListOwner>>()
|
||||
private val mutableAnalyzedClasses = mutableSetOf<String>()
|
||||
|
||||
@@ -35,6 +44,8 @@ internal class RoundAnnotations(val supportedAnnotationFqNames: Set<String>) {
|
||||
|
||||
val analyzedClasses: Set<String>
|
||||
get() = mutableAnalyzedClasses
|
||||
|
||||
fun copy() = RoundAnnotations(supportedAnnotationFqNames, sourceRetentionAnnotationHandler, bindingContext, typeMapper)
|
||||
|
||||
fun analyzeFiles(files: Collection<KtFile>) = files.forEach { analyzeFile(it) }
|
||||
|
||||
@@ -63,6 +74,18 @@ internal class RoundAnnotations(val supportedAnnotationFqNames: Set<String>) {
|
||||
is PsiClass -> containingClass?.let { it.getTopLevelClassParent() } ?: this
|
||||
else -> PsiTreeUtil.getParentOfType(this, PsiClass::class.java, true)?.getTopLevelClassParent()
|
||||
}
|
||||
|
||||
private val PsiAnnotation.hasSourceRetention: Boolean
|
||||
get() {
|
||||
val annotationDeclaration = nameReferenceElement?.resolve() as? PsiClass ?: return false
|
||||
val metaAnnotations = annotationDeclaration.modifierList?.annotations ?: return false
|
||||
return metaAnnotations.any { anno ->
|
||||
val declaration = anno.nameReferenceElement?.resolve() as? PsiClass ?: return@any false
|
||||
if (declaration.qualifiedName != "java.lang.annotation.Retention") return@any false
|
||||
val value = (anno.findAttributeValue("value") as? PsiReferenceExpression)?.resolve() ?: return@any false
|
||||
value is PsiEnumConstant && value.name == "SOURCE"
|
||||
}
|
||||
}
|
||||
|
||||
fun analyzeDeclaration(declaration: PsiElement): Boolean {
|
||||
if (declaration !is PsiModifierListOwner) return false
|
||||
@@ -72,6 +95,16 @@ internal class RoundAnnotations(val supportedAnnotationFqNames: Set<String>) {
|
||||
|
||||
for (annotation in declaration.getAnnotationsWithInherited()) {
|
||||
val fqName = annotation.qualifiedName ?: continue
|
||||
|
||||
val ktLightAnnotation = annotation as? KtLightAnnotation
|
||||
if (ktLightAnnotation != null && sourceRetentionAnnotationHandler != null && ktLightAnnotation.hasSourceRetention) {
|
||||
val type = bindingContext[BindingContext.ANNOTATION, ktLightAnnotation.kotlinOrigin]?.type
|
||||
if (type != null) {
|
||||
val internalName = typeMapper.mapType(type).internalName
|
||||
sourceRetentionAnnotationHandler.register(internalName)
|
||||
}
|
||||
}
|
||||
|
||||
if (!acceptsAnyAnnotation && fqName !in supportedAnnotationFqNames) continue
|
||||
mutableAnnotationsMap.getOrPut(fqName, { mutableListOf() }).add(declaration)
|
||||
|
||||
|
||||
+2
@@ -20,6 +20,7 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.JavaPsiFacade
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import javax.annotation.processing.ProcessingEnvironment
|
||||
@@ -41,6 +42,7 @@ class KotlinProcessingEnvironment(
|
||||
internal val psiManager: PsiManager,
|
||||
internal val javaPsiFacade: JavaPsiFacade,
|
||||
internal val projectScope: GlobalSearchScope,
|
||||
internal val bindingContext: BindingContext,
|
||||
internal val appendJavaSourceRootsHandler: (List<File>) -> Unit
|
||||
) : ProcessingEnvironment {
|
||||
private val options = Collections.unmodifiableMap(options)
|
||||
|
||||
+1
-8
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.annotation.processing.impl
|
||||
|
||||
import com.intellij.psi.PsiModifierListOwner
|
||||
import org.jetbrains.kotlin.annotation.processing.RoundAnnotations
|
||||
import org.jetbrains.kotlin.java.model.toJeElement
|
||||
import javax.annotation.processing.RoundEnvironment
|
||||
@@ -24,18 +23,12 @@ import javax.lang.model.element.Element
|
||||
import javax.lang.model.element.TypeElement
|
||||
|
||||
internal class KotlinRoundEnvironment(
|
||||
private val roundAnnotations: RoundAnnotations,
|
||||
val roundAnnotations: RoundAnnotations,
|
||||
private val isProcessingOver: Boolean,
|
||||
internal val roundNumber: Int
|
||||
) : RoundEnvironment {
|
||||
private var isError = false
|
||||
|
||||
internal val annotationsMap: Map<String, List<PsiModifierListOwner>>
|
||||
get() = roundAnnotations.annotationsMap
|
||||
|
||||
internal val supportedAnnotationFqNames: Set<String>
|
||||
get() = roundAnnotations.supportedAnnotationFqNames
|
||||
|
||||
override fun getRootElements() = emptySet<Element>()
|
||||
|
||||
override fun processingOver() = isProcessingOver
|
||||
|
||||
Reference in New Issue
Block a user