kapt: Support inherited annotations in AP wrapper

This commit is contained in:
Yan Zhulanow
2015-06-23 18:14:27 +03:00
parent afa3ae4439
commit a90f175fc2
3 changed files with 51 additions and 7 deletions
@@ -108,8 +108,8 @@ public abstract class AnnotationProcessorWrapper(
override fun process(annotations: MutableSet<out TypeElement>?, roundEnv: RoundEnvironment): Boolean { override fun process(annotations: MutableSet<out TypeElement>?, roundEnv: RoundEnvironment): Boolean {
roundCounter += 1 roundCounter += 1
val annotatedKotlinElements = kotlinAnnotationsProvider.annotatedKotlinElements val roundEnvironmentWrapper = RoundEnvironmentWrapper(
val roundEnvironmentWrapper = RoundEnvironmentWrapper(processingEnv, roundEnv, roundCounter, annotatedKotlinElements) processingEnv, roundEnv, roundCounter, kotlinAnnotationsProvider)
processor.process(annotations, roundEnvironmentWrapper) processor.process(annotations, roundEnvironmentWrapper)
return false return false
} }
@@ -20,7 +20,6 @@ import java.io.File
import java.io.Reader import java.io.Reader
import java.io.StringReader import java.io.StringReader
import javax.tools.FileObject import javax.tools.FileObject
import kotlin.properties.Delegates
public abstract class KotlinAnnotationProvider { public abstract class KotlinAnnotationProvider {
@@ -31,12 +30,22 @@ public abstract class KotlinAnnotationProvider {
val SHORTENED_ANNOTATION = "a" val SHORTENED_ANNOTATION = "a"
val SHORTENED_PACKAGE_NAME = "p" val SHORTENED_PACKAGE_NAME = "p"
val CLASS_DECLARATION = "d"
} }
public val annotatedKotlinElements: Map<String, Set<AnnotatedElementDescriptor>> by Delegates.lazy { public val annotatedKotlinElements: Map<String, Set<AnnotatedElementDescriptor>> by lazy {
readAnnotations() readAnnotations()
} }
private val kotlinClassesInternal = hashSetOf<String>()
public val kotlinClasses: Set<String>
get() = kotlinClassesInternal
public val supportInheritedAnnotations: Boolean
get() = kotlinClassesInternal.isNotEmpty()
protected abstract val serializedAnnotations: Reader protected abstract val serializedAnnotations: Reader
private fun readAnnotations(): MutableMap<String, MutableSet<AnnotatedElementDescriptor>> { private fun readAnnotations(): MutableMap<String, MutableSet<AnnotatedElementDescriptor>> {
@@ -65,6 +74,10 @@ public abstract class KotlinAnnotationProvider {
when (type) { when (type) {
SHORTENED_ANNOTATION -> handleShortenedName(shortenedAnnotationCache, lineParts) SHORTENED_ANNOTATION -> handleShortenedName(shortenedAnnotationCache, lineParts)
SHORTENED_PACKAGE_NAME -> handleShortenedName(shortenedPackageNameCache, lineParts) SHORTENED_PACKAGE_NAME -> handleShortenedName(shortenedPackageNameCache, lineParts)
CLASS_DECLARATION -> {
val classFqName = expandClassName(lineParts[1]).replace('$', '.')
kotlinClassesInternal.add(classFqName)
}
ANNOTATED_CLASS, ANNOTATED_FIELD, ANNOTATED_METHOD -> { ANNOTATED_CLASS, ANNOTATED_FIELD, ANNOTATED_METHOD -> {
val annotationName = expandAnnotation(lineParts[1]) val annotationName = expandAnnotation(lineParts[1])
@@ -1,16 +1,19 @@
package org.jetbrains.kotlin.annotation package org.jetbrains.kotlin.annotation
import java.lang.annotation.Inherited
import javax.annotation.processing.ProcessingEnvironment import javax.annotation.processing.ProcessingEnvironment
import javax.annotation.processing.RoundEnvironment import javax.annotation.processing.RoundEnvironment
import javax.lang.model.element.Element import javax.lang.model.element.Element
import javax.lang.model.element.ElementKind import javax.lang.model.element.ElementKind
import javax.lang.model.element.TypeElement import javax.lang.model.element.TypeElement
import javax.lang.model.type.NoType
import javax.lang.model.type.TypeVisitor
private class RoundEnvironmentWrapper( private class RoundEnvironmentWrapper(
val processingEnv: ProcessingEnvironment, val processingEnv: ProcessingEnvironment,
val parent: RoundEnvironment, val parent: RoundEnvironment,
val roundNumber: Int, val roundNumber: Int,
val annotatedElementDescriptors: Map<String, Set<AnnotatedElementDescriptor>> val kotlinAnnotationsProvider: KotlinAnnotationProvider
) : RoundEnvironment { ) : RoundEnvironment {
override fun getRootElements(): MutableSet<out Element>? { override fun getRootElements(): MutableSet<out Element>? {
@@ -45,11 +48,23 @@ private class RoundEnvironmentWrapper(
return getAnnotationMirrors().any { annotationFqName == it.getAnnotationType().asElement().toString() } return getAnnotationMirrors().any { annotationFqName == it.getAnnotationType().asElement().toString() }
} }
private fun TypeElement.hasInheritedAnnotation(annotationFqName: String): Boolean {
if (hasAnnotation(annotationFqName)) return true
val superclassMirror = getSuperclass()
if (superclassMirror is NoType) return false
val superClass = processingEnv.getTypeUtils().asElement(superclassMirror)
if (superClass !is TypeElement) return false
return superClass.hasInheritedAnnotation(annotationFqName)
}
private fun resolveKotlinElements(annotationFqName: String): Set<Element> { private fun resolveKotlinElements(annotationFqName: String): Set<Element> {
if (roundNumber > 1) return setOf() if (roundNumber > 1) return setOf()
val descriptors = annotatedElementDescriptors.get(annotationFqName) ?: setOf() val descriptors = kotlinAnnotationsProvider.annotatedKotlinElements.get(annotationFqName) ?: setOf()
return descriptors.fold(hashSetOf<Element>()) { set, descriptor -> val descriptorsWithKotlin = descriptors.fold(hashSetOf<Element>()) { set, descriptor ->
val clazz = processingEnv.getElementUtils().getTypeElement(descriptor.classFqName) ?: return@fold set val clazz = processingEnv.getElementUtils().getTypeElement(descriptor.classFqName) ?: return@fold set
when (descriptor) { when (descriptor) {
is AnnotatedClassDescriptor -> set.add(clazz) is AnnotatedClassDescriptor -> set.add(clazz)
@@ -68,5 +83,21 @@ private class RoundEnvironmentWrapper(
} }
set set
} }
if (kotlinAnnotationsProvider.supportInheritedAnnotations) {
val isInherited = processingEnv.getElementUtils().getTypeElement(annotationFqName)
?.hasAnnotation(javaClass<Inherited>().getCanonicalName()) ?: false
if (isInherited) {
kotlinAnnotationsProvider.kotlinClasses.forEach { classFqName ->
val clazz = processingEnv.getElementUtils().getTypeElement(classFqName) ?: return@forEach
if (clazz.hasInheritedAnnotation(annotationFqName)) {
descriptorsWithKotlin.add(clazz)
}
}
}
}
return descriptorsWithKotlin
} }
} }