Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Deadlock with IDEA EAP 2023-3 EAP #1193

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading