KT-34167: Warn when incremental AP does not follow the contract

Isolating incremental AP must report exactly one originating source file.
This commit logs a warning when this constraint is violated.

Test: AnnotationProcessorDependencyCollectorTest.testIsolatingWithoutOrigin
This commit is contained in:
Ivan Gavrilovic
2019-10-15 17:44:21 +01:00
committed by Yan Zhulanow
parent 8f94a71de7
commit 4e807692e5
7 changed files with 34 additions and 18 deletions
@@ -56,7 +56,7 @@ open class ProcessorLoader(private val options: KaptOptions, private val logger:
private fun wrapInIncrementalProcessor(processors: List<Processor>, classpath: Iterable<File>): List<IncrementalProcessor> { private fun wrapInIncrementalProcessor(processors: List<Processor>, classpath: Iterable<File>): List<IncrementalProcessor> {
if (options.incrementalCache == null) { if (options.incrementalCache == null) {
return processors.map { IncrementalProcessor(it, DeclaredProcType.NON_INCREMENTAL) } return processors.map { IncrementalProcessor(it, DeclaredProcType.NON_INCREMENTAL, logger) }
} }
val processorNames = processors.map {it.javaClass.name}.toSet() val processorNames = processors.map {it.javaClass.name}.toSet()
@@ -72,7 +72,7 @@ open class ProcessorLoader(private val options: KaptOptions, private val logger:
DeclaredProcType.INCREMENTAL_BUT_OTHER_APS_ARE_NOT DeclaredProcType.INCREMENTAL_BUT_OTHER_APS_ARE_NOT
} }
} ?: DeclaredProcType.NON_INCREMENTAL } ?: DeclaredProcType.NON_INCREMENTAL
IncrementalProcessor(it, procType) IncrementalProcessor(it, procType, logger)
} }
} }
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.kapt3.base.incremental package org.jetbrains.kotlin.kapt3.base.incremental
import com.sun.tools.javac.code.Symbol import com.sun.tools.javac.code.Symbol
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
import java.io.File import java.io.File
import java.net.URI import java.net.URI
import javax.annotation.processing.Filer import javax.annotation.processing.Filer
@@ -19,7 +20,8 @@ import javax.tools.JavaFileObject
private val ALLOWED_RUNTIME_TYPES = setOf(RuntimeProcType.AGGREGATING.name, RuntimeProcType.ISOLATING.name) private val ALLOWED_RUNTIME_TYPES = setOf(RuntimeProcType.AGGREGATING.name, RuntimeProcType.ISOLATING.name)
class IncrementalProcessor(private val processor: Processor, private val kind: DeclaredProcType) : Processor by processor { class IncrementalProcessor(private val processor: Processor, private val kind: DeclaredProcType, private val logger: KaptLogger) :
Processor by processor {
private var dependencyCollector = lazy { createDependencyCollector() } private var dependencyCollector = lazy { createDependencyCollector() }
@@ -56,7 +58,7 @@ class IncrementalProcessor(private val processor: Processor, private val kind: D
kind.toRuntimeType() kind.toRuntimeType()
} }
return AnnotationProcessorDependencyCollector(type) return AnnotationProcessorDependencyCollector(type) { s -> logger.warn("Issue detected with $processorName. $s") }
} }
fun isMissingIncrementalSupport(): Boolean { fun isMissingIncrementalSupport(): Boolean {
@@ -64,6 +66,7 @@ class IncrementalProcessor(private val processor: Processor, private val kind: D
return kind == DeclaredProcType.DYNAMIC && getRuntimeType() == RuntimeProcType.NON_INCREMENTAL return kind == DeclaredProcType.DYNAMIC && getRuntimeType() == RuntimeProcType.NON_INCREMENTAL
} }
fun isUnableToRunIncrementally() = !kind.canRunIncrementally fun isUnableToRunIncrementally() = !kind.canRunIncrementally
fun getGeneratedToSources() = dependencyCollector.value.getGeneratedToSources() fun getGeneratedToSources() = dependencyCollector.value.getGeneratedToSources()
fun getRuntimeType(): RuntimeProcType = dependencyCollector.value.getRuntimeType() fun getRuntimeType(): RuntimeProcType = dependencyCollector.value.getRuntimeType()
@@ -103,7 +106,10 @@ internal class IncrementalFiler(private val filer: Filer) : Filer by filer {
} }
} }
internal class AnnotationProcessorDependencyCollector(private val runtimeProcType: RuntimeProcType) { internal class AnnotationProcessorDependencyCollector(
private val runtimeProcType: RuntimeProcType,
private val warningCollector: (String) -> Unit
) {
private val generatedToSource = mutableMapOf<File, File?>() private val generatedToSource = mutableMapOf<File, File?>()
private var isFullRebuild = !runtimeProcType.isIncremental private var isFullRebuild = !runtimeProcType.isIncremental
@@ -117,6 +123,10 @@ internal class AnnotationProcessorDependencyCollector(private val runtimeProcTyp
val srcFiles = getSrcFiles(originatingElements) val srcFiles = getSrcFiles(originatingElements)
if (srcFiles.size != 1) { if (srcFiles.size != 1) {
isFullRebuild = true isFullRebuild = true
warningCollector.invoke(
"Expected 1 originating source file when generating $generatedFile, " +
"but detected ${srcFiles.size}: [${srcFiles.joinToString()}]."
)
} else { } else {
generatedToSource[generatedFile] = srcFiles.single() generatedToSource[generatedFile] = srcFiles.single()
} }
@@ -26,6 +26,7 @@ import javax.lang.model.element.TypeElement
class JavaKaptContextTest : TestCase() { class JavaKaptContextTest : TestCase() {
companion object { companion object {
private val TEST_DATA_DIR = File("plugins/kapt3/kapt3-base/testData/runner") private val TEST_DATA_DIR = File("plugins/kapt3/kapt3-base/testData/runner")
val logger = WriterBackedKaptLogger(isVerbose = true)
fun simpleProcessor() = IncrementalProcessor( fun simpleProcessor() = IncrementalProcessor(
object : AbstractProcessor() { object : AbstractProcessor() {
@@ -52,7 +53,7 @@ class JavaKaptContextTest : TestCase() {
} }
override fun getSupportedAnnotationTypes() = setOf("test.MyAnnotation") override fun getSupportedAnnotationTypes() = setOf("test.MyAnnotation")
}, DeclaredProcType.NON_INCREMENTAL }, DeclaredProcType.NON_INCREMENTAL, logger
) )
} }
@@ -69,7 +70,6 @@ class JavaKaptContextTest : TestCase() {
detectMemoryLeaks = DetectMemoryLeaksMode.NONE detectMemoryLeaks = DetectMemoryLeaksMode.NONE
}.build() }.build()
val logger = WriterBackedKaptLogger(isVerbose = true)
KaptContext(options, true, logger).doAnnotationProcessing(listOf(javaSourceFile), listOf(processor)) KaptContext(options, true, logger).doAnnotationProcessing(listOf(javaSourceFile), listOf(processor))
} }
@@ -99,7 +99,7 @@ class JavaKaptContextTest : TestCase() {
} }
try { try {
doAnnotationProcessing(File(TEST_DATA_DIR, "Simple.java"), IncrementalProcessor(processor, DeclaredProcType.NON_INCREMENTAL), TEST_DATA_DIR) doAnnotationProcessing(File(TEST_DATA_DIR, "Simple.java"), IncrementalProcessor(processor, DeclaredProcType.NON_INCREMENTAL, logger), TEST_DATA_DIR)
} catch (e: KaptBaseError) { } catch (e: KaptBaseError) {
assertEquals(KaptBaseError.Kind.EXCEPTION, e.kind) assertEquals(KaptBaseError.Kind.EXCEPTION, e.kind)
assertEquals("Here we are!", e.cause!!.message) assertEquals("Here we are!", e.cause!!.message)
@@ -8,13 +8,14 @@ package org.jetbrains.kotlin.kapt.base.test.org.jetbrains.kotlin.kapt3.base.incr
import org.jetbrains.kotlin.kapt3.base.incremental.AnnotationProcessorDependencyCollector import org.jetbrains.kotlin.kapt3.base.incremental.AnnotationProcessorDependencyCollector
import org.jetbrains.kotlin.kapt3.base.incremental.RuntimeProcType import org.jetbrains.kotlin.kapt3.base.incremental.RuntimeProcType
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
import java.io.File import java.io.File
class AnnotationProcessorDependencyCollectorTest { class AnnotationProcessorDependencyCollectorTest {
@Test @Test
fun testAggregating() { fun testAggregating() {
val aggregating = AnnotationProcessorDependencyCollector(RuntimeProcType.AGGREGATING) val aggregating = AnnotationProcessorDependencyCollector(RuntimeProcType.AGGREGATING) {}
val generated = listOf("GeneratedA.java", "GeneratedB.java", "GeneratedC.java").map { File(it).toURI() } val generated = listOf("GeneratedA.java", "GeneratedB.java", "GeneratedC.java").map { File(it).toURI() }
generated.forEach { aggregating.add(it, emptyArray()) } generated.forEach { aggregating.add(it, emptyArray()) }
@@ -24,16 +25,18 @@ class AnnotationProcessorDependencyCollectorTest {
@Test @Test
fun testIsolatingWithoutOrigin() { fun testIsolatingWithoutOrigin() {
val isolating = AnnotationProcessorDependencyCollector(RuntimeProcType.ISOLATING) val warnings = mutableListOf<String>()
val isolating = AnnotationProcessorDependencyCollector(RuntimeProcType.ISOLATING) { s -> warnings.add(s) }
isolating.add(File("GeneratedA.java").toURI(), emptyArray()) isolating.add(File("GeneratedA.java").toURI(), emptyArray())
assertEquals(isolating.getRuntimeType(), RuntimeProcType.NON_INCREMENTAL) assertEquals(isolating.getRuntimeType(), RuntimeProcType.NON_INCREMENTAL)
assertEquals(isolating.getGeneratedToSources(), emptyMap<File, File?>()) assertEquals(isolating.getGeneratedToSources(), emptyMap<File, File?>())
assertTrue(warnings.single().contains("Expected 1 originating source file when generating"))
} }
@Test @Test
fun testNonIncremental() { fun testNonIncremental() {
val nonIncremental = AnnotationProcessorDependencyCollector(RuntimeProcType.NON_INCREMENTAL) val nonIncremental = AnnotationProcessorDependencyCollector(RuntimeProcType.NON_INCREMENTAL) {}
nonIncremental.add(File("GeneratedA.java").toURI(), emptyArray()) nonIncremental.add(File("GeneratedA.java").toURI(), emptyArray())
nonIncremental.add(File("GeneratedB.java").toURI(), emptyArray()) nonIncremental.add(File("GeneratedB.java").toURI(), emptyArray())
@@ -71,7 +71,7 @@ class IncrementalKaptTest {
incrementalCache = incrementalCacheDir incrementalCache = incrementalCacheDir
compiledSources.add(classesOutput) compiledSources.add(classesOutput)
changedFiles.add(sourcesDir.resolve("User.java")) changedFiles.add(sourcesDir.resolve("User.java").canonicalFile)
flags.add(KaptFlag.INCREMENTAL_APT) flags.add(KaptFlag.INCREMENTAL_APT)
}.build() }.build()
@@ -145,7 +145,7 @@ class IncrementalKaptTest {
incrementalCache = incrementalCacheDir incrementalCache = incrementalCacheDir
compiledSources.add(classesOutput) compiledSources.add(classesOutput)
changedFiles.add(sourcesDir.resolve("User.java")) changedFiles.add(sourcesDir.resolve("User.java").canonicalFile)
flags.add(KaptFlag.INCREMENTAL_APT) flags.add(KaptFlag.INCREMENTAL_APT)
}.build() }.build()
@@ -11,6 +11,7 @@ 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
import org.jetbrains.kotlin.kapt3.base.incremental.RuntimeProcType import org.jetbrains.kotlin.kapt3.base.incremental.RuntimeProcType
import org.jetbrains.kotlin.kapt3.base.util.WriterBackedKaptLogger
import java.io.File import java.io.File
import javax.annotation.processing.AbstractProcessor import javax.annotation.processing.AbstractProcessor
import javax.annotation.processing.Filer import javax.annotation.processing.Filer
@@ -69,10 +70,12 @@ fun compileSources(srcFiles: Iterable<File>, outputDir: File) {
} }
} }
fun SimpleProcessor.toAggregating() = IncrementalProcessor(this, DeclaredProcType.AGGREGATING) fun SimpleProcessor.toAggregating() = IncrementalProcessor(this, DeclaredProcType.AGGREGATING, WriterBackedKaptLogger(isVerbose = true))
fun SimpleProcessor.toIsolating() = IncrementalProcessor(this, DeclaredProcType.ISOLATING) fun SimpleProcessor.toIsolating() = IncrementalProcessor(this, DeclaredProcType.ISOLATING, WriterBackedKaptLogger(isVerbose = true))
fun SimpleProcessor.toNonIncremental() = IncrementalProcessor(this, DeclaredProcType.NON_INCREMENTAL) fun SimpleProcessor.toNonIncremental() =
fun DynamicProcessor.toDynamic() = IncrementalProcessor(this, DeclaredProcType.DYNAMIC) IncrementalProcessor(this, DeclaredProcType.NON_INCREMENTAL, WriterBackedKaptLogger(isVerbose = true))
fun DynamicProcessor.toDynamic() = IncrementalProcessor(this, DeclaredProcType.DYNAMIC, WriterBackedKaptLogger(isVerbose = true))
open class SimpleProcessor(private val wrongOrigin: Boolean = false, private val generatedSuffix: String = "") : AbstractProcessor() { open class SimpleProcessor(private val wrongOrigin: Boolean = false, private val generatedSuffix: String = "") : AbstractProcessor() {
lateinit var filer: Filer lateinit var filer: Filer
@@ -175,7 +175,7 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
internal var savedBindings: Map<String, KaptJavaFileObject>? = null internal var savedBindings: Map<String, KaptJavaFileObject>? = null
override fun loadProcessors() = LoadedProcessors( override fun loadProcessors() = LoadedProcessors(
processors.map { IncrementalProcessor(it, DeclaredProcType.NON_INCREMENTAL) }, processors.map { IncrementalProcessor(it, DeclaredProcType.NON_INCREMENTAL, logger) },
Kapt3ExtensionForTests::class.java.classLoader) Kapt3ExtensionForTests::class.java.classLoader)
override fun saveStubs(kaptContext: KaptContext, stubs: List<KaptStub>) { override fun saveStubs(kaptContext: KaptContext, stubs: List<KaptStub>) {