From 5c13e1cc4bd086e50979ddc9b4a4568d4101d7f8 Mon Sep 17 00:00:00 2001 From: azerr Date: Fri, 1 Sep 2023 09:11:54 +0200 Subject: [PATCH] fix: ResponseErrorException when Ctrl+Hover due to cancellation Fixes #1136 Signed-off-by: azerr --- .../lsp4ij/internal/CancellationUtil.java | 44 ++++++++++++++ .../documentation/LSPTextHoverForFile.java | 9 ++- .../navigation/LSPGotoDeclarationHandler.java | 58 ++++++++++--------- 3 files changed, 80 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/redhat/devtools/intellij/lsp4ij/internal/CancellationUtil.java diff --git a/src/main/java/com/redhat/devtools/intellij/lsp4ij/internal/CancellationUtil.java b/src/main/java/com/redhat/devtools/intellij/lsp4ij/internal/CancellationUtil.java new file mode 100644 index 000000000..fc678163f --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/lsp4ij/internal/CancellationUtil.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2023 Avaloq Group AG. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Rubén Porras Campo (Avaloq Group AG) - Initial Implementation + *******************************************************************************/ +package com.redhat.devtools.intellij.lsp4ij.internal; + +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; + +import org.eclipse.lsp4j.jsonrpc.ResponseErrorException; +import org.eclipse.lsp4j.jsonrpc.messages.ResponseError; +import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode; + +public final class CancellationUtil { + + private CancellationUtil() { + // this class shouldn't be instantiated + } + + public static boolean isRequestCancelledException(Throwable throwable) { + if (throwable instanceof CompletionException | throwable instanceof ExecutionException) { + throwable = throwable.getCause(); + } + if (throwable instanceof ResponseErrorException) { + return isRequestCancelled((ResponseErrorException)throwable); + } + return throwable instanceof CancellationException; + } + + private static boolean isRequestCancelled(ResponseErrorException responseErrorException) { + ResponseError responseError = responseErrorException.getResponseError(); + return responseError != null + && responseError.getCode() == ResponseErrorCode.RequestCancelled.getValue(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/documentation/LSPTextHoverForFile.java b/src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/documentation/LSPTextHoverForFile.java index 9ef79c55c..e8d271d51 100644 --- a/src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/documentation/LSPTextHoverForFile.java +++ b/src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/documentation/LSPTextHoverForFile.java @@ -17,7 +17,9 @@ import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils; import com.redhat.devtools.intellij.lsp4ij.LanguageServiceAccessor; import com.redhat.devtools.intellij.lsp4ij.internal.CancellationSupport; +import com.redhat.devtools.intellij.lsp4ij.internal.CancellationUtil; import org.eclipse.lsp4j.*; +import org.eclipse.lsp4j.jsonrpc.ResponseErrorException; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -52,15 +54,16 @@ public List getHoverContent(PsiElement element, int targetOffset, // The LSP hover request are finished, don't need to cancel the previous LSP requests. previousCancellationSupport = null; return result; - } catch (ExecutionException e) { - if (!(e.getCause() instanceof CancellationException)) { + } catch (ResponseErrorException | ExecutionException | CancellationException e) { + // do not report error if the server has cancelled the request + if (!CancellationUtil.isRequestCancelledException(e)) { LOGGER.warn(e.getLocalizedMessage(), e); } } catch (TimeoutException e) { LOGGER.warn(e.getLocalizedMessage(), e); } catch (InterruptedException e) { - LOGGER.warn(e.getLocalizedMessage(), e); Thread.currentThread().interrupt(); + LOGGER.warn(e.getLocalizedMessage(), e); } return null; } diff --git a/src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/navigation/LSPGotoDeclarationHandler.java b/src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/navigation/LSPGotoDeclarationHandler.java index ba8959ebe..1fef0ca9c 100644 --- a/src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/navigation/LSPGotoDeclarationHandler.java +++ b/src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/navigation/LSPGotoDeclarationHandler.java @@ -24,10 +24,12 @@ import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils; import com.redhat.devtools.intellij.lsp4ij.LanguageServiceAccessor; import com.redhat.devtools.intellij.lsp4ij.internal.CancellationSupport; +import com.redhat.devtools.intellij.lsp4ij.internal.CancellationUtil; import com.redhat.devtools.intellij.lsp4mp4ij.psi.internal.core.ls.PsiUtilsLSImpl; import org.eclipse.lsp4j.DefinitionParams; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.LocationLink; +import org.eclipse.lsp4j.jsonrpc.ResponseErrorException; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -40,10 +42,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.*; import java.util.stream.Collectors; public class LSPGotoDeclarationHandler implements GotoDeclarationHandler { @@ -52,33 +51,36 @@ public class LSPGotoDeclarationHandler implements GotoDeclarationHandler { @Nullable @Override public PsiElement[] getGotoDeclarationTargets(@Nullable PsiElement sourceElement, int offset, Editor editor) { - try { - URI uri = LSPIJUtils.toUri(editor.getDocument()); - if (uri != null) { - DefinitionParams params = new DefinitionParams(LSPIJUtils.toTextDocumentIdentifier(uri), LSPIJUtils.toPosition(offset, editor.getDocument())); - Set targets = new HashSet<>(); - final CancellationSupport cancellationSupport = new CancellationSupport(); - try { - LanguageServiceAccessor.getInstance(editor.getProject()) - .getLanguageServers(editor.getDocument(), capabilities -> LSPIJUtils.hasCapability(capabilities.getDefinitionProvider())) - .thenComposeAsync(languageServers -> - cancellationSupport.execute( - CompletableFuture.allOf( - languageServers - .stream() - .map(server -> - cancellationSupport.execute(server.getServer().getTextDocumentService().definition(params)) - .thenAcceptAsync(definitions -> targets.addAll(toElements(editor.getProject(), definitions)))) - .toArray(CompletableFuture[]::new)))) - .get(1_000, TimeUnit.MILLISECONDS); - } catch (ExecutionException | TimeoutException e) { + URI uri = LSPIJUtils.toUri(editor.getDocument()); + if (uri != null) { + DefinitionParams params = new DefinitionParams(LSPIJUtils.toTextDocumentIdentifier(uri), LSPIJUtils.toPosition(offset, editor.getDocument())); + Set targets = new HashSet<>(); + final CancellationSupport cancellationSupport = new CancellationSupport(); + try { + LanguageServiceAccessor.getInstance(editor.getProject()) + .getLanguageServers(editor.getDocument(), capabilities -> LSPIJUtils.hasCapability(capabilities.getDefinitionProvider())) + .thenComposeAsync(languageServers -> + cancellationSupport.execute( + CompletableFuture.allOf( + languageServers + .stream() + .map(server -> + cancellationSupport.execute(server.getServer().getTextDocumentService().definition(params)) + .thenAcceptAsync(definitions -> targets.addAll(toElements(editor.getProject(), definitions)))) + .toArray(CompletableFuture[]::new)))) + .get(1_000, TimeUnit.MILLISECONDS); + } catch (ResponseErrorException | ExecutionException | CancellationException e) { + // do not report error if the server has cancelled the request + if (!CancellationUtil.isRequestCancelledException(e)) { LOGGER.warn(e.getLocalizedMessage(), e); } - return targets.toArray(new PsiElement[targets.size()]); + } catch (TimeoutException e) { + LOGGER.warn(e.getLocalizedMessage(), e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.warn(e.getLocalizedMessage(), e); } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOGGER.warn(e.getLocalizedMessage(), e); + return targets.toArray(new PsiElement[targets.size()]); } return new PsiElement[0]; }