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
|
||||
|
||||
import com.sun.source.util.Trees
|
||||
import com.sun.tools.javac.comp.CompileStates.CompileState
|
||||
import com.sun.tools.javac.main.JavaCompiler
|
||||
import com.sun.tools.javac.processing.AnnotationProcessingError
|
||||
@@ -54,7 +53,7 @@ fun KaptContext.doAnnotationProcessing(
|
||||
val listener = cacheManager?.let {
|
||||
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)
|
||||
recordTypesListener
|
||||
}
|
||||
@@ -67,7 +66,6 @@ fun KaptContext.doAnnotationProcessing(
|
||||
|
||||
listener?.let { compiler.getTaskListeners().remove(it) }
|
||||
|
||||
val l = System.currentTimeMillis()
|
||||
if (isJava9OrLater()) {
|
||||
val processAnnotationsMethod = compiler.javaClass.getMethod("processAnnotations", JavacList::class.java)
|
||||
processAnnotationsMethod.invoke(compiler, analyzedFiles)
|
||||
|
||||
@@ -32,7 +32,7 @@ class JavaClassCacheManager(private val file: File, private val classpathFqNames
|
||||
}
|
||||
|
||||
val dirtyFqNames = mutableSetOf<String>()
|
||||
after.forEach{ file ->
|
||||
after.forEach { file ->
|
||||
ObjectInputStream(file.inputStream().buffered()).use {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
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()) {
|
||||
try {
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ class JavaClassCache() : Serializable {
|
||||
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.
|
||||
* */
|
||||
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. */
|
||||
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>()
|
||||
|
||||
classpath.forEach { entry ->
|
||||
|
||||
-5
@@ -7,11 +7,7 @@ package org.jetbrains.kotlin.kapt3.base.incremental
|
||||
|
||||
import com.sun.tools.javac.code.Symbol
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
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.ProcessingEnvironment
|
||||
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 getRuntimeType(): RuntimeProcType {
|
||||
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.TaskEvent
|
||||
import com.sun.source.util.TaskListener
|
||||
import com.sun.source.util.Trees
|
||||
import com.sun.tools.javac.code.Symbol
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
import java.io.File
|
||||
import javax.lang.model.element.ElementKind
|
||||
import javax.lang.model.element.Modifier
|
||||
import javax.lang.model.element.TypeElement
|
||||
import javax.lang.model.util.Elements
|
||||
|
||||
class MentionedTypesTaskListener(
|
||||
private val cache: JavaClassCache,
|
||||
private val trees: Trees
|
||||
private val elementUtils: Elements
|
||||
) : TaskListener {
|
||||
|
||||
var time = 0L
|
||||
@@ -33,7 +35,7 @@ class MentionedTypesTaskListener(
|
||||
|
||||
val structure = SourceFileStructure(e.sourceFile.toUri())
|
||||
|
||||
val treeVisitor = TypeTreeVisitor(compilationUnit, trees, structure)
|
||||
val treeVisitor = TypeTreeVisitor(elementUtils, structure)
|
||||
compilationUnit.typeDecls.forEach {
|
||||
it.accept(treeVisitor, Visibility.ABI)
|
||||
}
|
||||
@@ -46,14 +48,25 @@ private enum class Visibility {
|
||||
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>() {
|
||||
|
||||
/** 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? {
|
||||
node as JCTree.JCClassDecl
|
||||
sourceStructure.addDeclaredType(node.sym.fullname.toString())
|
||||
sourceStructure.addMentionedType(node.sym.fullname.toString())
|
||||
|
||||
handleClassAnnotations(node.sym)
|
||||
|
||||
node.modifiers.annotations.forEach { visit(it, visibility) }
|
||||
node.typeParameters.forEach { visit(it, 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,
|
||||
listOf(processor),
|
||||
generatedSources
|
||||
) { trees -> MentionedTypesTaskListener(cache.javaCache, trees) }
|
||||
) { elementUtils -> MentionedTypesTaskListener(cache.javaCache, elementUtils) }
|
||||
cache.updateCache(listOf(processor))
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.kapt.base.test.org.jetbrains.kotlin.kapt3.base.incremental
|
||||
|
||||
import com.sun.source.util.TaskListener
|
||||
import com.sun.source.util.Trees
|
||||
import com.sun.tools.javac.api.JavacTaskImpl
|
||||
import org.jetbrains.kotlin.kapt3.base.incremental.DeclaredProcType
|
||||
import org.jetbrains.kotlin.kapt3.base.incremental.IncrementalProcessor
|
||||
@@ -18,6 +17,7 @@ import javax.annotation.processing.ProcessingEnvironment
|
||||
import javax.annotation.processing.RoundEnvironment
|
||||
import javax.lang.model.SourceVersion
|
||||
import javax.lang.model.element.TypeElement
|
||||
import javax.lang.model.util.Elements
|
||||
import javax.tools.StandardLocation
|
||||
import javax.tools.ToolProvider
|
||||
|
||||
@@ -27,7 +27,7 @@ fun runAnnotationProcessing(
|
||||
srcFiles: List<File>,
|
||||
processor: List<IncrementalProcessor>,
|
||||
generatedSources: File,
|
||||
listener: (Trees) -> TaskListener? = { null }
|
||||
listener: (Elements) -> TaskListener? = { null }
|
||||
) {
|
||||
val compiler = ToolProvider.getSystemJavaCompiler()
|
||||
compiler.getStandardFileManager(null, null, null).use { fileManager ->
|
||||
@@ -42,7 +42,7 @@ fun runAnnotationProcessing(
|
||||
javaSrcs
|
||||
) as JavacTaskImpl
|
||||
|
||||
val taskListener = listener(Trees.instance(compilationTask))
|
||||
val taskListener = listener(compilationTask.elements)
|
||||
taskListener?.let { compilationTask.addTaskListener(it) }
|
||||
|
||||
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