From 50e9a96ff3d4bc1a51b7fd7537440a7aeed9975d Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Wed, 2 Oct 2024 00:04:46 -0700 Subject: [PATCH] Close ksp caches on exception and error Previously, LookupCache doesn't need to be explicitly closed. With newer intellij dependencies that comes with Kotlin 2.0.20 it becomes a problem. --- .../ksp/KotlinSymbolProcessingExtension.kt | 6 +++++ .../ksp/common/IncrementalContextBase.kt | 24 +++++++++++-------- .../ksp/common/IncrementalContextBase.kt | 24 +++++++++++-------- .../ksp/impl/KotlinSymbolProcessing.kt | 10 +++++--- 4 files changed, 41 insertions(+), 23 deletions(-) diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt index 266c9aa720..92948f217c 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt @@ -310,6 +310,7 @@ abstract class AbstractKotlinSymbolProcessingExtension( processor.process(resolver).filter { it.origin == Origin.KOTLIN || it.origin == Origin.JAVA } }?.let { resolver.tearDown() + incrementalContext.closeFiles() return it } if (logger.hasError()) { @@ -336,9 +337,11 @@ abstract class AbstractKotlinSymbolProcessingExtension( processor.onError() }?.let { resolver.tearDown() + incrementalContext.closeFiles() return it } } + incrementalContext.closeFiles() } else { if (finished) { processors.forEach { processor -> @@ -346,6 +349,7 @@ abstract class AbstractKotlinSymbolProcessingExtension( processor.finish() }?.let { resolver.tearDown() + incrementalContext.closeFiles() return it } } @@ -364,6 +368,8 @@ abstract class AbstractKotlinSymbolProcessingExtension( codeGenerator.outputs, codeGenerator.sourceToOutputs ) + } else { + incrementalContext.closeFiles() } } } diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt index 9dba3de639..ccd3c5a73d 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt @@ -211,13 +211,13 @@ abstract class IncrementalContextBase( // Beware: no side-effects here; Caches should only be touched in updateCaches. fun calcDirtyFiles(ksFiles: List): Collection = closeFilesOnException { if (!isIncremental) { - return ksFiles + return@closeFilesOnException ksFiles } if (rebuild) { collectDefinedSymbols(ksFiles) logDirtyFiles(ksFiles, ksFiles) - return ksFiles + return@closeFilesOnException ksFiles } val newSyms = mutableSetOf() @@ -285,7 +285,7 @@ abstract class IncrementalContextBase( dirtyFilesByNewSyms, dirtyFilesBySealed ) - return ksFiles.filter { it.relativeFile in dirtyFiles } + return@closeFilesOnException ksFiles.filter { it.relativeFile in dirtyFiles } } // Loop detection isn't needed because of overwritten checks in CodeGeneratorImpl @@ -403,19 +403,23 @@ abstract class IncrementalContextBase( collectDefinedSymbols(newFiles) } - private inline fun closeFilesOnException(f: () -> T): T { + fun closeFilesOnException(f: () -> T): T { try { return f() } catch (e: Exception) { - symbolsMap.flush() - sealedMap.flush() - symbolLookupCache.close() - classLookupCache.close() - sourceToOutputsMap.flush() + closeFiles() throw e } } + fun closeFiles() { + symbolsMap.flush() + sealedMap.flush() + symbolLookupCache.close() + classLookupCache.close() + sourceToOutputsMap.flush() + } + // TODO: add a wildcard for outputs with no source and get rid of the outputs parameter. fun updateCachesAndOutputs( dirtyFiles: Collection, @@ -423,7 +427,7 @@ abstract class IncrementalContextBase( sourceToOutputs: Map>, ) = closeFilesOnException { if (!isIncremental) - return + return@closeFilesOnException cachesUpToDateFile.delete() assert(!cachesUpToDateFile.exists()) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt index 8686c7aa13..9273bce556 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/common/IncrementalContextBase.kt @@ -212,13 +212,13 @@ abstract class IncrementalContextBase( // Beware: no side-effects here; Caches should only be touched in updateCaches. fun calcDirtyFiles(ksFiles: List): Collection = closeFilesOnException { if (!isIncremental) { - return ksFiles + return@closeFilesOnException ksFiles } if (rebuild) { collectDefinedSymbols(ksFiles) logDirtyFiles(ksFiles, ksFiles) - return ksFiles + return@closeFilesOnException ksFiles } val newSyms = mutableSetOf() @@ -286,7 +286,7 @@ abstract class IncrementalContextBase( dirtyFilesByNewSyms, dirtyFilesBySealed ) - return ksFiles.filter { it.relativeFile in dirtyFiles } + return@closeFilesOnException ksFiles.filter { it.relativeFile in dirtyFiles } } // Loop detection isn't needed because of overwritten checks in CodeGeneratorImpl @@ -404,19 +404,23 @@ abstract class IncrementalContextBase( collectDefinedSymbols(newFiles) } - private inline fun closeFilesOnException(f: () -> T): T { + fun closeFilesOnException(f: () -> T): T { try { return f() } catch (e: Exception) { - symbolsMap.flush() - sealedMap.flush() - symbolLookupCache.close() - classLookupCache.close() - sourceToOutputsMap.flush() + closeFiles() throw e } } + fun closeFiles() { + symbolsMap.flush() + sealedMap.flush() + symbolLookupCache.close() + classLookupCache.close() + sourceToOutputsMap.flush() + } + // TODO: add a wildcard for outputs with no source and get rid of the outputs parameter. fun updateCachesAndOutputs( dirtyFiles: Collection, @@ -424,7 +428,7 @@ abstract class IncrementalContextBase( sourceToOutputs: Map>, ) = closeFilesOnException { if (!isIncremental) - return + return@closeFilesOnException cachesUpToDateFile.delete() assert(!cachesUpToDateFile.exists()) diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KotlinSymbolProcessing.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KotlinSymbolProcessing.kt index 0717fe4a5a..33f6cc0641 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KotlinSymbolProcessing.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/KotlinSymbolProcessing.kt @@ -548,9 +548,11 @@ class KotlinSymbolProcessing( ResolverAAImpl.instance.propertyAsMemberOfCache = mutableMapOf() processors.forEach { - deferredSymbols[it] = - it.process(resolver).filter { it.origin == Origin.KOTLIN || it.origin == Origin.JAVA } - .filterIsInstance().mapNotNull(Deferrable::defer) + incrementalContext.closeFilesOnException { + deferredSymbols[it] = + it.process(resolver).filter { it.origin == Origin.KOTLIN || it.origin == Origin.JAVA } + .filterIsInstance().mapNotNull(Deferrable::defer) + } if (!deferredSymbols.containsKey(it) || deferredSymbols[it]!!.isEmpty()) { deferredSymbols.remove(it) } @@ -591,6 +593,8 @@ class KotlinSymbolProcessing( codeGenerator.outputs, codeGenerator.sourceToOutputs ) + } else { + incrementalContext.closeFiles() } dropCaches()