Incremental KAPT - handle inherited annotations
Handle annotations with @Inherited. This is important for the aggregating APs, as the current implementation passes all sources annotated with claimed aggregating annotations. Issue is https://youtrack.jetbrains.com/issue/KT-23880
This commit is contained in:
committed by
Alexey Tsvetkov
parent
9f14daa682
commit
2f3d234516
+1
-3
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.kapt3.base
|
package org.jetbrains.kotlin.kapt3.base
|
||||||
|
|
||||||
import com.sun.source.util.Trees
|
|
||||||
import com.sun.tools.javac.comp.CompileStates.CompileState
|
import com.sun.tools.javac.comp.CompileStates.CompileState
|
||||||
import com.sun.tools.javac.main.JavaCompiler
|
import com.sun.tools.javac.main.JavaCompiler
|
||||||
import com.sun.tools.javac.processing.AnnotationProcessingError
|
import com.sun.tools.javac.processing.AnnotationProcessingError
|
||||||
@@ -54,7 +53,7 @@ fun KaptContext.doAnnotationProcessing(
|
|||||||
val listener = cacheManager?.let {
|
val listener = cacheManager?.let {
|
||||||
if (processors.any { it.kind == DeclaredProcType.NON_INCREMENTAL}) return@let null
|
if (processors.any { it.kind == DeclaredProcType.NON_INCREMENTAL}) return@let null
|
||||||
|
|
||||||
val recordTypesListener = MentionedTypesTaskListener(cacheManager.javaCache, Trees.instance(processingEnvironment))
|
val recordTypesListener = MentionedTypesTaskListener(cacheManager.javaCache, processingEnvironment.elementUtils)
|
||||||
compiler.getTaskListeners().add(recordTypesListener)
|
compiler.getTaskListeners().add(recordTypesListener)
|
||||||
recordTypesListener
|
recordTypesListener
|
||||||
}
|
}
|
||||||
@@ -67,7 +66,6 @@ fun KaptContext.doAnnotationProcessing(
|
|||||||
|
|
||||||
listener?.let { compiler.getTaskListeners().remove(it) }
|
listener?.let { compiler.getTaskListeners().remove(it) }
|
||||||
|
|
||||||
val l = System.currentTimeMillis()
|
|
||||||
if (isJava9OrLater()) {
|
if (isJava9OrLater()) {
|
||||||
val processAnnotationsMethod = compiler.javaClass.getMethod("processAnnotations", JavacList::class.java)
|
val processAnnotationsMethod = compiler.javaClass.getMethod("processAnnotations", JavacList::class.java)
|
||||||
processAnnotationsMethod.invoke(compiler, analyzedFiles)
|
processAnnotationsMethod.invoke(compiler, analyzedFiles)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class JavaClassCacheManager(private val file: File, private val classpathFqNames
|
|||||||
}
|
}
|
||||||
|
|
||||||
val dirtyFqNames = mutableSetOf<String>()
|
val dirtyFqNames = mutableSetOf<String>()
|
||||||
after.forEach{ file ->
|
after.forEach { file ->
|
||||||
ObjectInputStream(file.inputStream().buffered()).use {
|
ObjectInputStream(file.inputStream().buffered()).use {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
dirtyFqNames.addAll(it.readObject() as Collection<String>)
|
dirtyFqNames.addAll(it.readObject() as Collection<String>)
|
||||||
@@ -90,7 +90,7 @@ class JavaClassCacheManager(private val file: File, private val classpathFqNames
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maybeGetAptCacheFromFile(): IncrementalAptCache{
|
private fun maybeGetAptCacheFromFile(): IncrementalAptCache {
|
||||||
|
|
||||||
return if (aptCacheFile.exists()) {
|
return if (aptCacheFile.exists()) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
+1
-1
@@ -51,7 +51,7 @@ class JavaClassCache() : Serializable {
|
|||||||
internal fun getStructure(sourceFile: File) = sourceCache[sourceFile.toURI()]
|
internal fun getStructure(sourceFile: File) = sourceCache[sourceFile.toURI()]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidate cache entires for the specified files, and any files that depend on the changed ones. It returns the set of files that
|
* Invalidate cache entries for the specified files, and any files that depend on the changed ones. It returns the set of files that
|
||||||
* should be re-processed.
|
* should be re-processed.
|
||||||
* */
|
* */
|
||||||
fun invalidateEntriesForChangedFiles(changes: Changes): SourcesToReprocess {
|
fun invalidateEntriesForChangedFiles(changes: Changes): SourcesToReprocess {
|
||||||
|
|||||||
+2
-1
@@ -17,7 +17,8 @@ private const val INCREMENTAL_ANNOTATION_FLAG = "META-INF/gradle/incremental.ann
|
|||||||
|
|
||||||
/** Checks the incremental annotation processor information for the annotation processor classpath. */
|
/** Checks the incremental annotation processor information for the annotation processor classpath. */
|
||||||
fun getIncrementalProcessorsFromClasspath(
|
fun getIncrementalProcessorsFromClasspath(
|
||||||
names: Set<String>, classpath: Iterable<File>): Map<String, DeclaredProcType> {
|
names: Set<String>, classpath: Iterable<File>
|
||||||
|
): Map<String, DeclaredProcType> {
|
||||||
val finalValues = mutableMapOf<String, DeclaredProcType>()
|
val finalValues = mutableMapOf<String, DeclaredProcType>()
|
||||||
|
|
||||||
classpath.forEach { entry ->
|
classpath.forEach { entry ->
|
||||||
|
|||||||
-5
@@ -7,11 +7,7 @@ package org.jetbrains.kotlin.kapt3.base.incremental
|
|||||||
|
|
||||||
import com.sun.tools.javac.code.Symbol
|
import com.sun.tools.javac.code.Symbol
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.util.*
|
|
||||||
import java.util.zip.ZipEntry
|
|
||||||
import java.util.zip.ZipFile
|
|
||||||
import javax.annotation.processing.Filer
|
import javax.annotation.processing.Filer
|
||||||
import javax.annotation.processing.ProcessingEnvironment
|
import javax.annotation.processing.ProcessingEnvironment
|
||||||
import javax.annotation.processing.Processor
|
import javax.annotation.processing.Processor
|
||||||
@@ -118,7 +114,6 @@ internal class AnnotationProcessorDependencyCollector(private val runtimeProcTyp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal fun getGeneratedToSources(): Map<File, File?> = if (isFullRebuild) emptyMap() else generatedToSource
|
internal fun getGeneratedToSources(): Map<File, File?> = if (isFullRebuild) emptyMap() else generatedToSource
|
||||||
internal fun getRuntimeType(): RuntimeProcType {
|
internal fun getRuntimeType(): RuntimeProcType {
|
||||||
return if (isFullRebuild) {
|
return if (isFullRebuild) {
|
||||||
|
|||||||
+17
-4
@@ -9,15 +9,17 @@ import com.sun.source.tree.*
|
|||||||
import com.sun.source.util.SimpleTreeVisitor
|
import com.sun.source.util.SimpleTreeVisitor
|
||||||
import com.sun.source.util.TaskEvent
|
import com.sun.source.util.TaskEvent
|
||||||
import com.sun.source.util.TaskListener
|
import com.sun.source.util.TaskListener
|
||||||
import com.sun.source.util.Trees
|
|
||||||
import com.sun.tools.javac.code.Symbol
|
import com.sun.tools.javac.code.Symbol
|
||||||
import com.sun.tools.javac.tree.JCTree
|
import com.sun.tools.javac.tree.JCTree
|
||||||
|
import java.io.File
|
||||||
import javax.lang.model.element.ElementKind
|
import javax.lang.model.element.ElementKind
|
||||||
import javax.lang.model.element.Modifier
|
import javax.lang.model.element.Modifier
|
||||||
|
import javax.lang.model.element.TypeElement
|
||||||
|
import javax.lang.model.util.Elements
|
||||||
|
|
||||||
class MentionedTypesTaskListener(
|
class MentionedTypesTaskListener(
|
||||||
private val cache: JavaClassCache,
|
private val cache: JavaClassCache,
|
||||||
private val trees: Trees
|
private val elementUtils: Elements
|
||||||
) : TaskListener {
|
) : TaskListener {
|
||||||
|
|
||||||
var time = 0L
|
var time = 0L
|
||||||
@@ -33,7 +35,7 @@ class MentionedTypesTaskListener(
|
|||||||
|
|
||||||
val structure = SourceFileStructure(e.sourceFile.toUri())
|
val structure = SourceFileStructure(e.sourceFile.toUri())
|
||||||
|
|
||||||
val treeVisitor = TypeTreeVisitor(compilationUnit, trees, structure)
|
val treeVisitor = TypeTreeVisitor(elementUtils, structure)
|
||||||
compilationUnit.typeDecls.forEach {
|
compilationUnit.typeDecls.forEach {
|
||||||
it.accept(treeVisitor, Visibility.ABI)
|
it.accept(treeVisitor, Visibility.ABI)
|
||||||
}
|
}
|
||||||
@@ -46,14 +48,25 @@ private enum class Visibility {
|
|||||||
ABI, NON_ABI
|
ABI, NON_ABI
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TypeTreeVisitor(val unit: CompilationUnitTree, val trees: Trees, val sourceStructure: SourceFileStructure) :
|
private class TypeTreeVisitor(val elementUtils: Elements, val sourceStructure: SourceFileStructure) :
|
||||||
SimpleTreeVisitor<Void, Visibility>() {
|
SimpleTreeVisitor<Void, Visibility>() {
|
||||||
|
|
||||||
|
/** Handle annotations on this class, including the @Inherited ones as those are not visible using Tree APIs. */
|
||||||
|
private fun handleClassAnnotations(classSymbol: Symbol.ClassSymbol) {
|
||||||
|
elementUtils.getAllAnnotationMirrors(classSymbol).forEach {
|
||||||
|
(it.annotationType.asElement() as? TypeElement)?.let {
|
||||||
|
sourceStructure.addMentionedAnnotations(it.qualifiedName.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitClass(node: ClassTree, visibility: Visibility): Void? {
|
override fun visitClass(node: ClassTree, visibility: Visibility): Void? {
|
||||||
node as JCTree.JCClassDecl
|
node as JCTree.JCClassDecl
|
||||||
sourceStructure.addDeclaredType(node.sym.fullname.toString())
|
sourceStructure.addDeclaredType(node.sym.fullname.toString())
|
||||||
sourceStructure.addMentionedType(node.sym.fullname.toString())
|
sourceStructure.addMentionedType(node.sym.fullname.toString())
|
||||||
|
|
||||||
|
handleClassAnnotations(node.sym)
|
||||||
|
|
||||||
node.modifiers.annotations.forEach { visit(it, visibility) }
|
node.modifiers.annotations.forEach { visit(it, visibility) }
|
||||||
node.typeParameters.forEach { visit(it, visibility) }
|
node.typeParameters.forEach { visit(it, visibility) }
|
||||||
visit(node.extendsClause, visibility)
|
visit(node.extendsClause, visibility)
|
||||||
|
|||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.kapt.base.test.org.jetbrains.kotlin.kapt3.base.incremental
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.kapt3.base.incremental.JavaClassCacheManager
|
||||||
|
import org.jetbrains.kotlin.kapt3.base.incremental.MentionedTypesTaskListener
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.BeforeClass
|
||||||
|
import org.junit.ClassRule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.rules.TemporaryFolder
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
private val MY_TEST_DIR = File("plugins/kapt3/kapt3-base/testData/runner/incremental/complex/inherited")
|
||||||
|
|
||||||
|
class TestInheritedAnnotation {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@ClassRule
|
||||||
|
@JvmField
|
||||||
|
var tmp = TemporaryFolder()
|
||||||
|
|
||||||
|
private lateinit var cache: JavaClassCacheManager
|
||||||
|
private lateinit var generatedSources: File
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@BeforeClass
|
||||||
|
fun setUp() {
|
||||||
|
val classpathHistory = tmp.newFolder()
|
||||||
|
cache = JavaClassCacheManager(tmp.newFolder(), classpathHistory)
|
||||||
|
generatedSources = tmp.newFolder()
|
||||||
|
cache.close()
|
||||||
|
classpathHistory.resolve("0").createNewFile()
|
||||||
|
val processor = SimpleProcessor().toAggregating()
|
||||||
|
val srcFiles = listOf(
|
||||||
|
"BaseClass.java",
|
||||||
|
"InheritableAnnotation.java",
|
||||||
|
"ExtendsBase.java"
|
||||||
|
).map { File(MY_TEST_DIR, it) }
|
||||||
|
runAnnotationProcessing(
|
||||||
|
srcFiles,
|
||||||
|
listOf(processor),
|
||||||
|
generatedSources
|
||||||
|
) { trees -> MentionedTypesTaskListener(cache.javaCache, trees) }
|
||||||
|
cache.updateCache(listOf(processor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAnnotationInherited() {
|
||||||
|
val shouldInheritAnnotation = cache.javaCache.getStructure(MY_TEST_DIR.resolve("ExtendsBase.java"))!!
|
||||||
|
|
||||||
|
assertEquals(setOf("test.ExtendsBase"), shouldInheritAnnotation.getDeclaredTypes())
|
||||||
|
assertEquals(setOf("test.InheritableAnnotation"), shouldInheritAnnotation.getMentionedAnnotations())
|
||||||
|
assertEquals(emptySet<String>(), shouldInheritAnnotation.getPrivateTypes())
|
||||||
|
assertEquals(
|
||||||
|
setOf(
|
||||||
|
"test.ExtendsBase",
|
||||||
|
"test.BaseClass"
|
||||||
|
), shouldInheritAnnotation.getMentionedTypes()
|
||||||
|
)
|
||||||
|
assertEquals(emptyMap<String, String>(), shouldInheritAnnotation.getDefinedConstants())
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -73,7 +73,7 @@ class TestSimpleIncrementalAptCache {
|
|||||||
srcFiles,
|
srcFiles,
|
||||||
listOf(processor),
|
listOf(processor),
|
||||||
generatedSources
|
generatedSources
|
||||||
) { trees -> MentionedTypesTaskListener(cache.javaCache, trees) }
|
) { elementUtils -> MentionedTypesTaskListener(cache.javaCache, elementUtils) }
|
||||||
cache.updateCache(listOf(processor))
|
cache.updateCache(listOf(processor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-3
@@ -6,7 +6,6 @@
|
|||||||
package org.jetbrains.kotlin.kapt.base.test.org.jetbrains.kotlin.kapt3.base.incremental
|
package org.jetbrains.kotlin.kapt.base.test.org.jetbrains.kotlin.kapt3.base.incremental
|
||||||
|
|
||||||
import com.sun.source.util.TaskListener
|
import com.sun.source.util.TaskListener
|
||||||
import com.sun.source.util.Trees
|
|
||||||
import com.sun.tools.javac.api.JavacTaskImpl
|
import com.sun.tools.javac.api.JavacTaskImpl
|
||||||
import org.jetbrains.kotlin.kapt3.base.incremental.DeclaredProcType
|
import org.jetbrains.kotlin.kapt3.base.incremental.DeclaredProcType
|
||||||
import org.jetbrains.kotlin.kapt3.base.incremental.IncrementalProcessor
|
import org.jetbrains.kotlin.kapt3.base.incremental.IncrementalProcessor
|
||||||
@@ -18,6 +17,7 @@ import javax.annotation.processing.ProcessingEnvironment
|
|||||||
import javax.annotation.processing.RoundEnvironment
|
import javax.annotation.processing.RoundEnvironment
|
||||||
import javax.lang.model.SourceVersion
|
import javax.lang.model.SourceVersion
|
||||||
import javax.lang.model.element.TypeElement
|
import javax.lang.model.element.TypeElement
|
||||||
|
import javax.lang.model.util.Elements
|
||||||
import javax.tools.StandardLocation
|
import javax.tools.StandardLocation
|
||||||
import javax.tools.ToolProvider
|
import javax.tools.ToolProvider
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ fun runAnnotationProcessing(
|
|||||||
srcFiles: List<File>,
|
srcFiles: List<File>,
|
||||||
processor: List<IncrementalProcessor>,
|
processor: List<IncrementalProcessor>,
|
||||||
generatedSources: File,
|
generatedSources: File,
|
||||||
listener: (Trees) -> TaskListener? = { null }
|
listener: (Elements) -> TaskListener? = { null }
|
||||||
) {
|
) {
|
||||||
val compiler = ToolProvider.getSystemJavaCompiler()
|
val compiler = ToolProvider.getSystemJavaCompiler()
|
||||||
compiler.getStandardFileManager(null, null, null).use { fileManager ->
|
compiler.getStandardFileManager(null, null, null).use { fileManager ->
|
||||||
@@ -42,7 +42,7 @@ fun runAnnotationProcessing(
|
|||||||
javaSrcs
|
javaSrcs
|
||||||
) as JavacTaskImpl
|
) as JavacTaskImpl
|
||||||
|
|
||||||
val taskListener = listener(Trees.instance(compilationTask))
|
val taskListener = listener(compilationTask.elements)
|
||||||
taskListener?.let { compilationTask.addTaskListener(it) }
|
taskListener?.let { compilationTask.addTaskListener(it) }
|
||||||
|
|
||||||
compilationTask.setProcessors(processor)
|
compilationTask.setProcessors(processor)
|
||||||
|
|||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
package test;
|
||||||
|
|
||||||
|
@InheritableAnnotation
|
||||||
|
public class BaseClass {}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
package test;
|
||||||
|
|
||||||
|
public class ExtendsBase extends BaseClass {}
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
package test;
|
||||||
|
|
||||||
|
@java.lang.annotation.Inherited
|
||||||
|
public @interface InheritableAnnotation {}
|
||||||
Reference in New Issue
Block a user