Fix PsiEnvironment thread safety in SymbolExtractor#11
Conversation
extractSymbolsFromDirs and extractDependenciesFromBuildFile each created a new PsiEnvironment per call. When ContextTask runs these in parallel across 4 threads, multiple threads simultaneously call KotlinCoreEnvironment.createForProduction(), racing on IntelliJ's global ApplicationManager singleton and leaving the internal lateinit module uninitialized — crashing every project with "lateinit property module has not been initialized". Switch both methods to use PsiEnvironment.shared() with synchronized access, matching the pattern already used by scanSources.
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 52 minutes and 27 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/main/kotlin/zone/clanker/gradle/srcx/scan/SymbolExtractor.kt (1)
291-294: Narrow the synchronized section to avoid lock contention on file I/O.
buildFile.readText()(Line 293) does not require PSI access; keeping it insidesynchronized(env)serializes avoidable I/O across threads.♻️ Proposed refactor
- val env = PsiEnvironment.shared() ?: return emptyList() - return synchronized(env) { - val vf = LightVirtualFile(buildFile.name, KotlinFileType.INSTANCE, buildFile.readText()) + val scriptText = buildFile.readText() + val env = PsiEnvironment.shared() ?: return emptyList() + return synchronized(env) { + val vf = LightVirtualFile(buildFile.name, KotlinFileType.INSTANCE, scriptText) val ktFile = env.psiManager.findFile(vf) as? KtFile ?: return@synchronized emptyList()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/kotlin/zone/clanker/gradle/srcx/scan/SymbolExtractor.kt` around lines 291 - 294, Move file I/O out of the synchronized block: call buildFile.readText() before entering synchronized(env) and pass the resulting String into LightVirtualFile, so only PSI-dependent operations (PsiEnvironment.shared(), env.psiManager.findFile(...), casting to KtFile) remain inside synchronized(env); update references around LightVirtualFile, buildFile.readText(), and the synchronized(env) block to reflect this narrower synchronization.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/main/kotlin/zone/clanker/gradle/srcx/scan/SymbolExtractor.kt`:
- Around line 291-294: Move file I/O out of the synchronized block: call
buildFile.readText() before entering synchronized(env) and pass the resulting
String into LightVirtualFile, so only PSI-dependent operations
(PsiEnvironment.shared(), env.psiManager.findFile(...), casting to KtFile)
remain inside synchronized(env); update references around LightVirtualFile,
buildFile.readText(), and the synchronized(env) block to reflect this narrower
synchronization.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c742ba87-8327-49c9-b999-919561153bb2
📒 Files selected for processing (1)
src/main/kotlin/zone/clanker/gradle/srcx/scan/SymbolExtractor.kt
Pass the exception as the second argument to logger.warn/error in handleAnalysisFailure, extractSymbolsFromDirs, and PsiEnvironment.shared so Gradle prints the full stack trace instead of just the message.
Summary
extractSymbolsFromDirsandextractDependenciesFromBuildFileeach created a newPsiEnvironment()per call. WhenContextTaskruns these in parallel across 4 threads viarunParallelMapped, multiple threads simultaneously callKotlinCoreEnvironment.createForProduction(), racing on IntelliJ's globalApplicationManagersingleton and leaving the internallateinit var moduleuninitialized.Analysis failed for '<module>': lateinit property module has not been initializedPsiEnvironment.shared()withsynchronized(env), matching the pattern already used byscanSources.Test plan
./gradlew buildpasses (detekt, ktlint, tests, kover)srcx-contexton a multi-module repo to verify analysis completes without lateinit errorsSummary by CodeRabbit