From 246439d27e3ee88d4473563672d08bcb7363b68e Mon Sep 17 00:00:00 2001 From: azerr Date: Wed, 18 Dec 2024 11:16:01 +0100 Subject: [PATCH] fix: process element usages under ReadAction Fixes #708 --- .../usages/LSPExternalReferencesFinder.java | 9 +- .../lsp4ij/usages/LSPUsageSearcher.java | 124 +++++++++--------- 2 files changed, 63 insertions(+), 70 deletions(-) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/usages/LSPExternalReferencesFinder.java b/src/main/java/com/redhat/devtools/lsp4ij/usages/LSPExternalReferencesFinder.java index 8561f2176..276766dd4 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/usages/LSPExternalReferencesFinder.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/usages/LSPExternalReferencesFinder.java @@ -13,7 +13,6 @@ *******************************************************************************/ package com.redhat.devtools.lsp4ij.usages; -import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.editor.Document; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; @@ -56,7 +55,7 @@ private LSPExternalReferencesFinder() { public static void processExternalReferences(@NotNull PsiFile file, int offset, @NotNull Processor processor) { - processExternalReferences(file, offset, ReadAction.compute(file::getUseScope), processor); + processExternalReferences(file, offset, file.getUseScope(), processor); } /** @@ -77,7 +76,7 @@ public static void processExternalReferences(@NotNull PsiFile file, TextRange wordTextRange = document != null ? LSPIJUtils.getWordRangeAt(document, file, offset) : null; if (wordTextRange != null) { LSPPsiElement wordElement = new LSPPsiElement(file, wordTextRange); - String wordText = ReadAction.compute(wordElement::getText); + String wordText = wordElement.getText(); if (StringUtil.isNotEmpty(wordText)) { processExternalReferences( file, @@ -113,7 +112,7 @@ private static void processExternalReferences(@NotNull PsiFile file, } Set externalReferenceKeys = new HashSet<>(); - ReadAction.run(() -> PsiSearchHelper.getInstance(project).processElementsWithWord( + PsiSearchHelper.getInstance(project).processElementsWithWord( (element, offsetInElement) -> { PsiReference originalReference = element.findReferenceAt(offsetInElement); List references = originalReference != null ? @@ -154,7 +153,7 @@ private static void processExternalReferences(@NotNull PsiFile file, wordText, UsageSearchContext.ANY, caseSensitive - )); + ); } @Nullable diff --git a/src/main/java/com/redhat/devtools/lsp4ij/usages/LSPUsageSearcher.java b/src/main/java/com/redhat/devtools/lsp4ij/usages/LSPUsageSearcher.java index 8e569a24f..949249950 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/usages/LSPUsageSearcher.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/usages/LSPUsageSearcher.java @@ -12,7 +12,6 @@ import com.intellij.find.findUsages.CustomUsageSearcher; import com.intellij.find.findUsages.FindUsagesOptions; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.editor.Document; import com.intellij.openapi.progress.ProcessCanceledException; @@ -55,84 +54,78 @@ public class LSPUsageSearcher extends CustomUsageSearcher { @Override public void processElementUsages(@NotNull PsiElement element, @NotNull Processor processor, @NotNull FindUsagesOptions options) { + // Ensure that LSP process elements usage is executed in a ReadAction. + ReadAction.run(() -> { + PsiFile file = element.getContainingFile(); + if (file == null) { + return; + } - PsiFile file = element.getContainingFile(); - if (file == null) { - return; - } + VirtualFile virtualFile = file.getVirtualFile(); + if (virtualFile == null) { + return; + } - VirtualFile virtualFile = file.getVirtualFile(); - if (virtualFile == null) { - return; - } + Project project = element.getProject(); + if (!LanguageServiceAccessor.getInstance(project).hasAny( + virtualFile, + l -> l.getClientFeatures().getUsageFeature().isSupported(file) + )) { + return; + } - Project project = element.getProject(); - if (!LanguageServiceAccessor.getInstance(project).hasAny( - virtualFile, - l -> l.getClientFeatures().getUsageFeature().isSupported(file) - )) { - return; - } + if (element instanceof LSPUsageTriggeredPsiElement elt) { + if (elt.getLSPReferences() != null) { + elt.getLSPReferences() + .forEach(ref -> { + var psiElement = LSPUsagesManager.toPsiElement(ref.location(), ref.languageServer().getClientFeatures(), LSPUsagePsiElement.UsageKind.references, project); + if (psiElement != null) { + processor.process(new UsageInfo2UsageAdapter(new UsageInfo(psiElement))); + } + }); + return; + } + } - if (element instanceof LSPUsageTriggeredPsiElement elt) { - if (elt.getLSPReferences() != null) { - elt.getLSPReferences() - .forEach(ref -> { - var psiElement = LSPUsagesManager.toPsiElement(ref.location(), ref.languageServer().getClientFeatures(), LSPUsagePsiElement.UsageKind.references, project); - if (psiElement != null) { - processor.process(ReadAction.compute(() -> new UsageInfo2UsageAdapter(new UsageInfo(psiElement)))); - } - }); + // Get position where the "Find Usages" has been triggered + Position position = getPosition(element, file); + if (position == null) { return; } - } - - // Get position where the "Find Usages" has been triggered - Position position = getPosition(element, file); - if (position == null) { - return; - } - // Collect textDocument/definition, textDocument/references, etc - LSPUsageSupport usageSupport = new LSPUsageSupport(ReadAction.compute(() -> file)); - LSPUsageSupport.LSPUsageSupportParams params = new LSPUsageSupport.LSPUsageSupportParams(position); - CompletableFuture> usagesFuture = usageSupport.getFeatureData(params); - try { - // Wait for completion of textDocument/definition, textDocument/references, etc - waitUntilDone(usagesFuture); - if (usagesFuture.isDone()) { - // Show response of textDocument/definition, textDocument/references, etc as usage info. - List usages = usagesFuture.getNow(null); - if (usages != null) { - for (LSPUsagePsiElement usage : usages) { - processor.process(ReadAction.compute(() -> new UsageInfo2UsageAdapter(new UsageInfo(usage)))); + // Collect textDocument/definition, textDocument/references, etc + LSPUsageSupport usageSupport = new LSPUsageSupport(file); + LSPUsageSupport.LSPUsageSupportParams params = new LSPUsageSupport.LSPUsageSupportParams(position); + CompletableFuture> usagesFuture = usageSupport.getFeatureData(params); + try { + // Wait for completion of textDocument/definition, textDocument/references, etc + waitUntilDone(usagesFuture); + if (usagesFuture.isDone()) { + // Show response of textDocument/definition, textDocument/references, etc as usage info. + List usages = usagesFuture.getNow(null); + if (usages != null) { + for (LSPUsagePsiElement usage : usages) { + processor.process(new UsageInfo2UsageAdapter(new UsageInfo(usage))); + } } } + } catch (ProcessCanceledException pce) { + throw pce; + } catch (Exception e) { + LOGGER.error("Error while collection LSP Usages", e); } - } catch (ProcessCanceledException pce) { - throw pce; - } catch (Exception e) { - LOGGER.error("Error while collection LSP Usages", e); - } - // For completeness' sake, also collect external usages to LSP (pseudo-)elements - LSPExternalReferencesFinder.processExternalReferences( - file, - ReadAction.compute(element::getTextOffset), - options.searchScope, - reference -> processor.process(ReadAction.compute(() -> new UsageInfo2UsageAdapter(new UsageInfo(reference)))) - ); + // For completeness' sake, also collect external usages to LSP (pseudo-)elements + LSPExternalReferencesFinder.processExternalReferences( + file, + element.getTextOffset(), + options.searchScope, + reference -> processor.process(new UsageInfo2UsageAdapter(new UsageInfo(reference))) + ); + }); } @Nullable private static Position getPosition(@NotNull PsiElement element, @NotNull PsiFile psiFile) { - if (ApplicationManager.getApplication().isReadAccessAllowed()) { - return doGetPosition(element, psiFile); - } - return ReadAction.compute(() -> doGetPosition(element, psiFile)); - } - - @Nullable - private static Position doGetPosition(@NotNull PsiElement element, @NotNull PsiFile psiFile) { VirtualFile file = psiFile.getVirtualFile(); if (file == null) { return null; @@ -144,3 +137,4 @@ private static Position doGetPosition(@NotNull PsiElement element, @NotNull PsiF return LSPIJUtils.toPosition(Math.min(element.getTextRange().getStartOffset() + 1, element.getTextRange().getEndOffset()), document); } } +