Skip to content

Commit ebccf84

Browse files
nafgclaude
andcommitted
Fix deadlock in Extract Method when multiple scopes exist
Replace PsiTargetNavigator with JBPopupFactory in showPsiChooser to avoid a deadlock caused by runBlocking on the EDT. PsiTargetNavigator.createPopup() internally calls computeItems() which uses runBlocking, blocking the EDT while dispatching work to coroutine workers. Those workers contend for the indexing lock (ChangeTrackingValueContainer), which can't be released because the EDT is blocked. This causes a permanent deadlock (34 threads blocked). The fix delegates to showChooserGeneric which uses JBPopupFactory — a safe popup mechanism already used elsewhere in the same file. Fixes #712 Co-Authored-By: Claude Code (Anthropic) <noreply@anthropic.com>
1 parent ec2a3ca commit ebccf84

File tree

1 file changed

+4
-28
lines changed

1 file changed

+4
-28
lines changed

scala/scala-impl/src/org/jetbrains/plugins/scala/lang/refactoring/util/ScalaRefactoringUtil.scala

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package org.jetbrains.plugins.scala.lang.refactoring.util
22

33
import com.intellij.codeInsight.PsiEquivalenceUtil
44
import com.intellij.codeInsight.highlighting.HighlightManager
5-
import com.intellij.codeInsight.navigation.PsiTargetNavigator
65
import com.intellij.codeInsight.unwrap.ScopeHighlighter
76
import com.intellij.openapi.application.ApplicationManager
87
import com.intellij.openapi.editor.colors.{EditorColors, EditorColorsScheme}
@@ -12,7 +11,6 @@ import com.intellij.openapi.project.Project
1211
import com.intellij.openapi.ui.popup.{JBPopup, JBPopupFactory, JBPopupListener, LightweightWindowEvent}
1312
import com.intellij.openapi.util.{Key, TextRange}
1413
import com.intellij.openapi.vfs.ReadonlyStatusHandler
15-
import com.intellij.platform.backend.presentation.TargetPresentation
1614
import com.intellij.psi._
1715
import com.intellij.psi.search.searches.ReferencesSearch
1816
import com.intellij.psi.search.{GlobalSearchScope, LocalSearchScope}
@@ -547,32 +545,10 @@ object ScalaRefactoringUtil {
547545
presentation: T => String,
548546
toHighlight: PsiElement => PsiElement = identity)
549547
(implicit project: Project, editor: Editor): Unit =
550-
showChooserImpl(onChosen) { chooserModel =>
551-
new PsiTargetNavigator(elements.asJava)
552-
.presentationProvider((element: T) => TargetPresentation.builder(presentation(element)).presentation())
553-
.builderConsumer { builder =>
554-
builder
555-
.setMovable(false)
556-
.setResizable(false)
557-
.setRequestFocus(true)
558-
.addListener(chooserModel.highlighterPopupListener)
559-
.setItemSelectedCallback { item =>
560-
if (item != null) {
561-
val element = item.dereference()
562-
if (element != null) {
563-
val psiElement = toHighlight(element)
564-
if (psiElement != null) {
565-
chooserModel.highlightPsi.accept(psiElement)
566-
}
567-
}
568-
}
569-
}
570-
}
571-
.createPopup(project, title, (element: T) => {
572-
chooserModel.elementChosen.accept(element)
573-
true
574-
})
575-
}
548+
// Use JBPopupFactory instead of PsiTargetNavigator to avoid deadlock.
549+
// PsiTargetNavigator.createPopup() calls computeItems() which uses runBlocking on the EDT,
550+
// causing a deadlock when worker threads contend for the indexing lock. See #712.
551+
showChooserGeneric[T](elements, onChosen, title, presentation, toHighlight(_))
576552

577553
/** See [[showChooserImpl]] */
578554
private final case class HighlightingChooserModel[T](

0 commit comments

Comments
 (0)