Skip to content

Commit 8af228d

Browse files
ofir-blausclaude
andcommitted
Skip files the Kotlin analysis cannot handle, and always exit
A top-level destructuring declaration in a .kt file (`val (a, b) = ...`) is not valid Kotlin, so the Analysis API has no FIR for it, and asking for its type threw "No fir element was found for KtDestructuringDeclaration". That exception aborted the whole run. Afterwards a non-daemon pooled thread kept the JVM alive, so the process hung instead of exiting. - Skip a top-level destructuring declaration instead of resolving it. - If indexing a file throws, skip that file (no shard, one line on stderr) and keep indexing the rest. - Exit with status 1 when the run fails, so the process never hangs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent a77e133 commit 8af228d

3 files changed

Lines changed: 68 additions & 9 deletions

File tree

‎scip-kotlin-analysis/src/main/kotlin/org/scip_code/scip_java/kotlin_analysis/KotlinAnalysisIndexer.kt‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,16 @@ class KotlinAnalysisIndexer(
126126
val documents = mutableListOf<Document>()
127127
val ktFiles = session.modulesWithFiles.values.flatten().filterIsInstance<KtFile>()
128128
for (ktFile in ktFiles) {
129-
val document = indexFile(ktFile)
129+
val document =
130+
try {
131+
indexFile(ktFile)
132+
} catch (e: Exception) {
133+
val reason = e.message?.lineSequence()?.firstOrNull()
134+
System.err.println(
135+
"scip-kotlin-analysis: skipped ${ktFile.virtualFilePath}: ${e.javaClass.name}: $reason"
136+
)
137+
continue
138+
}
130139
writeShard(ktFile, document)
131140
callback(document)
132141
documents.add(document)
@@ -583,6 +592,7 @@ class KotlinAnalysisIndexer(
583592
override fun visitDestructuringDeclaration(
584593
destructuringDeclaration: KtDestructuringDeclaration
585594
) {
595+
if (destructuringDeclaration.parent is KtFile) return
586596
val isParameter = destructuringDeclaration.parent is KtParameter
587597
val type =
588598
destructuringDeclaration.initializer?.let { renderedExpressionType(it) }

‎scip-kotlin-analysis/src/main/kotlin/org/scip_code/scip_java/kotlin_analysis/Main.kt‎

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,20 @@ fun main(args: Array<String>) {
3737
require(sourceroot != null) { "missing required flag: --sourceroot" }
3838
require(targetroot != null) { "missing required flag: --targetroot" }
3939
require(sourceRoots.isNotEmpty()) { "missing source files or directories" }
40-
KotlinAnalysisIndexer(
41-
sourceroot = sourceroot,
42-
targetroot = targetroot,
43-
sourceRoots = sourceRoots,
44-
classpath = classpath,
45-
jdkHome = jdkHome,
46-
)
47-
.run()
4840
// The Analysis API environment leaves non-daemon threads behind; exit
4941
// explicitly so callers are not left waiting on them.
42+
try {
43+
KotlinAnalysisIndexer(
44+
sourceroot = sourceroot,
45+
targetroot = targetroot,
46+
sourceRoots = sourceRoots,
47+
classpath = classpath,
48+
jdkHome = jdkHome,
49+
)
50+
.run()
51+
} catch (e: Throwable) {
52+
e.printStackTrace()
53+
exitProcess(1)
54+
}
5055
exitProcess(0)
5156
}

‎scip-kotlin-analysis/src/test/kotlin/org/scip_code/scip_java/kotlin_analysis/KotlinAnalysisIndexerTest.kt‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,50 @@ class KotlinAnalysisIndexerTest {
9393
)
9494
}
9595

96+
@Test
97+
fun `a top-level destructuring in a kt file is skipped, not the file or the run`() {
98+
val sourceroot = Files.createTempDirectory("scip-kotlin-analysis").toRealPath()
99+
val src = Files.createDirectories(sourceroot.resolve("src"))
100+
Files.writeString(
101+
src.resolve("Broken.kt"),
102+
"""
103+
|package snapshots
104+
|
105+
|fun before(): Int = 1
106+
|
107+
|val (first, second) = Pair(1, 2)
108+
|
109+
|fun after(): Int = before()
110+
"""
111+
.trimMargin(),
112+
)
113+
Files.writeString(
114+
src.resolve("Other.kt"),
115+
"""
116+
|package snapshots
117+
|
118+
|fun other(): Int = after()
119+
"""
120+
.trimMargin(),
121+
)
122+
val documents =
123+
KotlinAnalysisIndexer(
124+
sourceroot = sourceroot,
125+
targetroot = sourceroot.resolve("scip-targetroot"),
126+
sourceRoots = listOf(src),
127+
classpath = listOf(kotlinStdlibJar()),
128+
)
129+
.run()
130+
.sortedBy { it.relativePath }
131+
132+
assertEquals(listOf("src/Broken.kt", "src/Other.kt"), documents.map { it.relativePath })
133+
val broken = definitions(documents[0])
134+
assertContains(broken, "snapshots/before().")
135+
assertContains(broken, "snapshots/after().")
136+
assertContains(references(documents[0]), "snapshots/before().")
137+
assertContains(references(documents[1]), "snapshots/after().")
138+
}
139+
96140
private fun definitions(document: Document): List<String> =
97141
document.occurrencesList
98142
.filter { it.symbolRoles and SymbolRole.Definition.number != 0 }

0 commit comments

Comments
 (0)