Skip to content

Commit

Permalink
fix: ResponseErrorException when Ctrl+Hover due to cancellation
Browse files Browse the repository at this point in the history
Fixes #1136

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Sep 1, 2023
1 parent 3fbeb41 commit 5c13e1c
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -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();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -52,15 +54,16 @@ public List<MarkupContent> 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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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<PsiElement> 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<PsiElement> 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];
}
Expand Down

0 comments on commit 5c13e1c

Please sign in to comment.