Skip to content

Commit

Permalink
fix: Deadlock with IDEA EAP 2023-3 EAP
Browse files Browse the repository at this point in the history
Fixes #1192

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Oct 4, 2023
1 parent abf9c7d commit d8a9d5c
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ private void bind(CancellablePromise<ResultOrError<R>> promise) {
promise.onError(ex -> {
if (ex instanceof ProcessCanceledException || ex instanceof CancellationException) {
// Case 2: cancel the completable future
this.cancel(true);
super.cancel(true);
} else {
// Other case..., mark the completable future as error
this.completeExceptionally(ex);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright (c) 2023 Red Hat Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.devtools.intellij.lsp4ij.internal;

public class StringUtils {

/**
* Copied code from https://github.com/apache/commons-lang/blob/24744a40b2c094945e542b71cc1fbf59caa0d70b/src/main/java/org/apache/commons/lang3/StringUtils.java#L3714C5-L3716C6
* @param cs
* @return
*/
public static boolean isNotBlank(final CharSequence cs) {
return !isBlank(cs);
}

/**
* Copied code from https://github.com/apache/commons-lang/blob/24744a40b2c094945e542b71cc1fbf59caa0d70b/src/main/java/org/apache/commons/lang3/StringUtils.java#L3564
* @param cs
* @return
*/
public static boolean isBlank(final CharSequence cs) {
final int strLen = length(cs);
if (strLen == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
}

/**
* Copied code from https://github.com/apache/commons-lang/blob/24744a40b2c094945e542b71cc1fbf59caa0d70b/src/main/java/org/apache/commons/lang3/StringUtils.java#L5281
* @param cs
* @return
*/
public static int length(final CharSequence cs) {
return cs == null ? 0 : cs.length();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils;
import com.redhat.devtools.intellij.lsp4ij.LanguageServerWrapper;
import com.redhat.devtools.intellij.lsp4ij.commands.CommandExecutor;
import org.apache.commons.lang.StringUtils;
import com.redhat.devtools.intellij.lsp4ij.internal.StringUtils;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.CodeActionOptions;
import org.eclipse.lsp4j.Command;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,28 +72,33 @@ public boolean collect(@NotNull PsiElement psiElement, @NotNull Editor editor, @
// The project has been closed, don't collect code lenses.
return false;
}
VirtualFile file = LSPIJUtils.getFile(psiFile);
if (file == null) {
return false;
}
URI fileUri = LSPIJUtils.toUri(file);
if (fileUri == null) {
return false;
}
Document document = editor.getDocument();
final CancellationSupport cancellationSupport = new CancellationSupport();
try {
VirtualFile file = LSPIJUtils.getFile(psiElement);
URI docURI = LSPIJUtils.toUri(file);
if (docURI != null) {
CodeLensParams param = new CodeLensParams(new TextDocumentIdentifier(docURI.toString()));
BlockingDeque<Pair<CodeLens, LanguageServer>> pairs = new LinkedBlockingDeque<>();

CompletableFuture<Void> future = collect(file, project, param, pairs, cancellationSupport);
List<Pair<Integer, Pair<CodeLens, LanguageServer>>> codeLenses = createCodeLenses(document, pairs, future, cancellationSupport);
codeLenses.stream()
.collect(Collectors.groupingBy(p -> p.first))
.forEach((offset, list) ->
inlayHintsSink.addBlockElement(
offset,
true,
true,
0,
toPresentation(editor, offset, list, getFactory()))
);
}
CodeLensParams param = new CodeLensParams(new TextDocumentIdentifier(fileUri.toString()));
BlockingDeque<Pair<CodeLens, LanguageServer>> pairs = new LinkedBlockingDeque<>();

CompletableFuture<Void> future = collect(file, project, param, pairs, cancellationSupport);
List<Pair<Integer, Pair<CodeLens, LanguageServer>>> codeLenses = createCodeLenses(document, pairs, future, cancellationSupport);
codeLenses.stream()
.collect(Collectors.groupingBy(p -> p.first))
.forEach((offset, list) ->
inlayHintsSink.addBlockElement(
offset,
true,
true,
0,
toPresentation(editor, offset, list, getFactory()))
);
} catch (ProcessCanceledException e) {
// Cancel all LSP requests
cancellationSupport.cancel();
Expand All @@ -109,16 +114,11 @@ public boolean collect(@NotNull PsiElement psiElement, @NotNull Editor editor, @
private List<Pair<Integer, Pair<CodeLens, LanguageServer>>> createCodeLenses(Document document, BlockingDeque<Pair<CodeLens, LanguageServer>> pairs, CompletableFuture<Void> future, CancellationSupport cancellationSupport) throws InterruptedException {
List<Pair<Integer, Pair<CodeLens, LanguageServer>>> codelenses = new ArrayList<>();
while (!future.isDone() || !pairs.isEmpty()) {
try {
ProgressManager.checkCanceled();
Pair<CodeLens, LanguageServer> pair = pairs.poll(25, TimeUnit.MILLISECONDS);
if (pair != null) {
int offset = LSPIJUtils.toOffset(pair.getFirst().getRange().getStart(), document);
codelenses.add(Pair.create(offset, pair));
}
} catch (ProcessCanceledException e) {
cancellationSupport.cancel();
throw e;
ProgressManager.checkCanceled();
Pair<CodeLens, LanguageServer> pair = pairs.poll(25, TimeUnit.MILLISECONDS);
if (pair != null) {
int offset = LSPIJUtils.toOffset(pair.getFirst().getRange().getStart(), document);
codelenses.add(Pair.create(offset, pair));
}
}
return codelenses;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import com.redhat.devtools.intellij.lsp4ij.LanguageServerItem;
import com.redhat.devtools.intellij.lsp4ij.LanguageServiceAccessor;
import com.redhat.devtools.intellij.lsp4ij.internal.CancellationSupport;
import org.apache.commons.lang.StringUtils;
import com.redhat.devtools.intellij.lsp4ij.internal.StringUtils;
import org.eclipse.lsp4j.*;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.eclipse.lsp4j.services.LanguageServer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
import com.redhat.devtools.intellij.lsp4ij.LanguageServerItem;
import com.redhat.devtools.intellij.lsp4ij.LanguageServiceAccessor;
import com.redhat.devtools.intellij.lsp4ij.commands.CommandExecutor;
import com.redhat.devtools.intellij.lsp4ij.internal.StringUtils;
import com.redhat.devtools.intellij.lsp4ij.operations.completion.snippet.LspSnippetIndentOptions;
import org.apache.commons.lang.StringUtils;
import org.eclipse.lsp4j.*;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.jetbrains.annotations.NotNull;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,30 +37,17 @@ public class LSPDiagnosticsForServer {

private final LanguageServerWrapper languageServerWrapper;

private final boolean codeActionSupported;

private final VirtualFile file;

// Map which contains all current diagnostics (as key) and future which load associated quick fixes (as value)
private Map<Diagnostic, LSPLazyCodeActions> diagnostics;

public LSPDiagnosticsForServer(LanguageServerWrapper languageServerWrapper, VirtualFile file) {
this.languageServerWrapper = languageServerWrapper;
this.codeActionSupported = isCodeActionSupported(languageServerWrapper);
this.file = file;
this.diagnostics = Collections.emptyMap();
}

private static boolean isCodeActionSupported(LanguageServerWrapper languageServerWrapper) {
if (!languageServerWrapper.isActive() || languageServerWrapper.isStopping()) {
// This use-case comes from when a diagnostics is published and the language server is stopped
// We cannot use here languageServerWrapper.getServerCapabilities() otherwise it will restart the language server.
return false;
}
ServerCapabilities serverCapabilities = languageServerWrapper.getServerCapabilities();
return serverCapabilities != null && LSPIJUtils.hasCapability(serverCapabilities.getCodeActionProvider());
}

/**
* Update the new LSP published diagnosics.
*
Expand Down Expand Up @@ -101,11 +88,22 @@ public Set<Diagnostic> getDiagnostics() {
* @return Intellij quickfixes for the given diagnostic if there available.
*/
public List<LSPLazyCodeActionIntentionAction> getQuickFixesFor(Diagnostic diagnostic) {
boolean codeActionSupported = isCodeActionSupported(languageServerWrapper);
if (!codeActionSupported || diagnostics.isEmpty()) {
return Collections.emptyList();
}
LSPLazyCodeActions codeActions = diagnostics.get(diagnostic);
return codeActions != null ? codeActions.getCodeActions() : Collections.emptyList();
}

private static boolean isCodeActionSupported(LanguageServerWrapper languageServerWrapper) {
if (!languageServerWrapper.isActive() || languageServerWrapper.isStopping()) {
// This use-case comes from when a diagnostics is published and the language server is stopped
// We cannot use here languageServerWrapper.getServerCapabilities() otherwise it will restart the language server.
return false;
}
ServerCapabilities serverCapabilities = languageServerWrapper.getServerCapabilities();
return serverCapabilities != null && LSPIJUtils.hasCapability(serverCapabilities.getCodeActionProvider());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,19 @@ public boolean collect(@NotNull PsiElement psiElement, @NotNull Editor editor, @
// The project has been closed, don't collect inlay hints.
return false;
}
VirtualFile file = LSPIJUtils.getFile(psiFile);
if (file == null) {
return false;
}
URI fileUri = LSPIJUtils.toUri(file);
if (fileUri == null) {
return false;
}
Document document = editor.getDocument();
final CancellationSupport cancellationSupport = new CancellationSupport();
try {
VirtualFile file = LSPIJUtils.getFile(psiFile);
if (file == null) {
return false;
}
URI docURI = LSPIJUtils.toUri(file);
Range viewPortRange = getViewPortRange(editor);
InlayHintParams param = new InlayHintParams(new TextDocumentIdentifier(docURI.toString()), viewPortRange);
InlayHintParams param = new InlayHintParams(new TextDocumentIdentifier(fileUri.toASCIIString()), viewPortRange);
BlockingDeque<Pair<InlayHint, LanguageServer>> pairs = new LinkedBlockingDeque<>();

CompletableFuture<Void> future = collect(psiElement.getProject(), file, param, pairs, cancellationSupport);
Expand All @@ -90,7 +93,7 @@ public boolean collect(@NotNull PsiElement psiElement, @NotNull Editor editor, @
} catch (ProcessCanceledException e) {
// Cancel all LSP requests
cancellationSupport.cancel();
throw e;
return false; //throw e;
} catch (InterruptedException e) {
LOGGER.warn(e.getLocalizedMessage(), e);
Thread.currentThread().interrupt();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@
import com.intellij.ide.plugins.PluginManager;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.project.Project;
import com.redhat.devtools.intellij.lsp4ij.operations.codelens.LSPCodelensInlayProvider;
import com.redhat.devtools.intellij.lsp4mp4ij.settings.MicroProfileInspectionsInfo;
import com.redhat.devtools.intellij.quarkus.TelemetryService;
import com.redhat.devtools.intellij.lsp4ij.server.JavaProcessCommandBuilder;
import com.redhat.devtools.intellij.lsp4ij.server.ProcessStreamConnectionProvider;
import com.redhat.devtools.intellij.lsp4mp4ij.settings.UserDefinedMicroProfileSettings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.URI;
Expand All @@ -32,6 +35,8 @@
*/
public class QuarkusServer extends ProcessStreamConnectionProvider {

private static final Logger LOGGER = LoggerFactory.getLogger(QuarkusServer.class);

private final Project project;

public QuarkusServer(Project project) {
Expand All @@ -47,7 +52,12 @@ public QuarkusServer(Project project) {
commands.add("-DrunAsync=true");
super.setCommands(commands);

TelemetryService.instance().action(TelemetryService.LSP_PREFIX + "start").send();
try {
TelemetryService.instance().action(TelemetryService.LSP_PREFIX + "start").send();
}
catch(Exception e) {
LOGGER.error("Error while consuming telemetry service", e);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
import com.redhat.devtools.intellij.quarkus.TelemetryService;
import com.redhat.devtools.intellij.lsp4ij.server.JavaProcessCommandBuilder;
import com.redhat.devtools.intellij.lsp4ij.server.ProcessStreamConnectionProvider;
import com.redhat.devtools.intellij.quarkus.lsp.QuarkusServer;
import com.redhat.devtools.intellij.qute.settings.QuteInspectionsInfo;
import com.redhat.devtools.intellij.qute.settings.UserDefinedQuteSettings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.URI;
Expand All @@ -33,6 +36,8 @@
*/
public class QuteServer extends ProcessStreamConnectionProvider {

private static final Logger LOGGER = LoggerFactory.getLogger(QuteServer.class);

private final Project project;

public QuteServer(Project project) {
Expand All @@ -46,7 +51,12 @@ public QuteServer(Project project) {
commands.add("-DrunAsync=true");
super.setCommands(commands);

TelemetryService.instance().action(TelemetryService.LSP_PREFIX + "startQute").send();
try {
TelemetryService.instance().action(TelemetryService.LSP_PREFIX + "startQute").send();
}
catch(Exception e) {
LOGGER.error("Error while consuming telemetry service", e);
}
}

@Override
Expand Down

0 comments on commit d8a9d5c

Please sign in to comment.