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

[WIP] Подключение сонар-плагина к bsl ls по LSP #222

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions lombok.config
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
lombok.anyConstructor.addConstructorProperties=true
lombok.addLombokGeneratedAnnotation=true
lombok.log.fieldname=LOGGER
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* This file is a part of SonarQube 1C (BSL) Community Plugin.
*
* Copyright (c) 2018-2022
* Alexey Sosnoviy <[email protected]>, Nikita Fedkin <[email protected]>
*
* 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> diagnostics(DiagnosticParams params);

}
10 changes: 7 additions & 3 deletions src/main/java/com/github/_1c_syntax/bsl/sonar/IssuesLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -153,7 +153,7 @@ private Map<String, LoaderSettings> 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) {
Expand Down Expand Up @@ -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()));
Expand All @@ -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<String, Integer> diagnosticCode) {
return diagnosticCode.isLeft() ? diagnosticCode.getLeft() : Integer.toString(diagnosticCode.getRight());
}

@Value
@AllArgsConstructor
private static class LoaderSettings {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
* This file is a part of SonarQube 1C (BSL) Community Plugin.
*
* Copyright (c) 2018-2022
* Alexey Sosnoviy <[email protected]>, Nikita Fedkin <[email protected]>
*
* 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<String> 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<BSLLanguageServerInterface>()
.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"
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* This file is a part of SonarQube 1C (BSL) Community Plugin.
*
* Copyright (c) 2018-2022
* Alexey Sosnoviy <[email protected]>, Nikita Fedkin <[email protected]>
*
* 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<MessageActionItem> 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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down