diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/Incremental.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/Incremental.kt index fc184e199c..0a6b509e57 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/Incremental.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/Incremental.kt @@ -254,7 +254,7 @@ class IncrementalContext( sealedMap.remove(it) } - sourceToOutputsMap.remove(removedOutputsKey) + sourceToOutputsMap.removeRecursively(removedOutputsKey) } private fun updateLookupCache(dirtyFiles: Collection) { @@ -417,6 +417,14 @@ class IncrementalContext( return ksFiles.filter { it.relativeFile in dirtyFiles } } + // Loop detection isn't needed because of overwritten checks in CodeGeneratorImpl + private fun FileToFilesMap.removeRecursively(src: File) { + get(src)?.forEach { out -> + removeRecursively(out) + } + remove(src) + } + private fun updateSourceToOutputs( dirtyFiles: Collection, outputs: Set, @@ -425,15 +433,15 @@ class IncrementalContext( ) { // Prune deleted sources in source-to-outputs map. removed.forEach { - sourceToOutputsMap.remove(it) + sourceToOutputsMap.removeRecursively(it) } dirtyFiles.filterNot { sourceToOutputs.containsKey(it) }.forEach { - sourceToOutputsMap.remove(it) + sourceToOutputsMap.removeRecursively(it) } removedOutputs.forEach { - sourceToOutputsMap.remove(it) + sourceToOutputsMap.removeRecursively(it) } sourceToOutputsMap[removedOutputsKey] = removedOutputs diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalMultiChainIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalMultiChainIT.kt index f95f07cbcb..cd1c177b9c 100644 --- a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalMultiChainIT.kt +++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/IncrementalMultiChainIT.kt @@ -47,6 +47,9 @@ class IncrementalMultiChainIT(useK2: Boolean) { Assert.assertTrue(result.output.contains("validating K1Impl.kt")) Assert.assertTrue(result.output.contains("validating AllImpls.kt")) Assert.assertTrue(result.output.contains("[K1Impl]")) + Assert.assertFalse( + File(project.root, "workload/build/generated/ksp/main/kotlin/K2ImplInfo.kt").exists() + ) } } diff --git a/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/Aggregator.kt b/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/Aggregator.kt index d7c25217b9..e9b7232bfa 100644 --- a/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/Aggregator.kt +++ b/integration-tests/src/test/resources/incremental-multi-chain/processors/src/main/kotlin/Aggregator.kt @@ -31,6 +31,21 @@ class Aggregator : SymbolProcessor { } codeGenerator.associate(impls.map { it.containingFile!! }.toList(), "", "AllImpls") } + + impls.forEach { decl -> + decl as KSClassDeclaration + val file = decl.containingFile!! + val baseName = decl.simpleName.asString() + val fileName = baseName + "Info" + OutputStreamWriter( + codeGenerator.createNewFile( + Dependencies(false, file), + "", fileName + ) + ).use { + it.write("// dummy file") + } + } return emptyList() } }