From 2f3d234516be200c6a5a74ccbfdcf04ec0ec185e Mon Sep 17 00:00:00 2001 From: Ivan Gavrilovic Date: Fri, 15 Mar 2019 17:38:31 +0000 Subject: [PATCH] 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 --- .../kotlin/kapt3/base/annotationProcessing.kt | 4 +- .../kotlin/kapt3/base/incremental/cache.kt | 4 +- .../base/incremental/classStructureCache.kt | 2 +- .../incrementalProcessorDiscovery.kt | 3 +- .../base/incremental/incrementalProcessors.kt | 5 -- .../kapt3/base/incremental/javacVisitors.kt | 21 ++++-- .../incremental/InheritedAnnotationTest.kt | 67 +++++++++++++++++++ .../TestSimpleIncrementalAptCache.kt | 2 +- .../kotlin/kapt3/base/incremental/fixtures.kt | 6 +- .../complex/inherited/BaseClass.java | 4 ++ .../complex/inherited/ExtendsBase.java | 3 + .../inherited/InheritableAnnotation.java | 4 ++ 12 files changed, 105 insertions(+), 20 deletions(-) create mode 100644 plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/InheritedAnnotationTest.kt create mode 100644 plugins/kapt3/kapt3-base/testData/runner/incremental/complex/inherited/BaseClass.java create mode 100644 plugins/kapt3/kapt3-base/testData/runner/incremental/complex/inherited/ExtendsBase.java create mode 100644 plugins/kapt3/kapt3-base/testData/runner/incremental/complex/inherited/InheritableAnnotation.java diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/annotationProcessing.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/annotationProcessing.kt index 5562e79e95f..37e3cb8ddac 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/annotationProcessing.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/annotationProcessing.kt @@ -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) diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/cache.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/cache.kt index 41d0e18e5a0..4e866c0f12c 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/cache.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/cache.kt @@ -32,7 +32,7 @@ class JavaClassCacheManager(private val file: File, private val classpathFqNames } val dirtyFqNames = mutableSetOf() - after.forEach{ file -> + after.forEach { file -> ObjectInputStream(file.inputStream().buffered()).use { @Suppress("UNCHECKED_CAST") dirtyFqNames.addAll(it.readObject() as Collection) @@ -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 { diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/classStructureCache.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/classStructureCache.kt index 6a15ba59dab..de8770186aa 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/classStructureCache.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/classStructureCache.kt @@ -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 { diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/incrementalProcessorDiscovery.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/incrementalProcessorDiscovery.kt index acebea39cd8..eeae090418b 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/incrementalProcessorDiscovery.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/incrementalProcessorDiscovery.kt @@ -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, classpath: Iterable): Map { + names: Set, classpath: Iterable +): Map { val finalValues = mutableMapOf() classpath.forEach { entry -> diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/incrementalProcessors.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/incrementalProcessors.kt index e99bc228fe9..88ba03ec61d 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/incrementalProcessors.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/incrementalProcessors.kt @@ -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 = if (isFullRebuild) emptyMap() else generatedToSource internal fun getRuntimeType(): RuntimeProcType { return if (isFullRebuild) { diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/javacVisitors.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/javacVisitors.kt index 53fbe30c40c..9d953b6c67e 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/javacVisitors.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/javacVisitors.kt @@ -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() { + /** 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) diff --git a/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/InheritedAnnotationTest.kt b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/InheritedAnnotationTest.kt new file mode 100644 index 00000000000..1f6d50e2b92 --- /dev/null +++ b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/InheritedAnnotationTest.kt @@ -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(), shouldInheritAnnotation.getPrivateTypes()) + assertEquals( + setOf( + "test.ExtendsBase", + "test.BaseClass" + ), shouldInheritAnnotation.getMentionedTypes() + ) + assertEquals(emptyMap(), shouldInheritAnnotation.getDefinedConstants()) + } +} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/TestSimpleIncrementalAptCache.kt b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/TestSimpleIncrementalAptCache.kt index 5dfa2846833..b40ac4a6ff3 100644 --- a/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/TestSimpleIncrementalAptCache.kt +++ b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/TestSimpleIncrementalAptCache.kt @@ -73,7 +73,7 @@ class TestSimpleIncrementalAptCache { srcFiles, listOf(processor), generatedSources - ) { trees -> MentionedTypesTaskListener(cache.javaCache, trees) } + ) { elementUtils -> MentionedTypesTaskListener(cache.javaCache, elementUtils) } cache.updateCache(listOf(processor)) } } \ No newline at end of file diff --git a/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/fixtures.kt b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/fixtures.kt index 404ff7e260b..86e6194ecf6 100644 --- a/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/fixtures.kt +++ b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/fixtures.kt @@ -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, processor: List, 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) diff --git a/plugins/kapt3/kapt3-base/testData/runner/incremental/complex/inherited/BaseClass.java b/plugins/kapt3/kapt3-base/testData/runner/incremental/complex/inherited/BaseClass.java new file mode 100644 index 00000000000..0b76bf4bcdc --- /dev/null +++ b/plugins/kapt3/kapt3-base/testData/runner/incremental/complex/inherited/BaseClass.java @@ -0,0 +1,4 @@ +package test; + +@InheritableAnnotation +public class BaseClass {} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-base/testData/runner/incremental/complex/inherited/ExtendsBase.java b/plugins/kapt3/kapt3-base/testData/runner/incremental/complex/inherited/ExtendsBase.java new file mode 100644 index 00000000000..4218960d3d7 --- /dev/null +++ b/plugins/kapt3/kapt3-base/testData/runner/incremental/complex/inherited/ExtendsBase.java @@ -0,0 +1,3 @@ +package test; + +public class ExtendsBase extends BaseClass {} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-base/testData/runner/incremental/complex/inherited/InheritableAnnotation.java b/plugins/kapt3/kapt3-base/testData/runner/incremental/complex/inherited/InheritableAnnotation.java new file mode 100644 index 00000000000..131d3cd92d7 --- /dev/null +++ b/plugins/kapt3/kapt3-base/testData/runner/incremental/complex/inherited/InheritableAnnotation.java @@ -0,0 +1,4 @@ +package test; + +@java.lang.annotation.Inherited +public @interface InheritableAnnotation {} \ No newline at end of file