Incremental KAPT - invalidate obsolete types
Once set of dirty symbols is computed, filter these types when they are requested from the JavaFileManager. This is accomplished by tracking all declared types in the sources and generated sources. It is not necessary track types in generated class files, as these will be removed before the APs are incrementally run. Motivation: APs (e.g. Dagger) may use Elements.getTypeElement(String) to determine if type is already present, and if it is, they will not generate it. Therefore, whenever generated sources is invalidated, types it defines need to be filtered in the JavaFileManager. Issue is https://youtrack.jetbrains.com/issue/KT-23880
This commit is contained in:
committed by
Alexey Tsvetkov
parent
2f3d234516
commit
b2ad82b7d2
+74
-4
@@ -50,8 +50,9 @@ class IncrementalKaptTest {
|
||||
|
||||
val logger = WriterBackedKaptLogger(isVerbose = true)
|
||||
KaptContext(options, true, logger).use {
|
||||
val toReprocess = it.cacheManager!!.invalidateAndGetDirtyFiles(options.changedFiles)
|
||||
it.doAnnotationProcessing(
|
||||
options.collectJavaSourceFiles(it.cacheManager), listOf(SimpleProcessor().toIsolating())
|
||||
options.collectJavaSourceFiles(toReprocess), listOf(SimpleProcessor().toIsolating())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -77,11 +78,12 @@ class IncrementalKaptTest {
|
||||
}.build()
|
||||
|
||||
KaptContext(optionsForSecondRun, true, logger).use {
|
||||
val sourcesToReprocess = optionsForSecondRun.collectJavaSourceFiles(it.cacheManager)
|
||||
val sourcesToReprocess =
|
||||
it.cacheManager!!.invalidateAndGetDirtyFiles(optionsForSecondRun.changedFiles)
|
||||
assertFalse(outputDir.resolve("test/UserGenerated.java").exists())
|
||||
|
||||
it.doAnnotationProcessing(
|
||||
sourcesToReprocess, listOf(SimpleProcessor().toIsolating())
|
||||
optionsForSecondRun.collectJavaSourceFiles(sourcesToReprocess), listOf(SimpleProcessor().toIsolating())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -90,12 +92,80 @@ class IncrementalKaptTest {
|
||||
|
||||
sourcesDir.resolve("User.java").delete()
|
||||
KaptContext(optionsForSecondRun, true, logger).use {
|
||||
val sourcesToReprocess = it.cacheManager!!.invalidateAndGetDirtyFiles(optionsForSecondRun.changedFiles)
|
||||
|
||||
it.doAnnotationProcessing(
|
||||
optionsForSecondRun.collectJavaSourceFiles(it.cacheManager), listOf(SimpleProcessor().toIsolating())
|
||||
optionsForSecondRun.collectJavaSourceFiles(sourcesToReprocess), listOf(SimpleProcessor().toIsolating())
|
||||
)
|
||||
}
|
||||
|
||||
assertEquals(addressTimestamp, outputDir.resolve("test/AddressGenerated.java").lastModified())
|
||||
assertFalse(outputDir.resolve("test/UserGenerated.java").exists())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGeneratedCompiledAreIgnored() {
|
||||
val sourcesDir = tmp.newFolder().resolve("test").also { base ->
|
||||
base.mkdir()
|
||||
listOf("User.java", "Address.java", "Observable.java").map {
|
||||
TEST_DATA_DIR.resolve(it).copyTo(base.resolve(it))
|
||||
}
|
||||
}
|
||||
|
||||
val outputDir = tmp.newFolder()
|
||||
val incrementalCacheDir = tmp.newFolder()
|
||||
val classpathHistory = tmp.newFolder().also {
|
||||
it.resolve("0").createNewFile()
|
||||
}
|
||||
val options = KaptOptions.Builder().apply {
|
||||
projectBaseDir = tmp.newFolder()
|
||||
javaSourceRoots.add(sourcesDir)
|
||||
|
||||
sourcesOutputDir = outputDir
|
||||
classesOutputDir = outputDir
|
||||
stubsOutputDir = outputDir
|
||||
incrementalDataOutputDir = outputDir
|
||||
|
||||
incrementalCache = incrementalCacheDir
|
||||
classpathFqNamesHistory = classpathHistory
|
||||
}.build()
|
||||
|
||||
val logger = WriterBackedKaptLogger(isVerbose = true)
|
||||
KaptContext(options, true, logger).use {
|
||||
val toReprocess = it.cacheManager!!.invalidateAndGetDirtyFiles(options.changedFiles)
|
||||
it.doAnnotationProcessing(
|
||||
options.collectJavaSourceFiles(toReprocess), listOf(SimpleGeneratingIfTypeDoesNotExist().toIsolating())
|
||||
)
|
||||
}
|
||||
|
||||
val classesOutput = tmp.newFolder()
|
||||
compileSources(sourcesDir.listFiles().asIterable(), classesOutput)
|
||||
compileSources(listOf(outputDir.resolve("test/UserGenerated.java")), classesOutput)
|
||||
|
||||
val optionsForSecondRun = KaptOptions.Builder().apply {
|
||||
projectBaseDir = tmp.newFolder()
|
||||
|
||||
sourcesOutputDir = outputDir
|
||||
classesOutputDir = outputDir
|
||||
stubsOutputDir = outputDir
|
||||
incrementalDataOutputDir = outputDir
|
||||
|
||||
incrementalCache = incrementalCacheDir
|
||||
classpathFqNamesHistory = classpathHistory
|
||||
compiledSources.add(classesOutput)
|
||||
changedFiles.add(sourcesDir.resolve("User.java"))
|
||||
}.build()
|
||||
|
||||
KaptContext(optionsForSecondRun, true, logger).use {
|
||||
val sourcesToReprocess =
|
||||
it.cacheManager!!.invalidateAndGetDirtyFiles(optionsForSecondRun.changedFiles)
|
||||
assertFalse(outputDir.resolve("test/UserGenerated.java").exists())
|
||||
|
||||
it.doAnnotationProcessing(
|
||||
optionsForSecondRun.collectJavaSourceFiles(sourcesToReprocess), listOf(SimpleGeneratingIfTypeDoesNotExist().toIsolating())
|
||||
)
|
||||
}
|
||||
|
||||
assertTrue(outputDir.resolve("test/UserGenerated.java").exists())
|
||||
}
|
||||
}
|
||||
@@ -119,6 +119,30 @@ class SimpleCreatingClassFilesAndResources : SimpleProcessor() {
|
||||
filer.createResource(StandardLocation.SOURCE_OUTPUT, "test", "${it.simpleName}GeneratedResource", it).openWriter().use { it.write("") }
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleGeneratingIfTypeDoesNotExist: SimpleProcessor() {
|
||||
override fun process(annotations: MutableSet<out TypeElement>, roundEnv: RoundEnvironment): Boolean {
|
||||
if (annotations.isEmpty()) return false
|
||||
|
||||
roundEnv.getElementsAnnotatedWith(annotations.single()).forEach { element ->
|
||||
element as TypeElement
|
||||
val generatedName = "${element.qualifiedName}Generated"
|
||||
|
||||
if (processingEnv.elementUtils.getTypeElement(generatedName) == null) {
|
||||
filer.createSourceFile(generatedName, element).openWriter().use {
|
||||
it.write(
|
||||
"""
|
||||
package test;
|
||||
public class ${element.simpleName}Generated {}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user