From 2d2865e99abf86d31518095d7a03ce488bec4542 Mon Sep 17 00:00:00 2001 From: Nikita Fedkin Date: Fri, 14 Oct 2022 22:52:34 +0400 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D1=81=D0=BE=D0=BD=D0=B0=D1=80-=D0=BF=D0=BB=D0=B0=D0=B3=D0=B8?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BA=20bsl=20ls=20=D0=BF=D0=BE=20LSP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lombok.config | 1 + .../bsl/sonar/BSLCommunityProperties.java | 2 + .../_1c_syntax/bsl/sonar/BSLHighlighter.java | 1 + .../bsl/sonar/BSLLanguageServerInterface.java | 44 +++++ .../_1c_syntax/bsl/sonar/IssuesLoader.java | 10 +- .../bsl/sonar/LanguageClientBinding.java | 181 ++++++++++++++++++ ...LanguageServerDiagnosticsLoaderSensor.java | 3 + .../bsl/sonar/SonarLanguageClient.java | 80 ++++++++ .../_1c_syntax/bsl/sonar/BSLPluginTest.java | 3 + 9 files changed, 322 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/github/_1c_syntax/bsl/sonar/BSLLanguageServerInterface.java create mode 100644 src/main/java/com/github/_1c_syntax/bsl/sonar/LanguageClientBinding.java create mode 100644 src/main/java/com/github/_1c_syntax/bsl/sonar/SonarLanguageClient.java diff --git a/lombok.config b/lombok.config index 2e9a5449..3c5cfa9c 100644 --- a/lombok.config +++ b/lombok.config @@ -1,2 +1,3 @@ lombok.anyConstructor.addConstructorProperties=true lombok.addLombokGeneratedAnnotation=true +lombok.log.fieldname=LOGGER diff --git a/src/main/java/com/github/_1c_syntax/bsl/sonar/BSLCommunityProperties.java b/src/main/java/com/github/_1c_syntax/bsl/sonar/BSLCommunityProperties.java index dfa15722..5930646d 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/sonar/BSLCommunityProperties.java +++ b/src/main/java/com/github/_1c_syntax/bsl/sonar/BSLCommunityProperties.java @@ -21,7 +21,9 @@ */ package com.github._1c_syntax.bsl.sonar; +// TODO: в api или заменить на прямое указение language code import com.github._1c_syntax.bsl.languageserver.configuration.Language; +// TODO: в api import com.github._1c_syntax.bsl.languageserver.configuration.diagnostics.SkipSupport; import org.sonar.api.PropertyType; import org.sonar.api.config.PropertyDefinition; diff --git a/src/main/java/com/github/_1c_syntax/bsl/sonar/BSLHighlighter.java b/src/main/java/com/github/_1c_syntax/bsl/sonar/BSLHighlighter.java index 3bb5856f..64c2f65b 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/sonar/BSLHighlighter.java +++ b/src/main/java/com/github/_1c_syntax/bsl/sonar/BSLHighlighter.java @@ -22,6 +22,7 @@ package com.github._1c_syntax.bsl.sonar; import com.github._1c_syntax.bsl.languageserver.context.DocumentContext; +// TODO: в api/helpers import com.github._1c_syntax.bsl.languageserver.utils.Ranges; import com.github._1c_syntax.bsl.parser.BSLLexer; import com.github._1c_syntax.bsl.parser.SDBLLexer; diff --git a/src/main/java/com/github/_1c_syntax/bsl/sonar/BSLLanguageServerInterface.java b/src/main/java/com/github/_1c_syntax/bsl/sonar/BSLLanguageServerInterface.java new file mode 100644 index 00000000..9105f73e --- /dev/null +++ b/src/main/java/com/github/_1c_syntax/bsl/sonar/BSLLanguageServerInterface.java @@ -0,0 +1,44 @@ +/* + * This file is a part of SonarQube 1C (BSL) Community Plugin. + * + * Copyright (c) 2018-2022 + * Alexey Sosnoviy , Nikita Fedkin + * + * SPDX-License-Identifier: LGPL-3.0-or-later + * + * SonarQube 1C (BSL) Community Plugin is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * SonarQube 1C (BSL) Community Plugin is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SonarQube 1C (BSL) Community Plugin. + */ +package com.github._1c_syntax.bsl.sonar; + +import com.github._1c_syntax.bsl.languageserver.jsonrpc.DiagnosticParams; +import com.github._1c_syntax.bsl.languageserver.jsonrpc.Diagnostics; +import org.eclipse.lsp4j.jsonrpc.services.JsonRequest; +import org.eclipse.lsp4j.services.LanguageServer; + +import java.util.concurrent.CompletableFuture; + +// TODO: перенести в api bsl ls +public interface BSLLanguageServerInterface extends LanguageServer { + + /** + * @param params Параметры запроса. + * @return Список рассчитанных диагностик. + */ + @JsonRequest( + value = "textDocument/x-diagnostics", + useSegment = false + ) + CompletableFuture diagnostics(DiagnosticParams params); + +} diff --git a/src/main/java/com/github/_1c_syntax/bsl/sonar/IssuesLoader.java b/src/main/java/com/github/_1c_syntax/bsl/sonar/IssuesLoader.java index 8af7a624..f91b4db9 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/sonar/IssuesLoader.java +++ b/src/main/java/com/github/_1c_syntax/bsl/sonar/IssuesLoader.java @@ -21,7 +21,6 @@ */ package com.github._1c_syntax.bsl.sonar; -import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticCode; import com.github._1c_syntax.bsl.sonar.ext_issues.ExternalReporters; import com.github._1c_syntax.bsl.sonar.ext_issues.Reporter; import com.github._1c_syntax.bsl.sonar.language.BSLLanguage; @@ -33,6 +32,7 @@ import org.eclipse.lsp4j.DiagnosticSeverity; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.jetbrains.annotations.NotNull; import org.sonar.api.batch.fs.FilePredicates; import org.sonar.api.batch.fs.FileSystem; @@ -153,7 +153,7 @@ private Map computeLoaderSettings(SensorContext context) public void createIssue(InputFile inputFile, Diagnostic diagnostic) { - var ruleId = DiagnosticCode.getStringValue(diagnostic.getCode()); + var ruleId = getStringValue(diagnostic.getCode()); var settings = loaderSettings.get(diagnostic.getSource()); if (settings == null) { @@ -219,7 +219,7 @@ private void createExternalIssue(LoaderSettings settings, InputFile inputFile, D issue.engineId(settings.engineId); - var ruleId = DiagnosticCode.getStringValue(diagnostic.getCode()); + var ruleId = getStringValue(diagnostic.getCode()); issue.ruleId(ruleId); issue.type(ruleTypeMap.get(diagnostic.getSeverity())); @@ -239,6 +239,10 @@ private InputFile getInputFile(Path path) { return fileSystem.inputFile(predicates.and(predicates.hasLanguage(BSLLanguage.KEY), predicates.hasAbsolutePath(path.toAbsolutePath().toString()))); } + public static String getStringValue(Either diagnosticCode) { + return diagnosticCode.isLeft() ? diagnosticCode.getLeft() : Integer.toString(diagnosticCode.getRight()); + } + @Value @AllArgsConstructor private static class LoaderSettings { diff --git a/src/main/java/com/github/_1c_syntax/bsl/sonar/LanguageClientBinding.java b/src/main/java/com/github/_1c_syntax/bsl/sonar/LanguageClientBinding.java new file mode 100644 index 00000000..6499add3 --- /dev/null +++ b/src/main/java/com/github/_1c_syntax/bsl/sonar/LanguageClientBinding.java @@ -0,0 +1,181 @@ +/* + * This file is a part of SonarQube 1C (BSL) Community Plugin. + * + * Copyright (c) 2018-2022 + * Alexey Sosnoviy , Nikita Fedkin + * + * SPDX-License-Identifier: LGPL-3.0-or-later + * + * SonarQube 1C (BSL) Community Plugin is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * SonarQube 1C (BSL) Community Plugin is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SonarQube 1C (BSL) Community Plugin. + */ +package com.github._1c_syntax.bsl.sonar; + +// todo: interface в api. Либо сделать ProtocolExtension extends LanguageServer и тогда можно использовать родную +// реализацию через setRemoteInterface + +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.lsp4j.ClientCapabilities; +import org.eclipse.lsp4j.InitializeParams; +import org.eclipse.lsp4j.TextDocumentClientCapabilities; +import org.eclipse.lsp4j.WorkspaceFolder; +import org.eclipse.lsp4j.launch.LSPLauncher; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; + +@Slf4j +public class LanguageClientBinding { + + public static LanguageClientBinding INSTANCE = new LanguageClientBinding(); + + { +// INSTANCE.start(); + } + + private Process process; + + @Getter + private BSLLanguageServerInterface server; + + public void start() { + createProcess(); + connectToProcess(); + } + + public void stop() { + if (server != null) { + server.shutdown(); + server.exit(); + } + clear(); + } + + public void restart() { + stop(); + start(); + } + + public boolean isLaunched() { + return process != null && process.isAlive(); + } + + @SneakyThrows + private void createProcess() { + var pathToWorkspace = getPathToWorkspace(); + var pathToLSP = getPathToBSLLS(); + + List arguments = new ArrayList<>(); + arguments.add("java"); + arguments.add("-jar"); + arguments.add("\"" + pathToLSP + "\""); + + try { + process = new ProcessBuilder() + .command(arguments) + .directory(pathToWorkspace.toFile()) + .start(); + + Thread.sleep(500); + + if (!process.isAlive()) { + LOGGER.warn("Не удалось запустить процесс с BSL LS. Процесс был аварийно завершен."); + } + } catch (IOException e) { + LOGGER.error("Не удалось запустить процесс BSL LS", e); + } + } + + @NotNull + private static Path getPathToWorkspace() { + return Paths.get(".").toAbsolutePath(); + } + + @SneakyThrows + private void connectToProcess() { + if (process == null) { + return; + } + + var launcher = new LSPLauncher.Builder() + .setLocalService(new SonarLanguageClient()) + .setRemoteInterface(BSLLanguageServerInterface.class) + .setInput(process.getInputStream()) + .setOutput(process.getOutputStream()) + .create(); + + server = launcher.getRemoteProxy(); + + Executors.newCachedThreadPool().execute(() -> { + var future = launcher.startListening(); + while (true) { + try { + future.get(); + break; + } catch (InterruptedException e) { + LOGGER.error(e.getMessage(), e); + Thread.currentThread().interrupt(); + } catch (ExecutionException e) { + LOGGER.error(e.getMessage(), e); + } + } + } + ); + + Thread.sleep(2000); + + var params = new InitializeParams(); + + params.setProcessId((int) ProcessHandle.current().pid()); + + var workspaceFolder = new WorkspaceFolder(getPathToWorkspace().toUri().toString()); + params.setWorkspaceFolders(List.of(workspaceFolder)); + + var clientCapabilities = new ClientCapabilities(); + + var textDocument = new TextDocumentClientCapabilities(); + clientCapabilities.setTextDocument(textDocument); + + params.setCapabilities(clientCapabilities); + + var initializeResult = server.initialize(params).get(); + + LOGGER.info("BSL LS version: {}", initializeResult.getServerInfo().getVersion()); + } + + private void clear() { + process = null; + server = null; + } + + private static Path getPathToBSLLS() { + return Path.of( + "d:", + "git", + "1c-syntax", + "bsl-language-server", + "build", + "libs", + "bsl-language-server-develop-004e007-DIRTY-exec.jar" + ); + } + +} diff --git a/src/main/java/com/github/_1c_syntax/bsl/sonar/LanguageServerDiagnosticsLoaderSensor.java b/src/main/java/com/github/_1c_syntax/bsl/sonar/LanguageServerDiagnosticsLoaderSensor.java index f88960ec..3a13c590 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/sonar/LanguageServerDiagnosticsLoaderSensor.java +++ b/src/main/java/com/github/_1c_syntax/bsl/sonar/LanguageServerDiagnosticsLoaderSensor.java @@ -22,8 +22,11 @@ package com.github._1c_syntax.bsl.sonar; import com.fasterxml.jackson.databind.ObjectMapper; +// TODO: в модуль api import com.github._1c_syntax.bsl.languageserver.reporters.data.AnalysisInfo; +// TODO: в модуль api import com.github._1c_syntax.bsl.languageserver.reporters.data.FileInfo; +// TODO: в модуль api import com.github._1c_syntax.bsl.languageserver.reporters.databind.AnalysisInfoObjectMapper; import com.github._1c_syntax.bsl.sonar.language.BSLLanguage; import org.apache.commons.io.FileUtils; diff --git a/src/main/java/com/github/_1c_syntax/bsl/sonar/SonarLanguageClient.java b/src/main/java/com/github/_1c_syntax/bsl/sonar/SonarLanguageClient.java new file mode 100644 index 00000000..c3d58fce --- /dev/null +++ b/src/main/java/com/github/_1c_syntax/bsl/sonar/SonarLanguageClient.java @@ -0,0 +1,80 @@ +/* + * This file is a part of SonarQube 1C (BSL) Community Plugin. + * + * Copyright (c) 2018-2022 + * Alexey Sosnoviy , Nikita Fedkin + * + * SPDX-License-Identifier: LGPL-3.0-or-later + * + * SonarQube 1C (BSL) Community Plugin is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * SonarQube 1C (BSL) Community Plugin is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SonarQube 1C (BSL) Community Plugin. + */ +package com.github._1c_syntax.bsl.sonar; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.lsp4j.MessageActionItem; +import org.eclipse.lsp4j.MessageParams; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.ShowMessageRequestParams; +import org.eclipse.lsp4j.services.LanguageClient; + +import java.util.concurrent.CompletableFuture; + +@Slf4j +public class SonarLanguageClient implements LanguageClient { + + @Override + public void telemetryEvent(Object object) { + LOGGER.debug("Telemetry event: {}", object); + } + + @Override + public void publishDiagnostics(PublishDiagnosticsParams diagnostics) { + // no-op + } + + @Override + public void showMessage(MessageParams messageParams) { + logIncomingMessage(messageParams); + } + + @Override + public CompletableFuture showMessageRequest(ShowMessageRequestParams requestParams) { + LOGGER.info("Incoming message: {}", requestParams); + return CompletableFuture.completedFuture(null); + } + + @Override + public void logMessage(MessageParams message) { + logIncomingMessage(message); + } + + private void logIncomingMessage(MessageParams message) { + var messageType = message.getType(); + + switch (messageType) { + case Error: + LOGGER.error(message.getMessage()); + break; + case Warning: + LOGGER.warn(message.getMessage()); + break; + case Info: + LOGGER.info(message.getMessage()); + break; + case Log: + LOGGER.debug(message.getMessage()); + break; + } + } +} diff --git a/src/test/java/com/github/_1c_syntax/bsl/sonar/BSLPluginTest.java b/src/test/java/com/github/_1c_syntax/bsl/sonar/BSLPluginTest.java index 22ca386d..52108bfd 100644 --- a/src/test/java/com/github/_1c_syntax/bsl/sonar/BSLPluginTest.java +++ b/src/test/java/com/github/_1c_syntax/bsl/sonar/BSLPluginTest.java @@ -47,6 +47,9 @@ class BSLPluginTest { @Test void testGetExtensions() { + + LanguageClientBinding.INSTANCE.start(); + var runtime = SonarRuntimeImpl.forSonarQube(VERSION_8_9, SonarQubeSide.SCANNER, SonarEdition.COMMUNITY); var context = new Plugin.Context(runtime); bslPlugin.define(context);