[LL FIR] KT-58257 Fix session project leak in invokeLater lambda
- The lambda passed to `invokeLater` in `LLFirSession.invalidate` might survive beyond project disposal (especially in tests), so me must not capture a hard reference to the session that can leak its `project`.
This commit is contained in:
committed by
Space Team
parent
bb92d19b47
commit
edadfd0daa
+19
-7
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.FirSession
|
|||||||
import org.jetbrains.kotlin.fir.PrivateSessionConstructor
|
import org.jetbrains.kotlin.fir.PrivateSessionConstructor
|
||||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
|
|
||||||
@@ -58,8 +59,12 @@ abstract class LLFirSession(
|
|||||||
"Outside a write action, a session may only be invalidated directly when FIR guards are turned off."
|
"Outside a write action, a session may only be invalidated directly when FIR guards are turned off."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The lambda passed to `invokeLater` might survive beyond project disposal (especially in tests), so me must not capture a hard
|
||||||
|
// reference to `this` that can leak `project`. A weak reference is appropriate because we do not need to invalidate the session
|
||||||
|
// when it has already been collected.
|
||||||
|
val weakSession = WeakReference(this)
|
||||||
application.invokeLater(
|
application.invokeLater(
|
||||||
{ application.runWriteAction { invalidateInWriteAction() } },
|
{ weakSession.invalidateIfAlive() },
|
||||||
|
|
||||||
// `ModalityState.any()` can be used because session invalidation does not modify PSI, VFS, or the project model.
|
// `ModalityState.any()` can be used because session invalidation does not modify PSI, VFS, or the project model.
|
||||||
ModalityState.any(),
|
ModalityState.any(),
|
||||||
@@ -67,12 +72,6 @@ abstract class LLFirSession(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun invalidateInWriteAction() {
|
|
||||||
if (!isValid) return
|
|
||||||
|
|
||||||
LLFirSessionInvalidationService.getInstance(project).invalidate(ktModule)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a [ModificationTracker] which tracks the validity of this session via [isValid].
|
* Creates a [ModificationTracker] which tracks the validity of this session via [isValid].
|
||||||
*/
|
*/
|
||||||
@@ -93,6 +92,19 @@ abstract class LLFirSession(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun LLFirSession.invalidateInWriteAction() {
|
||||||
|
if (!isValid) return
|
||||||
|
|
||||||
|
LLFirSessionInvalidationService.getInstance(project).invalidate(ktModule)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun WeakReference<LLFirSession>.invalidateIfAlive() = ApplicationManager.getApplication().runWriteAction {
|
||||||
|
val session = get() ?: return@runWriteAction
|
||||||
|
if (session.project.isDisposed) return@runWriteAction
|
||||||
|
|
||||||
|
session.invalidateInWriteAction()
|
||||||
|
}
|
||||||
|
|
||||||
abstract class LLFirModuleSession(
|
abstract class LLFirModuleSession(
|
||||||
ktModule: KtModule,
|
ktModule: KtModule,
|
||||||
builtinTypes: BuiltinTypes,
|
builtinTypes: BuiltinTypes,
|
||||||
|
|||||||
Reference in New Issue
Block a user