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:
Ivan Gavrilovic
2019-03-15 17:38:31 +00:00
committed by Alexey Tsvetkov
parent 9f14daa682
commit 2f3d234516
12 changed files with 105 additions and 20 deletions
@@ -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 {
@@ -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 {
@@ -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 ->
@@ -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) {
@@ -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)
@@ -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())
}
}
@@ -73,7 +73,7 @@ class TestSimpleIncrementalAptCache {
srcFiles,
listOf(processor),
generatedSources
) { trees -> MentionedTypesTaskListener(cache.javaCache, trees) }
) { elementUtils -> MentionedTypesTaskListener(cache.javaCache, elementUtils) }
cache.updateCache(listOf(processor))
}
}
@@ -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)
@@ -0,0 +1,4 @@
package test;
@InheritableAnnotation
public class BaseClass {}
@@ -0,0 +1,3 @@
package test;
public class ExtendsBase extends BaseClass {}
@@ -0,0 +1,4 @@
package test;
@java.lang.annotation.Inherited
public @interface InheritableAnnotation {}