initialize(InitializeParams params) {
capabilities.setDocumentLinkProvider(new DocumentLinkOptions());
capabilities.setWorkspaceSymbolProvider(Boolean.TRUE);
- InitializeResult result = new InitializeResult(capabilities);
+ InitializeResult result = new InitializeResult(capabilities, serverInfo);
return CompletableFuture.completedFuture(result);
}
@@ -118,12 +121,8 @@ public void exit() {
*
* См. {@link BSLTextDocumentService#diagnostics(DiagnosticParams)}
*/
-// @JsonRequest(
-// value = "textDocument/x-diagnostics",
-// useSegment = false
-// )
@Override
- public CompletableFuture> diagnostics(DiagnosticParams params) {
+ public CompletableFuture diagnostics(DiagnosticParams params) {
return textDocumentService.diagnostics(params);
}
@@ -137,4 +136,19 @@ public WorkspaceService getWorkspaceService() {
return workspaceService;
}
+ private static TextDocumentSyncOptions getTextDocumentSyncOptions() {
+ TextDocumentSyncOptions textDocumentSync = new TextDocumentSyncOptions();
+
+ textDocumentSync.setOpenClose(Boolean.TRUE);
+ textDocumentSync.setChange(TextDocumentSyncKind.Full);
+ textDocumentSync.setWillSave(Boolean.FALSE);
+ textDocumentSync.setWillSaveWaitUntil(Boolean.FALSE);
+
+ SaveOptions save = new SaveOptions();
+ save.setIncludeText(Boolean.FALSE);
+
+ textDocumentSync.setSave(save);
+
+ return textDocumentSync;
+ }
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
index be547ba0fa7..2e8811610eb 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
@@ -26,6 +26,7 @@
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
import com.github._1c_syntax.bsl.languageserver.context.ServerContext;
import com.github._1c_syntax.bsl.languageserver.jsonrpc.DiagnosticParams;
+import com.github._1c_syntax.bsl.languageserver.jsonrpc.Diagnostics;
import com.github._1c_syntax.bsl.languageserver.jsonrpc.ProtocolExtension;
import com.github._1c_syntax.bsl.languageserver.providers.CodeActionProvider;
import com.github._1c_syntax.bsl.languageserver.providers.CodeLensProvider;
@@ -46,7 +47,6 @@
import org.eclipse.lsp4j.CompletionList;
import org.eclipse.lsp4j.CompletionParams;
import org.eclipse.lsp4j.DefinitionParams;
-import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
import org.eclipse.lsp4j.DidCloseTextDocumentParams;
import org.eclipse.lsp4j.DidOpenTextDocumentParams;
@@ -74,14 +74,10 @@
import org.eclipse.lsp4j.TextEdit;
import org.eclipse.lsp4j.WorkspaceEdit;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
-import org.eclipse.lsp4j.services.LanguageClient;
-import org.eclipse.lsp4j.services.LanguageClientAware;
import org.eclipse.lsp4j.services.TextDocumentService;
import org.springframework.stereotype.Component;
-import javax.annotation.CheckForNull;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@@ -89,7 +85,7 @@
@Component
@RequiredArgsConstructor
-public class BSLTextDocumentService implements TextDocumentService, LanguageClientAware, ProtocolExtension {
+public class BSLTextDocumentService implements TextDocumentService, ProtocolExtension {
private final ServerContext context;
private final LanguageServerConfiguration configuration;
@@ -102,9 +98,6 @@ public class BSLTextDocumentService implements TextDocumentService, LanguageClie
private final FormatProvider formatProvider;
private final HoverProvider hoverProvider;
- @CheckForNull
- private LanguageClient client;
-
@Override
public CompletableFuture, CompletionList>> completion(CompletionParams position) {
List completionItems = new ArrayList<>();
@@ -245,7 +238,7 @@ public void didChange(DidChangeTextDocumentParams params) {
return;
}
- documentContext.rebuild(params.getContentChanges().get(0).getText());
+ documentContext.rebuild(params.getContentChanges().get(0).getText(), params.getTextDocument().getVersion());
if (configuration.getDiagnosticsOptions().getComputeTrigger() == ComputeTrigger.ONTYPE) {
validate(documentContext);
@@ -261,9 +254,7 @@ public void didClose(DidCloseTextDocumentParams params) {
documentContext.clearSecondaryData();
- if (client != null) {
- diagnosticProvider.publishEmptyDiagnosticList(client, documentContext);
- }
+ diagnosticProvider.publishEmptyDiagnosticList(documentContext);
}
@Override
@@ -278,11 +269,6 @@ public void didSave(DidSaveTextDocumentParams params) {
}
}
- @Override
- public void connect(LanguageClient client) {
- this.client = client;
- }
-
@Override
public CompletableFuture> documentLink(DocumentLinkParams params) {
DocumentContext documentContext = context.getDocument(params.getTextDocument().getUri());
@@ -294,10 +280,10 @@ public CompletableFuture> documentLink(DocumentLinkParams par
}
@Override
- public CompletableFuture> diagnostics(DiagnosticParams params) {
+ public CompletableFuture diagnostics(DiagnosticParams params) {
DocumentContext documentContext = context.getDocument(params.getTextDocument().getUri());
if (documentContext == null) {
- return CompletableFuture.completedFuture(Collections.emptyList());
+ return CompletableFuture.completedFuture(Diagnostics.EMPTY);
}
return CompletableFuture.supplyAsync(() -> {
@@ -309,7 +295,7 @@ public CompletableFuture> diagnostics(DiagnosticParams params)
.filter(diagnostic -> Ranges.containsRange(range, diagnostic.getRange()))
.collect(Collectors.toList());
}
- return diagnostics;
+ return new Diagnostics(diagnostics, documentContext.getVersion());
});
}
@@ -318,10 +304,7 @@ public void reset() {
}
private void validate(DocumentContext documentContext) {
- if (client == null) {
- return;
- }
- diagnosticProvider.computeAndPublishDiagnostics(client, documentContext);
+ diagnosticProvider.computeAndPublishDiagnostics(documentContext);
}
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/AnalyzeCommand.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/AnalyzeCommand.java
index 363eb83e996..b64303f8273 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/AnalyzeCommand.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/AnalyzeCommand.java
@@ -33,6 +33,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.tongfei.progressbar.ProgressBar;
+import me.tongfei.progressbar.ProgressBarBuilder;
import me.tongfei.progressbar.ProgressBarStyle;
import org.apache.commons.io.FileUtils;
import org.eclipse.lsp4j.Diagnostic;
@@ -56,27 +57,27 @@
/**
* Выполнение анализа
* Ключ команды:
- * -a, (--analyze)
+ * -a, (--analyze)
* Параметры:
- * -s, (--srcDir) <arg> - Путь к каталогу исходных файлов.
- * Возможно указывать как в абсолютном, так и относительном виде. Если параметр опущен,
- * то анализ выполняется в текущем каталоге запуска.
- * -o, (--outputDir) <arg> - Путь к каталогу размещения отчетов - результатов анализа.
- * Возможно указывать как в абсолютном, так и относительном виде. Если параметр опущен,
- * то файлы отчета будут сохранены в текущем каталоге запуска.
- * -w, (--workspaceDir) <arg> - Путь к каталогу проекта, относительно которого располагаются исходные файлы.
- * Возможно указывать как в абсолютном, так и в относительном виде. Если параметр опущен,
- * то пути к исходным файлам будут указываться относительно текущего каталога запуска.
- * -c, (--configuration) <arg> - Путь к конфигурационному файлу BSL Language Server (.bsl-language-server.json).
- * Возможно указывать как в абсолютном, так и относительном виде. Если параметр опущен,
- * то будут использованы настройки по умолчанию.
- * -r, (--reporter) <arg> - Ключи "Репортеров", т.е. форматов отчетов, котрые необходимо сгенерировать после
- * выполнения анализа. Может быть указано более одного ключа. Если параметр опущен,
- * то вывод результата будет призведен в консоль.
- * -q, (--silent) - Флаг для отключения вывода прогресс-бара и дополнительных сообщений в консоль
+ * -s, (--srcDir) <arg> - Путь к каталогу исходных файлов.
+ * Возможно указывать как в абсолютном, так и относительном виде. Если параметр опущен,
+ * то анализ выполняется в текущем каталоге запуска.
+ * -o, (--outputDir) <arg> - Путь к каталогу размещения отчетов - результатов анализа.
+ * Возможно указывать как в абсолютном, так и относительном виде. Если параметр опущен,
+ * то файлы отчета будут сохранены в текущем каталоге запуска.
+ * -w, (--workspaceDir) <arg> - Путь к каталогу проекта, относительно которого располагаются исходные файлы.
+ * Возможно указывать как в абсолютном, так и в относительном виде. Если параметр опущен,
+ * то пути к исходным файлам будут указываться относительно текущего каталога запуска.
+ * -c, (--configuration) <arg> - Путь к конфигурационному файлу BSL Language Server (.bsl-language-server.json).
+ * Возможно указывать как в абсолютном, так и относительном виде. Если параметр опущен,
+ * то будут использованы настройки по умолчанию.
+ * -r, (--reporter) <arg> - Ключи "Репортеров", т.е. форматов отчетов, котрые необходимо сгенерировать после
+ * выполнения анализа. Может быть указано более одного ключа. Если параметр опущен,
+ * то вывод результата будет призведен в консоль.
+ * -q, (--silent) - Флаг для отключения вывода прогресс-бара и дополнительных сообщений в консоль
* Выводимая информация:
- * Выполняет анализ каталога исходных файлов и генерацию файлов отчета. Для каждого указанного ключа "Репортера"
- * создается отдельный файл (каталог файлов). Реализованные "репортеры" находятся в пакете "reporter".
+ * Выполняет анализ каталога исходных файлов и генерацию файлов отчета. Для каждого указанного ключа "Репортера"
+ * создается отдельный файл (каталог файлов). Реализованные "репортеры" находятся в пакете "reporter".
**/
@Slf4j
@Command(
@@ -172,7 +173,7 @@ public Integer call() {
context.setConfigurationRoot(configurationPath);
Collection files = FileUtils.listFiles(srcDir.toFile(), new String[]{"bsl", "os"}, true);
-
+
context.populateContext(files);
List fileInfos;
@@ -181,7 +182,11 @@ public Integer call() {
.map((File file) -> getFileInfoFromFile(workspaceDir, file))
.collect(Collectors.toList());
} else {
- try (ProgressBar pb = new ProgressBar("Analyzing files...", files.size(), ProgressBarStyle.ASCII)) {
+ try (ProgressBar pb = new ProgressBarBuilder()
+ .setTaskName("Analyzing files...")
+ .setInitialMax(files.size())
+ .setStyle(ProgressBarStyle.ASCII)
+ .build()) {
fileInfos = files.parallelStream()
.map((File file) -> {
pb.step();
@@ -209,7 +214,7 @@ private FileInfo getFileInfoFromFile(Path srcDir, File file) {
throw new RuntimeException(e);
}
- DocumentContext documentContext = context.addDocument(file.toURI(), textDocumentContent);
+ DocumentContext documentContext = context.addDocument(file.toURI(), textDocumentContent, 1);
Path filePath = srcDir.relativize(Absolute.path(file));
List diagnostics = documentContext.getDiagnostics();
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/FormatCommand.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/FormatCommand.java
index b97d90c1cd0..01aabc8e000 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/FormatCommand.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/FormatCommand.java
@@ -29,6 +29,7 @@
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import me.tongfei.progressbar.ProgressBar;
+import me.tongfei.progressbar.ProgressBarBuilder;
import me.tongfei.progressbar.ProgressBarStyle;
import org.apache.commons.io.FileUtils;
import org.eclipse.lsp4j.DocumentFormattingParams;
@@ -41,6 +42,7 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
@@ -52,9 +54,11 @@
* Ключ команды:
* -f, (--format)
* Параметры:
- * -s, (--srcDir) <arg> - Путь к каталогу исходных файлов.
+ * -s, (--src) - Путь к каталогу исходных файлов.
* Возможно указывать как в абсолютном, так и относительном виде. Если параметр опущен,
* то анализ выполняется в текущем каталоге запуска.
+ * Можно указать каталог, в котором будут найдены файлы для форматирования, либо один
+ * файл для форматирования
* -q, (--silent) - Флаг для отключения вывода прогресс-бара и дополнительных сообщений в консоль
* Выводимая информация:
* Выполняет форматирование исходного кода в файлах каталога. Для форматирования используются правила и настройки
@@ -81,8 +85,8 @@ public class FormatCommand implements Callable {
private boolean usageHelpRequested;
@Option(
- names = {"-s", "--srcDir"},
- description = "Source directory",
+ names = {"-s", "--srcDir", "--src"}, // TODO delete old key --srcDir
+ description = "Source directory or file",
paramLabel = "",
defaultValue = "")
private String srcDirOption;
@@ -107,12 +111,22 @@ public Integer call() {
return 1;
}
- Collection files = FileUtils.listFiles(srcDir.toFile(), new String[]{"bsl", "os"}, true);
+ Collection files;
+
+ if(srcDir.toFile().isDirectory()) {
+ files = FileUtils.listFiles(srcDir.toFile(), new String[]{"bsl", "os"}, true);
+ } else {
+ files = Collections.singletonList(srcDir.toFile());
+ }
if (silentMode) {
files.parallelStream().forEach(this::formatFile);
} else {
- try (ProgressBar pb = new ProgressBar("Formatting files...", files.size(), ProgressBarStyle.ASCII)) {
+ try (ProgressBar pb = new ProgressBarBuilder()
+ .setTaskName("Formatting files...")
+ .setInitialMax(files.size())
+ .setStyle(ProgressBarStyle.ASCII)
+ .build()) {
files.parallelStream()
.forEach((File file) -> {
pb.step();
@@ -129,7 +143,7 @@ private void formatFile(File file) {
String textDocumentContent = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
final URI uri = file.toURI();
- DocumentContext documentContext = serverContext.addDocument(uri, textDocumentContent);
+ DocumentContext documentContext = serverContext.addDocument(uri, textDocumentContent, 1);
DocumentFormattingParams params = new DocumentFormattingParams();
FormattingOptions options = new FormattingOptions();
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/VersionCommand.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/VersionCommand.java
index a6bd70f2a0b..98c36cb2ce3 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/VersionCommand.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/VersionCommand.java
@@ -21,16 +21,14 @@
*/
package com.github._1c_syntax.bsl.languageserver.cli;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.eclipse.lsp4j.ServerInfo;
import org.springframework.stereotype.Component;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
-import java.io.IOException;
-import java.io.InputStream;
import java.util.concurrent.Callable;
-import java.util.jar.Attributes;
-import java.util.jar.Manifest;
/**
* Выводит версию приложения
@@ -45,6 +43,7 @@
usageHelpAutoWidth = true,
footer = "@|green Copyright(c) 2018-2020|@")
@Component
+@RequiredArgsConstructor
public class VersionCommand implements Callable {
@Option(names = "--spring.config.location", hidden = true)
@@ -53,24 +52,18 @@ public class VersionCommand implements Callable {
@Option(names = "--debug", hidden = true)
private boolean debug;
- public Integer call() {
- final InputStream mfStream = Thread.currentThread()
- .getContextClassLoader()
- .getResourceAsStream("META-INF/MANIFEST.MF");
+ private final ServerInfo serverInfo;
- Manifest manifest = new Manifest();
- try {
- manifest.read(mfStream);
- } catch (IOException e) {
- LOGGER.error("Can't read manifest", e);
+ public Integer call() {
+ String version = serverInfo.getVersion();
+ if (version.isEmpty()) {
return 1;
}
- System.out.print(
- String.format(
- "version: %s%n",
- manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION)
- ));
+ System.out.printf(
+ "version: %s%n",
+ version
+ );
return 0;
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/package-info.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/package-info.java
index dbf7852daa6..3ac9c7811cf 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/package-info.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/package-info.java
@@ -19,7 +19,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with BSL Language Server.
*/
-
/**
* Пакет предназначен для реализации CLI функциональности BSL Language Server.
* Каждый класс пакета реализовывает интерфейс Command (и одноименный суффикс имени) и имеет javadoc-описание своих
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codeactions/AbstractQuickFixSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codeactions/AbstractQuickFixSupplier.java
index 033659b8e8b..1eb26e7b2c5 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codeactions/AbstractQuickFixSupplier.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codeactions/AbstractQuickFixSupplier.java
@@ -23,13 +23,17 @@
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
import lombok.RequiredArgsConstructor;
+import lombok.Value;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.CodeActionKind;
import org.eclipse.lsp4j.CodeActionParams;
import org.eclipse.lsp4j.Diagnostic;
+import org.eclipse.lsp4j.Range;
+import org.eclipse.lsp4j.jsonrpc.messages.Either;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -50,10 +54,13 @@ public List getCodeActions(CodeActionParams params, DocumentContext
return Collections.emptyList();
}
- List computedDiagnostics = documentContext.getComputedDiagnostics();
+ Set computedDiagnostics = documentContext.getComputedDiagnostics()
+ .stream()
+ .map(LightDiagnostic::new)
+ .collect(Collectors.toSet());
Stream diagnosticStream = incomingDiagnostics.stream()
- .filter(computedDiagnostics::contains);
+ .filter(diagnostic -> computedDiagnostics.contains(new LightDiagnostic(diagnostic)));
return processDiagnosticStream(diagnosticStream, params, documentContext)
.collect(Collectors.toList());
@@ -65,4 +72,17 @@ protected abstract Stream processDiagnosticStream(
CodeActionParams params,
DocumentContext documentContext
);
+
+ @Value
+ private static class LightDiagnostic {
+ Either code;
+ Range range;
+ String source;
+
+ public LightDiagnostic(Diagnostic diagnostic) {
+ this.code = diagnostic.getCode();
+ this.range = diagnostic.getRange();
+ this.source = diagnostic.getSource();
+ }
+ }
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codeactions/DisableDiagnosticTriggeringSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codeactions/DisableDiagnosticTriggeringSupplier.java
new file mode 100644
index 00000000000..7caa1a49cf7
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codeactions/DisableDiagnosticTriggeringSupplier.java
@@ -0,0 +1,238 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.codeactions;
+
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticCode;
+import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
+import com.github._1c_syntax.bsl.languageserver.utils.Resources;
+import org.antlr.v4.runtime.Token;
+import org.eclipse.lsp4j.CodeAction;
+import org.eclipse.lsp4j.CodeActionKind;
+import org.eclipse.lsp4j.CodeActionParams;
+import org.eclipse.lsp4j.Diagnostic;
+import org.eclipse.lsp4j.Range;
+import org.eclipse.lsp4j.TextEdit;
+import org.eclipse.lsp4j.WorkspaceEdit;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+
+@Component
+public class DisableDiagnosticTriggeringSupplier implements CodeActionSupplier {
+
+ private static final String ALL_DIAGNOSTIC_NAME = "";
+ private final LanguageServerConfiguration languageServerConfiguration;
+
+ public DisableDiagnosticTriggeringSupplier(LanguageServerConfiguration languageServerConfiguration) {
+ this.languageServerConfiguration = languageServerConfiguration;
+ }
+
+ /**
+ * При необходимости создает {@code CodeAction} для создания служебного комментария отключающего срабатывание
+ * диагностики.
+ * Может быть в трех вариантах:
+ * 1. Отключаются срабатывания в конкретной строке
+ * 2. Отключаются срабатывания в области между парой комментариев
+ * 3. Отключаются срабатывания во всем файле
+ *
+ * @param params параметры вызова генерации {@code codeAction}
+ * @param documentContext представление программного модуля
+ * @return {@code List} если модуль не содержит всех стандартных областей,
+ * пустой {@code List} если генерация областей не требуется
+ */
+ @Override
+ public List getCodeActions(CodeActionParams params, DocumentContext documentContext) {
+ List result = new ArrayList<>();
+
+ if (!params.getContext().getDiagnostics().isEmpty()) {
+ if (params.getRange().getStart() != null && params.getRange().getEnd() != null) {
+ var selectedLineNumber = params.getRange().getEnd().getLine() + 1;
+
+ documentContext
+ .getTokens()
+ .stream()
+ .filter(token -> token.getLine() == selectedLineNumber)
+ .max(Comparator.comparingInt(Token::getCharPositionInLine))
+ .ifPresent(token -> {
+ if (params.getRange().getStart().getLine() == params.getRange().getEnd().getLine()) {
+ result.addAll(getDisableActionForLine(params, documentContext, token));
+ } else {
+ result.addAll(getDisableActionForRange(params, documentContext, token));
+ }
+ }
+ );
+ }
+
+ result.addAll(
+ actionDisableDiagnostic(
+ name -> createCodeAction(
+ getMessage("file", name),
+ createInFileTextEdits(":" + name),
+ documentContext
+ ),
+ params
+ )
+ );
+ }
+
+ result.add(
+ createCodeAction(
+ getMessage("fileAll"),
+ createInFileTextEdits(ALL_DIAGNOSTIC_NAME),
+ documentContext
+ )
+ );
+ return new ArrayList<>(result);
+ }
+
+ private List getDisableActionForLine(
+ CodeActionParams params,
+ DocumentContext documentContext,
+ Token lastToken
+ ) {
+ var result = actionDisableDiagnostic(
+ name -> createCodeAction(
+ getMessage("line", name),
+ createInLineTextEdits(":" + name, lastToken, params),
+ documentContext
+ ),
+ params
+ );
+ result.add(
+ createCodeAction(
+ getMessage("lineAll"),
+ createInLineTextEdits(ALL_DIAGNOSTIC_NAME, lastToken, params),
+ documentContext
+ )
+ );
+ return result;
+ }
+
+ private List getDisableActionForRange(
+ CodeActionParams params,
+ DocumentContext documentContext,
+ Token lastToken
+ ) {
+ var result = actionDisableDiagnostic(
+ name -> createCodeAction(
+ getMessage("range", name),
+ createInRegionTextEdits(":" + name, lastToken, params),
+ documentContext
+ ),
+ params
+ );
+ result.add(
+ createCodeAction(
+ getMessage("rangeAll"),
+ createInRegionTextEdits(ALL_DIAGNOSTIC_NAME, lastToken, params),
+ documentContext
+ )
+ );
+ return result;
+ }
+
+ private List actionDisableDiagnostic(Function func, CodeActionParams params) {
+ return params.getContext()
+ .getDiagnostics()
+ .stream()
+ .map(Diagnostic::getCode)
+ .map(DiagnosticCode::getStringValue)
+ .distinct()
+ .map(func)
+ .collect(Collectors.toList());
+ }
+
+ private List createInRegionTextEdits(String diagnosticName, Token last, CodeActionParams params) {
+ List edits = new ArrayList<>();
+
+ Range disableRange = Ranges.create(
+ params.getRange().getStart().getLine(),
+ 0,
+ params.getRange().getStart().getLine(),
+ 0
+ );
+ TextEdit disableTextEdit = new TextEdit(disableRange, String.format("// BSLLS%s-off%n", diagnosticName));
+ edits.add(disableTextEdit);
+
+ Range enableRange = Ranges.create(
+ params.getRange().getEnd().getLine(),
+ last.getCharPositionInLine() + last.getText().length(),
+ params.getRange().getEnd().getLine(),
+ last.getCharPositionInLine() + last.getText().length()
+ );
+ TextEdit enableTextEdit = new TextEdit(enableRange, String.format("%n// BSLLS%s-on%n", diagnosticName));
+ edits.add(enableTextEdit);
+ return edits;
+ }
+
+ private List createInFileTextEdits(String diagnosticName) {
+ TextEdit textEdit = new TextEdit(
+ Ranges.create(0, 0, 0, 0),
+ String.format("// BSLLS%s-off%n", diagnosticName)
+ );
+ return Collections.singletonList(textEdit);
+ }
+
+ @NotNull
+ private CodeAction createCodeAction(String title, List edits, DocumentContext documentContext) {
+ Map> changes = Map.of(documentContext.getUri().toString(), edits);
+ WorkspaceEdit edit = new WorkspaceEdit();
+ edit.setChanges(changes);
+
+ CodeAction codeAction = new CodeAction(title);
+ codeAction.setDiagnostics(new ArrayList<>());
+ codeAction.setKind(CodeActionKind.Refactor);
+ codeAction.setEdit(edit);
+ return codeAction;
+ }
+
+ private String getMessage(String key) {
+ return Resources.getResourceString(languageServerConfiguration.getLanguage(), this.getClass(), key);
+ }
+
+ private String getMessage(String key, Object... args) {
+ return Resources.getResourceString(languageServerConfiguration.getLanguage(), this.getClass(), key, args);
+ }
+
+ private static List createInLineTextEdits(String diagnosticName, Token last, CodeActionParams params) {
+ Range range = Ranges.create(
+ params.getRange().getStart().getLine(),
+ last.getCharPositionInLine() + last.getText().length(),
+ params.getRange().getStart().getLine(),
+ last.getCharPositionInLine() + last.getText().length()
+ );
+
+ TextEdit textEdit = new TextEdit(range, String.format(" // BSLLS%s-off", diagnosticName));
+ return Collections.singletonList(textEdit);
+ }
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CodeLensSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CodeLensSupplier.java
new file mode 100644
index 00000000000..019257848ce
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CodeLensSupplier.java
@@ -0,0 +1,31 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.codelenses;
+
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import org.eclipse.lsp4j.CodeLens;
+
+import java.util.List;
+
+public interface CodeLensSupplier {
+ List getCodeLenses(DocumentContext documentContext);
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CognitiveComplexityCodeLensSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CognitiveComplexityCodeLensSupplier.java
new file mode 100644
index 00000000000..75ec763a0cd
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CognitiveComplexityCodeLensSupplier.java
@@ -0,0 +1,69 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.codelenses;
+
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
+import lombok.RequiredArgsConstructor;
+import org.eclipse.lsp4j.CodeLens;
+import org.eclipse.lsp4j.Command;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+@Component
+@RequiredArgsConstructor
+public class CognitiveComplexityCodeLensSupplier implements CodeLensSupplier {
+
+ private final LanguageServerConfiguration configuration;
+
+ @Override
+ public List getCodeLenses(DocumentContext documentContext) {
+
+ if (!configuration.getCodeLensOptions().isShowCognitiveComplexity()) {
+ return Collections.emptyList();
+ }
+
+ Map methodsComplexity = documentContext.getCognitiveComplexityData()
+ .getMethodsComplexity();
+
+ List codeLenses = new ArrayList<>(methodsComplexity.size());
+
+ methodsComplexity.forEach((MethodSymbol methodSymbol, Integer complexity) -> {
+ String title = String.format("Cognitive complexity is %d", complexity);
+ Command command = new Command(title, "");
+ CodeLens codeLens = new CodeLens(
+ methodSymbol.getSubNameRange(),
+ command,
+ null
+ );
+
+ codeLenses.add(codeLens);
+ });
+
+ return codeLenses;
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CyclomaticComplexityCodeLensSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CyclomaticComplexityCodeLensSupplier.java
new file mode 100644
index 00000000000..23610668064
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CyclomaticComplexityCodeLensSupplier.java
@@ -0,0 +1,69 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.codelenses;
+
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
+import lombok.RequiredArgsConstructor;
+import org.eclipse.lsp4j.CodeLens;
+import org.eclipse.lsp4j.Command;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+@Component
+@RequiredArgsConstructor
+public class CyclomaticComplexityCodeLensSupplier implements CodeLensSupplier {
+
+ private final LanguageServerConfiguration configuration;
+
+ @Override
+ public List getCodeLenses(DocumentContext documentContext) {
+
+ if (!configuration.getCodeLensOptions().isShowCyclomaticComplexity()) {
+ return Collections.emptyList();
+ }
+
+ Map methodsComplexity = documentContext.getCyclomaticComplexityData()
+ .getMethodsComplexity();
+
+ List codeLenses = new ArrayList<>(methodsComplexity.size());
+
+ methodsComplexity.forEach((MethodSymbol methodSymbol, Integer complexity) -> {
+ String title = String.format("Cyclomatic complexity is %d", complexity);
+ Command command = new Command(title, "");
+ CodeLens codeLens = new CodeLens(
+ methodSymbol.getSubNameRange(),
+ command,
+ null
+ );
+
+ codeLenses.add(codeLens);
+ });
+
+ return codeLenses;
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/package-info.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/package-info.java
new file mode 100644
index 00000000000..580ff867ae5
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+@ParametersAreNonnullByDefault
+package com.github._1c_syntax.bsl.languageserver.codelenses;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/codelens/package-info.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/codelens/package-info.java
index 8648ddebe11..6e2d789b2d2 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/codelens/package-info.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/codelens/package-info.java
@@ -19,7 +19,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with BSL Language Server.
*/
-
/**
* Пакет содержит настройки {@link com.github._1c_syntax.bsl.languageserver.providers.CodeLensProvider}
*/
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/diagnostics/DiagnosticsOptions.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/diagnostics/DiagnosticsOptions.java
index f53e3977293..991638c2238 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/diagnostics/DiagnosticsOptions.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/diagnostics/DiagnosticsOptions.java
@@ -23,6 +23,7 @@
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.github._1c_syntax.bsl.languageserver.configuration.diagnostics.databind.ParametersDeserializer;
import lombok.AllArgsConstructor;
@@ -44,6 +45,7 @@ public class DiagnosticsOptions {
private ComputeTrigger computeTrigger = ComputeTrigger.ONSAVE;
private SkipSupport skipSupport = SkipSupport.NEVER;
private Mode mode = Mode.ON;
+ private boolean ordinaryAppSupport = true;
@JsonDeserialize(using = ParametersDeserializer.class)
private Map>> parameters = new HashMap<>();
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/documentlink/package-info.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/documentlink/package-info.java
index 2c15f7357ea..125c0dc67ed 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/documentlink/package-info.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/documentlink/package-info.java
@@ -19,7 +19,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with BSL Language Server.
*/
-
/**
* Пакет содержит настройки {@link com.github._1c_syntax.bsl.languageserver.providers.DocumentLinkProvider}
*/
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/package-info.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/package-info.java
index f1f647eb85c..a4451c55cf2 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/package-info.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/package-info.java
@@ -19,7 +19,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with BSL Language Server.
*/
-
/**
* В пакете содержатся классы для конфигурирования BSL Language Server.
*
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/watcher/package-info.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/watcher/package-info.java
index 15ee0a330f2..e9da672b2ef 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/watcher/package-info.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/watcher/package-info.java
@@ -19,7 +19,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with BSL Language Server.
*/
-
/**
* В пакете содержатся классы, относящиеся к отслеживанию факта изменения (удаление, создание, редактирование) файла
* конфигурации ({@link com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration}).
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentContext.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentContext.java
index 866d5deda06..dc743af79bc 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentContext.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentContext.java
@@ -42,6 +42,7 @@
import com.github._1c_syntax.mdclasses.metadata.additional.ModuleType;
import com.github._1c_syntax.mdclasses.metadata.additional.SupportVariant;
import com.github._1c_syntax.utils.Lazy;
+import lombok.Getter;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.TerminalNodeImpl;
import org.antlr.v4.runtime.tree.Tree;
@@ -67,6 +68,8 @@ public class DocumentContext {
private final URI uri;
private String content;
+ @Getter
+ private int version;
private final ServerContext context;
private final DiagnosticComputer diagnosticComputer;
@@ -92,9 +95,16 @@ public class DocumentContext {
private final Lazy> queries = new Lazy<>(this::computeQueries, computeLock);
- public DocumentContext(URI uri, String content, ServerContext context, DiagnosticComputer diagnosticComputer) {
+ public DocumentContext(
+ URI uri,
+ String content,
+ ServerContext context,
+ int version,
+ DiagnosticComputer diagnosticComputer
+ ) {
this.uri = uri;
this.content = content;
+ this.version = version;
this.context = context;
this.diagnosticComputer = diagnosticComputer;
@@ -219,28 +229,46 @@ public List getComputedDiagnostics() {
.orElseGet(Collections::emptyList);
}
- public void rebuild(String content) {
+ public void rebuild(String content, int version) {
computeLock.lock();
+
+ boolean versionMatches = version == this.version && version != 0;
+ boolean contentWasCleared = this.content == null;
+
+ if (versionMatches && !contentWasCleared) {
+ clearDependantData();
+ computeLock.unlock();
+ return;
+ }
+
clearSecondaryData();
symbolTree.clear();
this.content = content;
tokenizer = new BSLTokenizer(content);
+ this.version = version;
computeLock.unlock();
}
public void clearSecondaryData() {
computeLock.lock();
- diagnosticsLock.lock();
content = null;
contentList.clear();
tokenizer = null;
-
cognitiveComplexityData.clear();
cyclomaticComplexityData.clear();
metrics.clear();
diagnosticIgnoranceData.clear();
- diagnostics.clear();
queries.clear();
+ clearDependantData();
+ computeLock.unlock();
+ }
+
+ private void clearDependantData() {
+ computeLock.lock();
+ diagnosticsLock.lock();
+
+ diagnostics.clear();
+
diagnosticsLock.unlock();
computeLock.unlock();
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
index 37eff00d9af..7f64234b03a 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
@@ -84,7 +84,7 @@ public void populateContext(Collection uris) {
uris.parallelStream().forEach((File file) -> {
DocumentContext documentContext = getDocument(file.toURI());
if (documentContext == null) {
- documentContext = createDocumentContext(file);
+ documentContext = createDocumentContext(file, 0);
documentContext.getSymbolTree();
documentContext.clearSecondaryData();
}
@@ -120,14 +120,14 @@ public Map getDocuments(String mdoRef) {
return documentsByMDORef.getOrDefault(mdoRef, Collections.emptyMap());
}
- public DocumentContext addDocument(URI uri, String content) {
+ public DocumentContext addDocument(URI uri, String content, int version) {
contextLock.readLock().lock();
DocumentContext documentContext = getDocument(uri);
if (documentContext == null) {
- documentContext = createDocumentContext(uri, content);
+ documentContext = createDocumentContext(uri, content, version);
} else {
- documentContext.rebuild(content);
+ documentContext.rebuild(content, version);
}
contextLock.readLock().unlock();
@@ -135,7 +135,11 @@ public DocumentContext addDocument(URI uri, String content) {
}
public DocumentContext addDocument(TextDocumentItem textDocumentItem) {
- return addDocument(URI.create(textDocumentItem.getUri()), textDocumentItem.getText());
+ return addDocument(
+ URI.create(textDocumentItem.getUri()),
+ textDocumentItem.getText(),
+ textDocumentItem.getVersion()
+ );
}
public void removeDocument(URI uri) {
@@ -156,18 +160,18 @@ public Configuration getConfiguration() {
}
@Lookup
- protected abstract DocumentContext lookupDocumentContext(URI absoluteURI, String content);
+ protected abstract DocumentContext lookupDocumentContext(URI absoluteURI, String content, int version);
@SneakyThrows
- private DocumentContext createDocumentContext(File file) {
+ private DocumentContext createDocumentContext(File file, int version) {
String content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
- return createDocumentContext(file.toURI(), content);
+ return createDocumentContext(file.toURI(), content, version);
}
- private DocumentContext createDocumentContext(URI uri, String content) {
+ private DocumentContext createDocumentContext(URI uri, String content, int version) {
URI absoluteURI = Absolute.uri(uri);
- DocumentContext documentContext = lookupDocumentContext(absoluteURI, content);
+ DocumentContext documentContext = lookupDocumentContext(absoluteURI, content, version);
documents.put(absoluteURI, documentContext);
addMdoRefByUri(absoluteURI, documentContext);
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/computer/MethodSymbolComputer.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/computer/MethodSymbolComputer.java
index ca7633db545..91be6b9aff0 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/computer/MethodSymbolComputer.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/computer/MethodSymbolComputer.java
@@ -40,6 +40,7 @@
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
+import org.eclipse.lsp4j.Range;
import javax.annotation.Nullable;
import java.util.ArrayList;
@@ -231,6 +232,7 @@ private static List createParameters(@Nullable BSLParser.Pa
.name(getParameterName(param.IDENTIFIER()))
.byValue(param.VAL_KEYWORD() != null)
.optional(param.defaultValue() != null)
+ .range(getParameterRange(param))
.build()
).collect(Collectors.toList());
}
@@ -241,6 +243,13 @@ private static String getParameterName(TerminalNode identifier) {
.orElse("");
}
+ private static Range getParameterRange(BSLParser.ParamContext param) {
+ if(param.IDENTIFIER() == null) {
+ return Ranges.create(param.start);
+ }
+ return Ranges.create(param.IDENTIFIER());
+ }
+
private static List getAnnotations(List extends BSLParser.AnnotationContext> annotationContext) {
return annotationContext.stream()
.map(MethodSymbolComputer::createAnnotation)
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/computer/QueryComputer.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/computer/QueryComputer.java
index 136de1ca6ab..604999d321f 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/computer/QueryComputer.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/computer/QueryComputer.java
@@ -40,12 +40,32 @@ public class QueryComputer extends BSLParserBaseVisitor implements Co
private final DocumentContext documentContext;
private final List queries = new ArrayList<>();
+ /**
+ * Ключевые слова для поиска потенциально запросных строк
+ */
private static final Pattern QUERIES_ROOT_KEY = CaseInsensitivePattern.compile(
- "select|выбрать|drop|уничтожить");
- private static final Pattern QUERIES_STARTING_QUOTE = CaseInsensitivePattern.compile("^\\s*\"");
+ "(?:[\\s\";]|^)(?:select|выбрать|drop|уничтожить)(?:\\s|$)");
+ private static final Pattern NON_QUERIES_START = CaseInsensitivePattern.compile(
+ "(?:^\\s*(?:(?:\\|)|(?:\"\")))");
+
+ /**
+ * Минимальная строка для анализа
+ */
private static final int MINIMAL_QUERY_STRING_LENGTH = 8;
+ /**
+ * Поиск сдвоенных кавычек
+ */
+ private static final Pattern QUOTE_LINE_PATTERN = CaseInsensitivePattern.compile(
+ "(?:\"{12}|\"{10}|\"{8}|\"{6}|\"{4}|\"{2})");
+
+ /**
+ * Поиск первой кавычки в строке
+ */
+ private static final Pattern FIRST_QUOTE_PATTERN = CaseInsensitivePattern.compile(
+ "^\\s*(\")");
+
public QueryComputer(DocumentContext documentContext) {
this.documentContext = documentContext;
}
@@ -74,18 +94,44 @@ public ParseTree visitString(BSLParser.StringContext ctx) {
boolean isQuery = false;
+ // конкатенация строк в одну
+ int prevTokenLine = -1;
+ String partString = "";
var strings = new StringJoiner("\n");
for (Token token : ctx.getTokens()) {
- var partString = getString(startLine, token);
+
+ // бывает несколько токенов строки в одной строе файла
+ // добавляем часть строки только в случае находления ее на другой строке файла
+ if (token.getLine() != prevTokenLine && prevTokenLine != -1) {
+ strings.add(partString);
+ partString = "";
+ }
+
+ // если новый токен строки находится на той же строке файла, что и предыдущий, то добавляем его к ней
+ if (token.getLine() == prevTokenLine && prevTokenLine != -1) {
+ String newString = getString(startLine, token);
+ partString = newString.substring(partString.length());
+ } else {
+ partString = getString(startLine, token);
+ }
+
+ // проверяем подстроку на вероятность запроса
if (!isQuery) {
- isQuery = QUERIES_ROOT_KEY.matcher(partString).find();
+ isQuery = QUERIES_ROOT_KEY.matcher(partString).find()
+ && !NON_QUERIES_START.matcher(partString).find();
}
- strings.add(partString);
+
startLine = token.getLine();
+ prevTokenLine = token.getLine();
+ }
+
+ // последнюю часть тоже необходимо добавить к общему тексту
+ if (!partString.isEmpty()) {
+ strings.add(partString);
}
if (isQuery) {
- queries.add(new SDBLTokenizer(startEmptyLines + removeExtremeQuotes(strings.toString())));
+ queries.add(new SDBLTokenizer(startEmptyLines + removeDoubleQuotes(strings.toString())));
}
return ctx;
@@ -95,13 +141,37 @@ public ParseTree visitString(BSLParser.StringContext ctx) {
private static String getString(int startLine, Token token) {
var string = addEmptyLines(startLine, token) + " ".repeat(token.getCharPositionInLine());
if (token.getText().startsWith("|")) {
- string += " " + token.getText().substring(1);
+ string += " " + trimLastQuote(token.getText().substring(1));
} else {
- string += token.getText();
+ string += trimQuotes(token.getText());
}
return string;
}
+ private static String trimLastQuote(String text) {
+ var quoteCount = text.length() - text.replace("\"", "").length();
+ if (quoteCount % 2 == 1) {
+ String newString;
+ var quotePosition = text.lastIndexOf("\"");
+ newString = text.substring(0, quotePosition) + " ";
+ if (quotePosition + 1 < text.length()) {
+ newString += text.substring(quotePosition + 1);
+ }
+ return newString;
+ }
+ return text;
+ }
+
+ private static String trimQuotes(String text) {
+ var matcher = FIRST_QUOTE_PATTERN.matcher(text);
+ if (matcher.find()) {
+ var newText = text.substring(0, matcher.start(1)) + " " + text.substring(matcher.end(1));
+ return trimLastQuote(newText);
+ }
+
+ return text;
+ }
+
private static String addEmptyLines(int startLine, Token token) {
if (token.getLine() > startLine + 1) {
return "\n".repeat(token.getLine() - startLine - 1);
@@ -109,13 +179,34 @@ private static String addEmptyLines(int startLine, Token token) {
return "";
}
- private static String removeExtremeQuotes(String text) {
- if (QUERIES_STARTING_QUOTE.matcher(text).find()) {
- // Кавычка может быть не первым символом строки
- var quoteIndex = text.indexOf("\"");
- return text.substring(0, quoteIndex) + " " + text.substring(quoteIndex + 1, text.length() - 1);
+ private static String removeDoubleQuotes(String text) {
+ var leftQuoteFound = false;
+ var matcher = QUOTE_LINE_PATTERN.matcher(text);
+ var newText = text;
+ var textLength = text.length();
+ var strings = new StringJoiner("");
+ while (matcher.find()) {
+ var quotesLineLength = matcher.group(0).length();
+ var emptyString = (" ".repeat(quotesLineLength / 2)).intern();
+ strings.add(newText.substring(0, matcher.start()) + (leftQuoteFound ? "" : emptyString)
+ + matcher.group(0).substring(0, quotesLineLength / 2) + (leftQuoteFound ? emptyString : ""));
+
+ if (matcher.end() < textLength) {
+ newText = newText.substring(matcher.end());
+ textLength = newText.length();
+ } else {
+ newText = "";
+ break;
+ }
+
+ matcher = QUOTE_LINE_PATTERN.matcher(newText);
+ leftQuoteFound = !leftQuoteFound;
}
- return text;
+ if (!newText.isEmpty()) {
+ strings.add(newText);
+ }
+
+ return strings.toString();
}
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/infrastructure/DocumentContextConfiguration.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/infrastructure/DocumentContextConfiguration.java
index 6ee824291b3..93b83409085 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/infrastructure/DocumentContextConfiguration.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/infrastructure/DocumentContextConfiguration.java
@@ -40,10 +40,10 @@ public class DocumentContextConfiguration {
@Bean
@Scope("prototype")
- public DocumentContext documentContext(URI uri, String content) {
+ public DocumentContext documentContext(URI uri, String content, int version) {
var serverContext = applicationContext.getBean(ServerContext.class);
var diagnosticComputer = applicationContext.getBean(DiagnosticComputer.class);
- return new DocumentContext(uri, content, serverContext, diagnosticComputer);
+ return new DocumentContext(uri, content, serverContext, version, diagnosticComputer);
}
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/MethodDescription.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/MethodDescription.java
index bbe9699b07c..c88d0177bbf 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/MethodDescription.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/MethodDescription.java
@@ -21,44 +21,90 @@
*/
package com.github._1c_syntax.bsl.languageserver.context.symbol;
-import com.github._1c_syntax.utils.CaseInsensitivePattern;
-import lombok.Getter;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.description.DescriptionReader;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.description.ParameterDescription;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.description.TypeDescription;
+import com.github._1c_syntax.bsl.parser.BSLMethodDescriptionParser;
+import com.github._1c_syntax.bsl.parser.BSLMethodDescriptionTokenizer;
+import lombok.Value;
import org.antlr.v4.runtime.Token;
import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import java.util.stream.Collectors;
-public class MethodDescription {
+import static java.util.Objects.requireNonNull;
- private static final int COMMENT_LENGTH = 2;
- private static final Pattern DEPRECATED_PATTERN
- = CaseInsensitivePattern.compile("(?:\\s*)(?:Устарела|Deprecated)\\.(.*)");
+/**
+ * Класс-описание метода (процедуры или функции)
+ */
+@Value
+public class MethodDescription {
- private final int startLine;
- private final int endLine;
- @Getter
- private final String description;
+ /**
+ * Номер первой строки описания
+ */
+ int startLine;
+ /**
+ * Номер последней строки описания
+ */
+ int endLine;
+ /**
+ * Содержит полное описание метода (весь текст)
+ */
+ String description;
+ /**
+ * Содержит часть строки после ключевого слова, в которой должно быть
+ * описание причины устаревания метода либо альтернативы
+ */
+ String deprecationInfo;
- @Getter
- private final String deprecationInfo;
- @Getter
- private final boolean deprecated;
+ /**
+ * Признак устарения метода
+ */
+ boolean deprecated;
+ /**
+ * Описание назначения метода
+ */
+ String purposeDescription;
+ /**
+ * Примеры использования метода
+ */
+ List examples;
+ /**
+ * Варианты вызова метода
+ */
+ List callOptions;
+ /**
+ * Параметры метода с типами и описанием
+ */
+ List parameters;
+ /**
+ * Возвращаемые значения (типы)
+ */
+ List returnedValue;
+ /**
+ * Если описание содержит только ссылку, то здесь будет ее значение
+ *
+ * TODO Временное решение, надо будет продумать в следующем релизе
+ */
+ String link;
public MethodDescription(List comments) {
description = comments.stream()
.map(Token::getText)
- .map(MethodDescription::uncomment)
.collect(Collectors.joining("\n"));
- Matcher matcher = DEPRECATED_PATTERN.matcher(description);
- if (matcher.find()) {
- deprecationInfo = matcher.group(1);
- deprecated = true;
- } else {
- deprecationInfo = "";
- deprecated = false;
- }
+
+ var tokenizer = new BSLMethodDescriptionTokenizer(description);
+ var ast = requireNonNull(tokenizer.getAst());
+
+ purposeDescription = DescriptionReader.readPurposeDescription(ast);
+ link = DescriptionReader.readLink(ast);
+ deprecated = ast.deprecate() != null;
+ deprecationInfo = DescriptionReader.readDeprecationInfo(ast);
+ callOptions = DescriptionReader.readExamples(ast, BSLMethodDescriptionParser.RULE_callOptionsString);
+ examples = DescriptionReader.readExamples(ast, BSLMethodDescriptionParser.RULE_examplesString);
+ parameters = DescriptionReader.readParameters(ast);
+ returnedValue = DescriptionReader.readReturnedValue(ast);
if (comments.isEmpty()) {
startLine = 0;
@@ -80,12 +126,4 @@ public boolean contains(Token first, Token last) {
return (firstLine >= startLine && lastLine <= endLine);
}
- private static String uncomment(String text) {
- String result = text;
- if (result.startsWith("//")) {
- result = result.substring(COMMENT_LENGTH);
- }
- return result;
- }
-
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/ParameterDefinition.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/ParameterDefinition.java
index 7da5671b7b5..ea9c988a757 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/ParameterDefinition.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/ParameterDefinition.java
@@ -23,6 +23,7 @@
import lombok.Builder;
import lombok.Value;
+import org.eclipse.lsp4j.Range;
/**
* Класс хранит информацию о параметре метода.
@@ -34,4 +35,5 @@ public class ParameterDefinition {
String name;
boolean byValue;
boolean optional;
+ Range range;
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/RegionSymbol.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/RegionSymbol.java
index becd86eac17..9c5741c864e 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/RegionSymbol.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/RegionSymbol.java
@@ -21,7 +21,6 @@
*/
package com.github._1c_syntax.bsl.languageserver.context.symbol;
-import lombok.AccessLevel;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@@ -38,7 +37,7 @@
import java.util.stream.Collectors;
@Value
-@Builder(access = AccessLevel.PUBLIC)
+@Builder(access = lombok.AccessLevel.PUBLIC)
@EqualsAndHashCode(exclude = {"children", "parent"})
@ToString(exclude = {"children", "parent"})
public class RegionSymbol implements Symbol {
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/annotations/package-info.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/annotations/package-info.java
index 7720d5c6ea5..d9d815e55cc 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/annotations/package-info.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/annotations/package-info.java
@@ -19,7 +19,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with BSL Language Server.
*/
-
/**
* В пакете содержатся data-классы для представления аннотаций и директив компиляции.
*/
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/description/DescriptionReader.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/description/DescriptionReader.java
new file mode 100644
index 00000000000..196356f570c
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/description/DescriptionReader.java
@@ -0,0 +1,434 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.context.symbol.description;
+
+import com.github._1c_syntax.bsl.languageserver.utils.Trees;
+import com.github._1c_syntax.bsl.parser.BSLMethodDescriptionParser;
+import com.github._1c_syntax.bsl.parser.BSLParserRuleContext;
+import lombok.experimental.UtilityClass;
+import org.antlr.v4.runtime.tree.ParseTree;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringJoiner;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+/**
+ * Вспомогательный класс для чтения данных из описания метода
+ */
+@UtilityClass
+public class DescriptionReader {
+
+ private static final int HYPERLINK_REF_LEN = 4;
+
+ /**
+ * Выполняет разбор прочитанного AST дерева описания метода и формирует список описаний параметров метода
+ *
+ * @param ctx Дерево описания метода
+ * @return Список описаний параметров метода
+ */
+ public static List readParameters(BSLMethodDescriptionParser.MethodDescriptionContext ctx) {
+
+ List result = new ArrayList<>();
+ var current = new TempParameterData();
+ var strings = getParametersStrings(ctx);
+ for (BSLMethodDescriptionParser.ParametersStringContext string : strings) {
+
+ // найдем дочерние ноды. на самом деле должна быть либо одна указанная нода, либо ни одной, что заставляет
+ // считать строку как описание
+ var child = Trees.findAllRuleNodes(string,
+ BSLMethodDescriptionParser.RULE_parameterString, BSLMethodDescriptionParser.RULE_subParameterString,
+ BSLMethodDescriptionParser.RULE_typeWithDescription)
+ .stream()
+ .findFirst();
+
+ // сразу необходимо обыграть неклассифицированную строку
+ if (child.isEmpty()) {
+ current = readUnknownParameterString(result, current, string);
+ } else {
+ var parameterPart = (BSLParserRuleContext) child.get();
+ current = readSpecialParameterString(result, current, parameterPart);
+ }
+ }
+
+ // не забываем сохранить последний прочитанный параметр
+ saveLastParameter(current, result);
+ return result;
+ }
+
+ /**
+ * Выполняет разбор прочитанного AST дерева описания метода и формирует список описаний возвращаемых значений
+ *
+ * @param ctx Дерево описания метода
+ * @return Список описаний возвращаемых значений
+ */
+ public static List readReturnedValue(BSLMethodDescriptionParser.MethodDescriptionContext ctx) {
+
+ var current = new TempParameterData();
+ var strings = getReturnedValuesStrings(ctx);
+ for (BSLMethodDescriptionParser.ReturnsValuesStringContext string : strings) {
+ current.empty = false;
+
+ // найдем дочерние ноды. на самом деле должна быть либо одна указанная нода, либо ни одной, что заставляет
+ // считать строку как описание
+ var child = Trees.findAllRuleNodes(string,
+ BSLMethodDescriptionParser.RULE_returnsValueString, BSLMethodDescriptionParser.RULE_subParameterString,
+ BSLMethodDescriptionParser.RULE_typeWithDescription)
+ .stream()
+ .findFirst();
+
+ // сразу необходимо обыграть неклассифицированную строку
+ if (child.isEmpty()) {
+ // если прочитанных параметров не было, то учтем как тип без описания
+ if (current.children.isEmpty()) {
+ current.addType(string.getText());
+ } else {
+ // считаем что текущая строка является продолжением описания прочитанного на шаге ранее
+ current.appendDescription(string.getText());
+ }
+ } else {
+ var typePart = (BSLParserRuleContext) child.get();
+ // выполняется разбор параметров в зависимости от типа подстроки
+ if (typePart.getRuleIndex() == BSLMethodDescriptionParser.RULE_subParameterString) {
+ current.addSubParam((BSLMethodDescriptionParser.SubParameterStringContext) typePart);
+ } else {
+ current.addType(typePart);
+ }
+ }
+ }
+
+ return current.getReturnedValueDescription();
+ }
+
+ /**
+ * Выполняет разбор прочитанного AST дерева описания метода и возвращает описание устаревшего метода
+ *
+ * @param ctx Дерево описания метода
+ * @return Описание устаревшего метода
+ */
+ public static String readDeprecationInfo(BSLMethodDescriptionParser.MethodDescriptionContext ctx) {
+ if (ctx.deprecate() != null) {
+ var deprecationDescription = ctx.deprecate().deprecateDescription();
+ if (deprecationDescription != null) {
+ return deprecationDescription.getText().strip();
+ }
+ }
+ return "";
+ }
+
+ /**
+ * Выполняет разбор прочитанного AST дерева описания метода и возвращает список примеров (или вариантов вызова)
+ *
+ * @param ctx Дерево описания метода
+ * @return Список примеров
+ */
+ public static List readExamples(BSLMethodDescriptionParser.MethodDescriptionContext ctx,
+ int ruleIndex) {
+ var exampleStringNodes = Trees.findAllRuleNodes(ctx, ruleIndex);
+ if (exampleStringNodes.isEmpty()) {
+ return Collections.emptyList();
+ } else {
+ return exampleStringNodes.stream()
+ .map(parseTree -> parseTree.getText().strip())
+ .filter(str -> !str.isEmpty())
+ .collect(Collectors.toList());
+ }
+ }
+
+ /**
+ * Выполняет разбор прочитанного AST дерева описания метода и возвращает описание назначения метода.
+ *
+ * @param ctx Дерево описания метода
+ * @return Описание назначения метода
+ */
+ public static String readPurposeDescription(BSLMethodDescriptionParser.MethodDescriptionContext ctx) {
+ if (ctx.description() != null) {
+ var strings = ctx.description().descriptionString();
+ if (strings != null) {
+ return strings.stream()
+ .map(BSLParserRuleContext::getText)
+ .collect(Collectors.joining("\n"))
+ .strip();
+ }
+ }
+ return "";
+ }
+
+ /**
+ * Выполняет разбор прочитанного AST дерева описания метода и достает описание назначения метода.
+ * Если описание метода представляет собой только ссылку, то возвращает ее значение, иначе - пустая строка
+ *
+ * @param ctx Дерево описания метода
+ * @return Ссылка в методе
+ */
+ public static String readLink(BSLMethodDescriptionParser.MethodDescriptionContext ctx) {
+ if (ctx.description() != null) {
+ var allStrings = ctx.description().descriptionString();
+ if (allStrings == null) {
+ return "";
+ }
+
+ // достаем из описания непустые строки
+ var strings = allStrings.stream()
+ .filter(stringContext -> !stringContext.getText().isBlank())
+ .collect(Collectors.toList());
+ if (strings.size() == 1) {
+ AtomicReference result = new AtomicReference<>("");
+ strings.get(0).getTokens(BSLMethodDescriptionParser.HYPERLINK).stream()
+ .findFirst()
+ .ifPresent(hyperLink -> result.set(hyperLink.getText().substring(HYPERLINK_REF_LEN)));
+
+ return result.get();
+ }
+ }
+ return "";
+ }
+
+ private List extends BSLMethodDescriptionParser.ParametersStringContext> getParametersStrings(
+ BSLMethodDescriptionParser.MethodDescriptionContext ast) {
+ if (ast.parameters() != null) {
+ var strings = ast.parameters().parametersString();
+ if (strings != null) {
+ return strings;
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ private List extends BSLMethodDescriptionParser.ReturnsValuesStringContext> getReturnedValuesStrings(
+ BSLMethodDescriptionParser.MethodDescriptionContext ast) {
+ if (ast.returnsValues() != null) {
+ var strings = ast.returnsValues().returnsValuesString();
+ if (strings != null) {
+ return strings;
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ private static TempParameterData readSpecialParameterString(List result,
+ TempParameterData current,
+ BSLParserRuleContext ctx) {
+ // выполняется разбор параметров в зависимости от типа подстроки
+ if (ctx.getRuleIndex() == BSLMethodDescriptionParser.RULE_parameterString) {
+ saveLastParameter(current, result);
+ current = new TempParameterData(ctx);
+ } else if (ctx.getRuleIndex() == BSLMethodDescriptionParser.RULE_subParameterString) {
+ current.addSubParam((BSLMethodDescriptionParser.SubParameterStringContext) ctx);
+ } else { // BSLMethodDescriptionParser.RULE_typeWithDescription
+ current.addType(ctx);
+ }
+ return current;
+ }
+
+ private static TempParameterData readUnknownParameterString(List result,
+ TempParameterData current,
+ BSLParserRuleContext string) {
+ // Строка может состоят из одного слова и пробелов, запомним на будущее
+ var isOneWord = string.getTokens().stream()
+ .filter(t -> t.getType() != BSLMethodDescriptionParser.SPACE
+ && t.getType() != BSLMethodDescriptionParser.EOL).count() == 1;
+
+ // если прочитанных параметров не было, то учтем как параметр без описания
+ if (isOneWord && current.isEmpty()) {
+ current = new TempParameterData(string.getText());
+ // некоторые параметры ранее были прочитаны, но если у них нет описания, то учтем как параметр без описания
+ } else if (isOneWord && current.missingLastDescription()) {
+ saveLastParameter(current, result);
+ current = new TempParameterData(string.getText());
+ // считаем что текущая строка является продолжением описания параметра, прочитанного на шаге ранее
+ } else {
+ current.appendDescription(string.getText());
+ }
+ return current;
+ }
+
+ private static void saveLastParameter(TempParameterData current, List result) {
+ if (current.isEmpty()) {
+ return;
+ }
+ result.add(current.getParameterDescription());
+ }
+
+ /**
+ * Служебный класс для временного хранения прочитанной информации из описания параметра
+ */
+ private static class TempParameterData {
+ private String name;
+ private final StringJoiner description;
+ private boolean empty;
+ private final List children;
+ private TempParameterData last;
+ private TempParameterData parent;
+ private int level;
+
+ TempParameterData() {
+ name = "";
+ description = new StringJoiner("\n");
+ empty = true;
+ children = new ArrayList<>();
+ level = 0;
+ }
+
+ TempParameterData(String text) {
+ this();
+ name = text.strip();
+ empty = false;
+ }
+
+ TempParameterData(BSLParserRuleContext ctx) {
+ this();
+ readAndAddType(ctx);
+ }
+
+ TempParameterData(BSLParserRuleContext ctx, TempParameterData current) {
+ this();
+ level = current.level + 1;
+ parent = current;
+ readAndAddType(ctx);
+ }
+
+ TempParameterData(String text, TempParameterData current) {
+ this(text);
+ level = current.level;
+ parent = current;
+ }
+
+ private void readAndAddType(BSLParserRuleContext ctx) {
+ Trees.getFirstChild(ctx, BSLMethodDescriptionParser.RULE_parameterName)
+ .ifPresent((BSLParserRuleContext child) -> {
+ name = child.getText();
+ empty = false;
+ addType(ctx);
+ });
+ }
+
+ private boolean isEmpty() {
+ return empty;
+ }
+
+ private void appendDescription(ParseTree ctx) {
+ appendDescription(ctx.getText());
+ }
+
+ private void appendDescription(String text) {
+ if (!isEmpty()) {
+ if (last == null) {
+ description.add(text.strip());
+ } else {
+ last.appendDescription(text);
+ }
+ }
+ }
+
+ private void addType(BSLParserRuleContext ctx) {
+ if (isEmpty()) {
+ return;
+ }
+
+ if (last != null && !last.children.isEmpty()) {
+ last.addType(ctx);
+ } else if (ctx.getRuleIndex() == BSLMethodDescriptionParser.RULE_typeWithDescription
+ || ctx.getRuleIndex() == BSLMethodDescriptionParser.RULE_returnsValueString) {
+ addNewType(ctx);
+ } else {
+ Trees.getFirstChild(ctx, BSLMethodDescriptionParser.RULE_typeWithDescription)
+ .ifPresent(this::addNewType);
+ }
+ }
+
+ private void addType(String text) {
+ var newType = new TempParameterData(text, this);
+ children.add(newType);
+ last = newType;
+ }
+
+ private void addNewType(BSLParserRuleContext ctx) {
+ last = null;
+ Trees.getFirstChild(ctx, BSLMethodDescriptionParser.RULE_types).ifPresent(
+ (BSLParserRuleContext typeString) -> {
+ var newType = new TempParameterData(typeString.getText(), this);
+ Trees.findAllRuleNodes(ctx, BSLMethodDescriptionParser.RULE_typeDescription)
+ .stream().findFirst()
+ .ifPresent(newType::appendDescription);
+ children.add(newType);
+ last = newType;
+ });
+ }
+
+ private void addSubParam(BSLMethodDescriptionParser.SubParameterStringContext ctx) {
+ if (isEmpty()) {
+ return;
+ }
+
+ // если тип не определен был, то подчиненных параметров быть не может
+ if (last == null) {
+ appendDescription(ctx.getText());
+ return;
+ }
+ var child = ctx.starPreffix();
+ var subParamLevel = child.getText().length();
+ TempParameterData subParameter;
+ if (last.level >= subParamLevel) {
+ while (last.level >= subParamLevel) {
+ last = last.parent;
+ }
+ }
+ subParameter = new TempParameterData(ctx, last);
+ last.children.add(subParameter);
+ last = subParameter.last;
+ }
+
+ private boolean missingLastDescription() {
+ if (last != null) {
+ return last.missingLastDescription();
+ }
+ return description.toString().isEmpty();
+ }
+
+ private ParameterDescription getParameterDescription() {
+ var parameterTypes = children.stream()
+ .map((TempParameterData child) -> {
+ List subParameters = new ArrayList<>();
+ if (!child.children.isEmpty()) {
+ child.children.forEach(subParam -> subParameters.add(subParam.getParameterDescription()));
+ }
+ return new TypeDescription(child.name, child.description.toString(), subParameters);
+ }).collect(Collectors.toList());
+
+ var descriptionStr = description.toString();
+ if (descriptionStr.isEmpty() && parameterTypes.size() == 1) {
+ descriptionStr = parameterTypes.get(0).getDescription();
+ }
+ return new ParameterDescription(name, parameterTypes, descriptionStr);
+ }
+
+ private List getReturnedValueDescription() {
+ if (!isEmpty()) {
+ return getParameterDescription().getTypes();
+ }
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/description/ParameterDescription.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/description/ParameterDescription.java
new file mode 100644
index 00000000000..009a24c98e9
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/description/ParameterDescription.java
@@ -0,0 +1,47 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.context.symbol.description;
+
+import lombok.AllArgsConstructor;
+import lombok.Value;
+
+import java.util.List;
+
+/**
+ * Описание параметра из комментария - описания метода
+ */
+@AllArgsConstructor
+@Value
+public class ParameterDescription {
+ /**
+ * Имя параметра
+ */
+ String name;
+ /**
+ * Возможные типы параметра. Может быть пустым
+ */
+ List types;
+ /**
+ * Описание параметра. TODO а зачем, если все привязано к типам?
+ */
+ String description;
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/description/TypeDescription.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/description/TypeDescription.java
new file mode 100644
index 00000000000..be82f25af5f
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/description/TypeDescription.java
@@ -0,0 +1,47 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.context.symbol.description;
+
+import lombok.AllArgsConstructor;
+import lombok.Value;
+
+import java.util.List;
+
+/**
+ * Описание типа параметра, прочитанного из описания метода
+ */
+@AllArgsConstructor
+@Value
+public class TypeDescription {
+ /**
+ * Имя типа. На данный момент может быть строковый массив перечисления типов а также гиперссылка на метод
+ */
+ String name;
+ /**
+ * Описание типа. Может быть пустым
+ */
+ String description;
+ /**
+ * Параметры (ключи или поля) типа для сложных типов данных. Может быть пустым
+ */
+ List parameters;
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/description/package-info.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/description/package-info.java
new file mode 100644
index 00000000000..dbcd9b968bd
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/description/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+/**
+ * Классы для хранения информации, прочитанной из комментариев-описаний
+ */
+@ParametersAreNonnullByDefault
+package com.github._1c_syntax.bsl.languageserver.context.symbol.description;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AbstractCommonModuleNameDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AbstractCommonModuleNameDiagnostic.java
index 57a781cbdb4..c5afbe6b925 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AbstractCommonModuleNameDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AbstractCommonModuleNameDiagnostic.java
@@ -21,24 +21,32 @@
*/
package com.github._1c_syntax.bsl.languageserver.diagnostics;
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
+import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
import com.github._1c_syntax.mdclasses.mdo.CommonModule;
import com.github._1c_syntax.mdclasses.mdo.MDObjectBase;
import com.github._1c_syntax.utils.CaseInsensitivePattern;
+import org.eclipse.lsp4j.Range;
+import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+
abstract class AbstractCommonModuleNameDiagnostic extends AbstractDiagnostic {
protected Pattern pattern;
+ private final LanguageServerConfiguration serverConfiguration;
- public AbstractCommonModuleNameDiagnostic(String regexp) {
- pattern = CaseInsensitivePattern.compile(regexp);
+ protected AbstractCommonModuleNameDiagnostic(LanguageServerConfiguration serverConfiguration, String regexp) {
+ this.serverConfiguration = serverConfiguration;
+ this.pattern = CaseInsensitivePattern.compile(regexp);
}
@Override
protected void check() {
- if (documentContext.getTokensFromDefaultChannel().isEmpty()) {
+ Optional range = Ranges.getFirstSignificantTokenRange(documentContext.getTokens());
+ if (range.isEmpty()) {
return;
}
@@ -49,7 +57,7 @@ protected void check() {
.map(MDObjectBase::getName)
.map(pattern::matcher)
.filter(this::matchCheck)
- .ifPresent(commonModule -> diagnosticStorage.addDiagnostic(documentContext.getTokensFromDefaultChannel().get(0)));
+ .ifPresent(commonModule -> diagnosticStorage.addDiagnostic(range.get()));
}
protected abstract boolean flagsCheck(CommonModule commonModule);
@@ -58,21 +66,21 @@ protected boolean matchCheck(Matcher matcher) {
return !matcher.find();
}
- protected static boolean isClientServer(CommonModule commonModule) {
+ protected boolean isClientServer(CommonModule commonModule) {
return !commonModule.isServerCall()
&& commonModule.isServer()
&& commonModule.isExternalConnection()
&& isClientApplication(commonModule);
}
- protected static boolean isClient(CommonModule commonModule) {
+ protected boolean isClient(CommonModule commonModule) {
return !commonModule.isServerCall()
&& !commonModule.isServer()
&& !commonModule.isExternalConnection()
&& isClientApplication(commonModule);
}
- protected static boolean isServerCall(CommonModule commonModule) {
+ protected boolean isServerCall(CommonModule commonModule) {
return commonModule.isServerCall()
&& commonModule.isServer()
&& !commonModule.isExternalConnection()
@@ -80,17 +88,21 @@ protected static boolean isServerCall(CommonModule commonModule) {
&& !commonModule.isClientManagedApplication();
}
- protected static boolean isServer(CommonModule commonModule) {
+ protected boolean isServer(CommonModule commonModule) {
return !commonModule.isServerCall()
&& commonModule.isServer()
&& commonModule.isExternalConnection()
- && commonModule.isClientOrdinaryApplication()
+ && isClientOrdinaryAppIfNeed(commonModule)
&& !commonModule.isClientManagedApplication();
}
- private static boolean isClientApplication(CommonModule commonModule) {
- return commonModule.isClientOrdinaryApplication()
+ private boolean isClientApplication(CommonModule commonModule) {
+ return isClientOrdinaryAppIfNeed(commonModule)
&& commonModule.isClientManagedApplication();
}
+ private boolean isClientOrdinaryAppIfNeed(CommonModule commonModule) {
+ return commonModule.isClientOrdinaryApplication()
+ || !serverConfiguration.getDiagnosticsOptions().isOrdinaryAppSupport();
+ }
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CodeOutOfRegionDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CodeOutOfRegionDiagnostic.java
index 7ea0bc4f30e..a0afa119274 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CodeOutOfRegionDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CodeOutOfRegionDiagnostic.java
@@ -25,6 +25,7 @@
import com.github._1c_syntax.bsl.languageserver.context.symbol.RegionSymbol;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticCompatibilityMode;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticParameter;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
@@ -34,6 +35,7 @@
import com.github._1c_syntax.bsl.languageserver.utils.Trees;
import com.github._1c_syntax.bsl.parser.BSLParser;
import com.github._1c_syntax.bsl.parser.BSLParserRuleContext;
+import com.github._1c_syntax.mdclasses.metadata.additional.ModuleType;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.antlr.v4.runtime.tree.Tree;
@@ -55,14 +57,27 @@
compatibilityMode = DiagnosticCompatibilityMode.COMPATIBILITY_MODE_8_3_1
)
public class CodeOutOfRegionDiagnostic extends AbstractVisitorDiagnostic {
+ private static final boolean CHECK_UNKNOWN_MODULE_TYPE = false;
private final List regionsRanges = new ArrayList<>();
+ @DiagnosticParameter(
+ type = Boolean.class,
+ defaultValue = "" + CHECK_UNKNOWN_MODULE_TYPE
+ )
+ private boolean checkUnknownModuleType = CHECK_UNKNOWN_MODULE_TYPE;
+
@Override
public ParseTree visitFile(BSLParser.FileContext ctx) {
+
+ // Для неизвестных модулей не будем требовать нахождения кода в области
+ if (documentContext.getModuleType() == ModuleType.UNKNOWN && !checkUnknownModuleType) {
+ return ctx;
+ }
+
List regions = documentContext.getSymbolTree().getModuleLevelRegions();
regionsRanges.clear();
- // если областей нет, то и смысла дальше анализировть тоже нет
+ // если областей нет, то и смысла дальше анализировать тоже нет
if (regions.isEmpty() && !ctx.getTokens().isEmpty()) {
List relatedInformation = createRelatedInformations(ctx);
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommandModuleExportMethodsDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommandModuleExportMethodsDiagnostic.java
new file mode 100644
index 00000000000..3db5d943782
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommandModuleExportMethodsDiagnostic.java
@@ -0,0 +1,54 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.diagnostics;
+
+import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+import com.github._1c_syntax.mdclasses.metadata.additional.ModuleType;
+
+@DiagnosticMetadata(
+ type = DiagnosticType.CODE_SMELL,
+ severity = DiagnosticSeverity.INFO,
+ scope = DiagnosticScope.BSL,
+ modules = {
+ ModuleType.CommandModule
+ },
+ minutesToFix = 1,
+ tags = {
+ DiagnosticTag.STANDARD,
+ DiagnosticTag.CLUMSY
+ }
+)
+public class CommandModuleExportMethodsDiagnostic extends AbstractSymbolTreeDiagnostic {
+
+ @Override
+ public void visitMethod(MethodSymbol method) {
+ if (method.isExport()) {
+ diagnosticStorage.addDiagnostic(method.getSubNameRange());
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleInvalidTypeDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleInvalidTypeDiagnostic.java
index 66cdca39556..5e5df5369b8 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleInvalidTypeDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleInvalidTypeDiagnostic.java
@@ -21,6 +21,7 @@
*/
package com.github._1c_syntax.bsl.languageserver.diagnostics;
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
@@ -46,9 +47,11 @@
}
)
+
public class CommonModuleInvalidTypeDiagnostic extends AbstractCommonModuleNameDiagnostic {
- public CommonModuleInvalidTypeDiagnostic() {
- super("");
+
+ public CommonModuleInvalidTypeDiagnostic(LanguageServerConfiguration serverConfiguration) {
+ super(serverConfiguration, "");
}
@Override
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameCachedDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameCachedDiagnostic.java
index 3f1d3f28ba8..84d67c9c295 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameCachedDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameCachedDiagnostic.java
@@ -21,6 +21,7 @@
*/
package com.github._1c_syntax.bsl.languageserver.diagnostics;
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
@@ -46,10 +47,11 @@
)
public class CommonModuleNameCachedDiagnostic extends AbstractCommonModuleNameDiagnostic {
+
private static final String REGEXP = "повторноеиспользование|повтисп|cached";
- public CommonModuleNameCachedDiagnostic() {
- super(REGEXP);
+ public CommonModuleNameCachedDiagnostic(LanguageServerConfiguration serverConfiguration) {
+ super(serverConfiguration, REGEXP);
}
@Override
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameClientDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameClientDiagnostic.java
index c80386391fb..cae69a4c310 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameClientDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameClientDiagnostic.java
@@ -21,6 +21,7 @@
*/
package com.github._1c_syntax.bsl.languageserver.diagnostics;
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
@@ -47,8 +48,8 @@ public class CommonModuleNameClientDiagnostic extends AbstractCommonModuleNameDi
private static final String REGEXP = "клиент|client";
- public CommonModuleNameClientDiagnostic() {
- super(REGEXP);
+ public CommonModuleNameClientDiagnostic(LanguageServerConfiguration serverConfiguration) {
+ super(serverConfiguration, REGEXP);
}
@Override
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameClientServerDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameClientServerDiagnostic.java
index 0e790cf509d..366d605098b 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameClientServerDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameClientServerDiagnostic.java
@@ -21,6 +21,7 @@
*/
package com.github._1c_syntax.bsl.languageserver.diagnostics;
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
@@ -47,8 +48,8 @@ public class CommonModuleNameClientServerDiagnostic extends AbstractCommonModule
private static final String REGEXP = "клиентсервер|clientserver";
- public CommonModuleNameClientServerDiagnostic() {
- super(REGEXP);
+ public CommonModuleNameClientServerDiagnostic(LanguageServerConfiguration serverConfiguration) {
+ super(serverConfiguration, REGEXP);
}
@Override
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameFullAccessDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameFullAccessDiagnostic.java
index 9563ff275fd..13ed5f2f049 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameFullAccessDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameFullAccessDiagnostic.java
@@ -21,6 +21,7 @@
*/
package com.github._1c_syntax.bsl.languageserver.diagnostics;
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
@@ -47,8 +48,8 @@ public class CommonModuleNameFullAccessDiagnostic extends AbstractCommonModuleNa
private static final String REGEXP = "полныеправа|fullaccess";
- public CommonModuleNameFullAccessDiagnostic() {
- super(REGEXP);
+ public CommonModuleNameFullAccessDiagnostic(LanguageServerConfiguration serverConfiguration) {
+ super(serverConfiguration, REGEXP);
}
@Override
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameGlobalClientDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameGlobalClientDiagnostic.java
index bed1375036f..a3c21c68bd5 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameGlobalClientDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameGlobalClientDiagnostic.java
@@ -21,6 +21,7 @@
*/
package com.github._1c_syntax.bsl.languageserver.diagnostics;
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
@@ -45,8 +46,8 @@ public class CommonModuleNameGlobalClientDiagnostic extends AbstractCommonModule
private static final String REGEXP = "^(?>(?!.+клиент|.+client).)*$";
- public CommonModuleNameGlobalClientDiagnostic() {
- super(REGEXP);
+ public CommonModuleNameGlobalClientDiagnostic(LanguageServerConfiguration serverConfiguration) {
+ super(serverConfiguration, REGEXP);
}
@Override
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameGlobalDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameGlobalDiagnostic.java
index 3985967c605..f90b2a98ecf 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameGlobalDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameGlobalDiagnostic.java
@@ -21,6 +21,7 @@
*/
package com.github._1c_syntax.bsl.languageserver.diagnostics;
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
@@ -47,8 +48,8 @@ public class CommonModuleNameGlobalDiagnostic extends AbstractCommonModuleNameDi
private static final String REGEXP = "глобальный|global";
- public CommonModuleNameGlobalDiagnostic() {
- super(REGEXP);
+ public CommonModuleNameGlobalDiagnostic(LanguageServerConfiguration serverConfiguration) {
+ super(serverConfiguration, REGEXP);
}
@Override
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameServerCallDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameServerCallDiagnostic.java
index f262b7e5b04..11c59756353 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameServerCallDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameServerCallDiagnostic.java
@@ -21,6 +21,7 @@
*/
package com.github._1c_syntax.bsl.languageserver.diagnostics;
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
@@ -47,8 +48,8 @@ public class CommonModuleNameServerCallDiagnostic extends AbstractCommonModuleNa
private static final String REGEXP = "вызовсервера|servercall";
- public CommonModuleNameServerCallDiagnostic() {
- super(REGEXP);
+ public CommonModuleNameServerCallDiagnostic(LanguageServerConfiguration serverConfiguration) {
+ super(serverConfiguration, REGEXP);
}
@Override
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameWordsDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameWordsDiagnostic.java
index dfad523521a..4aa405ca217 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameWordsDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CommonModuleNameWordsDiagnostic.java
@@ -21,6 +21,7 @@
*/
package com.github._1c_syntax.bsl.languageserver.diagnostics;
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticParameter;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
@@ -61,8 +62,8 @@ public class CommonModuleNameWordsDiagnostic extends AbstractCommonModuleNameDia
)
private String words = DEFAULT_WORDS;
- public CommonModuleNameWordsDiagnostic() {
- super(DEFAULT_WORDS);
+ public CommonModuleNameWordsDiagnostic(LanguageServerConfiguration serverConfiguration) {
+ super(serverConfiguration, DEFAULT_WORDS);
}
@Override
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/DiagnosticStorage.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/DiagnosticStorage.java
index afd094b7db2..fc034e9d53f 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/DiagnosticStorage.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/DiagnosticStorage.java
@@ -24,6 +24,7 @@
import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
import com.github._1c_syntax.bsl.parser.BSLParserRuleContext;
import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.DiagnosticRelatedInformation;
@@ -200,6 +201,16 @@ public void addDiagnostic(
));
}
+ public void addDiagnostic(ParseTree tree) {
+ if(tree instanceof BSLParserRuleContext) {
+ addDiagnostic((BSLParserRuleContext) tree);
+ } else if (tree instanceof TerminalNode) {
+ addDiagnostic((TerminalNode) tree);
+ } else {
+ throw new IllegalArgumentException("Unsupported parameter type " + tree);
+ }
+ }
+
private static Diagnostic createDiagnostic(
BSLDiagnostic bslDiagnostic,
Range range,
@@ -214,6 +225,7 @@ private static Diagnostic createDiagnostic(
);
diagnostic.setCode(bslDiagnostic.getInfo().getCode());
+ diagnostic.setTags(bslDiagnostic.getInfo().getLSPTags());
if (relatedInformation != null) {
diagnostic.setRelatedInformation(relatedInformation);
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FunctionOutParameterDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FunctionOutParameterDiagnostic.java
new file mode 100644
index 00000000000..53ce201e4ad
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FunctionOutParameterDiagnostic.java
@@ -0,0 +1,90 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.diagnostics;
+
+import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.ParameterDefinition;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+import com.github._1c_syntax.bsl.languageserver.utils.Trees;
+import com.github._1c_syntax.bsl.parser.BSLParser;
+import com.github._1c_syntax.bsl.parser.BSLParserRuleContext;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.apache.commons.collections4.map.CaseInsensitiveMap;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+@DiagnosticMetadata(
+ type = DiagnosticType.CODE_SMELL,
+ severity = DiagnosticSeverity.MAJOR,
+ minutesToFix = 10,
+ activatedByDefault = false,
+ tags = {
+ DiagnosticTag.DESIGN
+ }
+
+)
+public class FunctionOutParameterDiagnostic extends AbstractVisitorDiagnostic {
+
+ @Override
+ public ParseTree visitFunction(BSLParser.FunctionContext ctx) {
+
+ List parameters = documentContext
+ .getSymbolTree()
+ .getMethodSymbol((BSLParserRuleContext) ctx.getParent())
+ .stream()
+ .map(MethodSymbol::getParameters)
+ .flatMap(Collection::stream)
+ .filter(param -> !param.isByValue())
+ .collect(Collectors.toList());
+
+ if (parameters.isEmpty()) {
+ return ctx;
+ }
+
+ Map lvalues = Trees
+ .findAllRuleNodes(ctx.subCodeBlock(), BSLParser.RULE_lValue)
+ .stream()
+ .collect(
+ Collectors.toMap(
+ ParseTree::getText,
+ node -> (BSLParserRuleContext) node,
+ (existing, replacement) -> existing,
+ CaseInsensitiveMap::new)
+ );
+
+ parameters.
+ stream()
+ .filter(param -> lvalues.containsKey(param.getName()))
+ .map(param -> lvalues.get(param.getName()))
+ .filter(Objects::nonNull)
+ .forEach(diagnosticStorage::addDiagnostic);
+
+ return ctx;
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/GlobalContextMethodCollision8312Diagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/GlobalContextMethodCollision8312Diagnostic.java
new file mode 100644
index 00000000000..659c942b893
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/GlobalContextMethodCollision8312Diagnostic.java
@@ -0,0 +1,63 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.diagnostics;
+
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticCompatibilityMode;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticInfo;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+import com.github._1c_syntax.utils.CaseInsensitivePattern;
+
+import java.util.regex.Pattern;
+
+@DiagnosticMetadata(
+ type = DiagnosticType.ERROR,
+ severity = DiagnosticSeverity.BLOCKER,
+ minutesToFix = 10,
+ tags = {
+ DiagnosticTag.ERROR,
+ DiagnosticTag.UNPREDICTABLE
+ },
+ compatibilityMode = DiagnosticCompatibilityMode.COMPATIBILITY_MODE_8_3_12
+
+)
+public class GlobalContextMethodCollision8312Diagnostic extends AbstractDiagnostic {
+
+ private static final Pattern COLLISION_METHODS = CaseInsensitivePattern.compile("(ПроверитьБит|ПроверитьПоБитовойМаске|УстановитьБит|ПобитовоеИ|ПобитовоеИли|ПобитовоеНе|ПобитовоеИНе|" +
+ "ПобитовоеИсключительноеИли|ПобитовыйСдвигВлево|ПобитовыйСдвигВправо|" +
+ "CheckBit|CheckByBitMask|SetBit|BitwiseAnd|BitwiseOr|BitwiseNot|BitwiseAndNot|BitwiseXor|BitwiseShiftLeft|" +
+ "BitwiseShiftRight)");
+
+ @Override
+ protected void check() {
+ documentContext.getSymbolTree().getMethods().stream()
+ .filter(method -> COLLISION_METHODS.matcher(method.getName()).matches())
+ .forEach(method ->
+ diagnosticStorage.addDiagnostic(
+ method.getSubNameRange(),
+ info.getMessage(method.getName())
+ )
+ );
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/IfConditionComplexityDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/IfConditionComplexityDiagnostic.java
index 9f5db0685b3..535fb3df0a5 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/IfConditionComplexityDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/IfConditionComplexityDiagnostic.java
@@ -19,7 +19,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with BSL Language Server.
*/
-
package com.github._1c_syntax.bsl.languageserver.diagnostics;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/LatinAndCyrillicSymbolInWordDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/LatinAndCyrillicSymbolInWordDiagnostic.java
new file mode 100644
index 00000000000..4ffd5cd3432
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/LatinAndCyrillicSymbolInWordDiagnostic.java
@@ -0,0 +1,131 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.diagnostics;
+
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticParameter;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+import com.github._1c_syntax.bsl.languageserver.utils.Trees;
+import com.github._1c_syntax.bsl.parser.BSLParser;
+import com.github._1c_syntax.utils.CaseInsensitivePattern;
+import org.antlr.v4.runtime.tree.ParseTree;
+
+import java.util.Map;
+import java.util.StringJoiner;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+@DiagnosticMetadata(
+ type = DiagnosticType.CODE_SMELL,
+ severity = DiagnosticSeverity.MINOR,
+ minutesToFix = 5,
+ tags = {
+ DiagnosticTag.BRAINOVERLOAD,
+ DiagnosticTag.SUSPICIOUS
+ }
+)
+public class LatinAndCyrillicSymbolInWordDiagnostic extends AbstractDiagnostic {
+ /**
+ * Минимальная длина имени для анализа
+ */
+ private static final int MINIMAL_WORD_LEN = 2;
+
+ /**
+ * Список слов-исключений через `,`
+ */
+ private static final String DEFAULT_EXCLUDE_WORDS = "ЧтениеXML, ЧтениеJSON, ЗаписьXML, ЗаписьJSON, ComОбъект, " +
+ "ФабрикаXDTO, ОбъектXDTO, СоединениеFTP, HTTPСоединение, HTTPЗапрос, HTTPСервисОтвет, SMSСообщение, WSПрокси";
+
+ /**
+ * Паттерн для поиска кириллических символов в имени
+ */
+ private static final Pattern RU_LANG_PATTERN = CaseInsensitivePattern.compile("[а-яё]");
+
+ /**
+ * Паттерн для поиска латинских символов в имени
+ */
+ private static final Pattern EN_LANG_PATTERN = CaseInsensitivePattern.compile("[a-z]");
+
+ @DiagnosticParameter(
+ type = String.class,
+ defaultValue = "" + DEFAULT_EXCLUDE_WORDS
+ )
+ private Pattern excludeWords = createExcludeWordPattern(DEFAULT_EXCLUDE_WORDS);
+
+ private static Pattern createExcludeWordPattern(String words) {
+ StringJoiner stringJoiner = new StringJoiner("|");
+ for (String elem : words.split(",")) {
+ stringJoiner.add(Pattern.quote(elem.trim()));
+ }
+
+ return CaseInsensitivePattern.compile("(?:^" + stringJoiner.toString() + ")");
+ }
+
+ @Override
+ public void configure(Map configuration) {
+ this.excludeWords = createExcludeWordPattern(
+ (String) configuration.getOrDefault("excludeWords", DEFAULT_EXCLUDE_WORDS));
+ }
+
+ @Override
+ protected void check() {
+ check(BSLParser.RULE_subName);
+ check(BSLParser.RULE_var_name);
+ check(BSLParser.RULE_annotationName);
+ check(BSLParser.RULE_annotationParamName);
+ check(BSLParser.RULE_regionName);
+
+ checkLabel();
+ checkParameters();
+ checkLValue();
+ }
+
+ private void check(int ruleID) {
+ checkTree(Trees.findAllRuleNodes(documentContext.getAst(), ruleID).stream());
+ }
+
+ private void checkLValue() {
+ checkTree(Trees.findAllRuleNodes(documentContext.getAst(), BSLParser.RULE_lValue).stream()
+ .filter(ctx -> ((BSLParser.LValueContext) ctx).IDENTIFIER() != null)
+ .map(ctx -> ((BSLParser.LValueContext) ctx).IDENTIFIER()));
+ }
+
+ private void checkParameters() {
+ checkTree(Trees.findAllRuleNodes(documentContext.getAst(), BSLParser.RULE_param).stream()
+ .filter(ctx -> ((BSLParser.ParamContext) ctx).IDENTIFIER() != null)
+ .map(ctx -> ((BSLParser.ParamContext) ctx).IDENTIFIER()));
+ }
+
+ private void checkLabel() {
+ checkTree(Trees.findAllRuleNodes(documentContext.getAst(), BSLParser.RULE_labelName).stream()
+ .filter(ctx -> ctx.getParent() instanceof BSLParser.GotoStatementContext));
+ }
+
+ private void checkTree(Stream tree) {
+ tree.filter(ctx -> ctx.getText() != null && ctx.getText().length() >= MINIMAL_WORD_LEN)
+ .filter(ctx -> !excludeWords.matcher(ctx.getText()).matches())
+ .filter(ctx -> RU_LANG_PATTERN.matcher(ctx.getText()).find() && EN_LANG_PATTERN.matcher(ctx.getText()).find())
+ .forEach(diagnosticStorage::addDiagnostic);
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MagicDateDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MagicDateDiagnostic.java
new file mode 100644
index 00000000000..7ed3a5f01d7
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MagicDateDiagnostic.java
@@ -0,0 +1,133 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.diagnostics;
+
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticParameter;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+import com.github._1c_syntax.bsl.parser.BSLParser;
+import com.github._1c_syntax.bsl.parser.BSLParserRuleContext;
+import com.github._1c_syntax.utils.CaseInsensitivePattern;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+@DiagnosticMetadata(
+ type = DiagnosticType.CODE_SMELL,
+ severity = DiagnosticSeverity.MINOR,
+ minutesToFix = 5,
+ tags = {
+ DiagnosticTag.BADPRACTICE,
+ DiagnosticTag.BRAINOVERLOAD
+ }
+
+)
+public class MagicDateDiagnostic extends AbstractVisitorDiagnostic {
+
+ private static final String DEFAULT_AUTHORIZED_DATES = "00010101,00010101000000,000101010000";
+
+ private static final Pattern methodPattern = CaseInsensitivePattern.compile(
+ "Дата|Date"
+ );
+
+ private static final Pattern paramPattern = CaseInsensitivePattern.compile(
+ "\"\\d{8}.*"
+ );
+
+ private static final Pattern nonNumberPattern = CaseInsensitivePattern.compile(
+ "\\D"
+ );
+
+ @DiagnosticParameter(
+ type = String.class,
+ defaultValue = "" + DEFAULT_AUTHORIZED_DATES
+ )
+ private Set authorizedDates = new HashSet<>(Arrays.asList(DEFAULT_AUTHORIZED_DATES.split(",")));
+
+ @Override
+ public void configure(Map configuration) {
+ String authorizedDatesString =
+ (String) configuration.getOrDefault("authorizedDates", DEFAULT_AUTHORIZED_DATES);
+ Set authD =
+ Arrays.stream(authorizedDatesString.split(",")).map(s -> s.trim()).collect(Collectors.toSet());
+ this.authorizedDates.addAll(authD);
+ }
+
+ @Override
+ public ParseTree visitGlobalMethodCall(BSLParser.GlobalMethodCallContext ctx) {
+ Optional.of(ctx)
+ .filter(it -> methodPattern.matcher(it.methodName().getText()).matches())
+ .map(BSLParser.GlobalMethodCallContext::doCall)
+ .map(BSLParser.DoCallContext::callParamList)
+ .filter(callParamList -> paramPattern.matcher(callParamList.getText()).matches())
+ .ifPresent(this::checkExclAddDiagnostic);
+
+ return super.visitGlobalMethodCall(ctx);
+ }
+
+ @Override
+ public ParseTree visitConstValue(BSLParser.ConstValueContext ctx) {
+ TerminalNode tNode = ctx.DATETIME();
+ if (tNode != null) {
+ checkExclAddDiagnostic(ctx);
+ }
+
+ return ctx;
+ }
+
+ private void checkExclAddDiagnostic(BSLParserRuleContext ctx){
+ String checked = ctx.getText();
+ if (checked != null && !isExcluded(checked)) {
+ ParserRuleContext expression;
+ if (ctx instanceof BSLParser.CallParamListContext){
+ expression = ctx.getParent().getParent().getParent().getParent().getParent();
+ }
+ else {
+ expression = ctx.getParent().getParent();
+ }
+ if (expression instanceof BSLParser.ExpressionContext
+ && (!isAssignExpression((BSLParser.ExpressionContext) expression))) {
+ diagnosticStorage.addDiagnostic(ctx.stop, info.getMessage(checked));
+ }
+ }
+ }
+
+ private boolean isExcluded(String sIn) {
+ String s = nonNumberPattern.matcher(sIn).replaceAll("");
+ return authorizedDates.contains(s);
+ }
+
+ private static boolean isAssignExpression(BSLParser.ExpressionContext expression) {
+ return (expression.getChildCount() <= 1);
+ }
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MetadataObjectNameLengthDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MetadataObjectNameLengthDiagnostic.java
index 76b08dc0d5f..793dfbeb1c5 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MetadataObjectNameLengthDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MetadataObjectNameLengthDiagnostic.java
@@ -27,8 +27,11 @@
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
import com.github._1c_syntax.mdclasses.mdo.MDObjectBase;
-import org.antlr.v4.runtime.Token;
+import org.eclipse.lsp4j.Range;
+
+import java.util.Optional;
@DiagnosticMetadata(
type = DiagnosticType.ERROR,
@@ -52,18 +55,20 @@ public class MetadataObjectNameLengthDiagnostic extends AbstractDiagnostic {
@Override
protected void check() {
- if (!documentContext.getTokens().isEmpty()
- && documentContext.getTokens().get(0).getType() != Token.EOF
- ) {
- documentContext
- .getMdObject()
- .map(MDObjectBase::getName)
- .filter(this::checkName)
- .ifPresent(name -> diagnosticStorage.addDiagnostic(
- documentContext.getTokens().get(0),
- info.getMessage(maxMetadataObjectNameLength))
- );
+
+ Optional range = Ranges.getFirstSignificantTokenRange(documentContext.getTokens());
+ if (range.isEmpty()) {
+ return;
}
+
+ documentContext
+ .getMdObject()
+ .map(MDObjectBase::getName)
+ .filter(this::checkName)
+ .ifPresent(name -> diagnosticStorage.addDiagnostic(
+ range.get(),
+ info.getMessage(maxMetadataObjectNameLength))
+ );
}
private boolean checkName(String name) {
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MissingEventSubscriptionHandlerDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MissingEventSubscriptionHandlerDiagnostic.java
new file mode 100644
index 00000000000..6cec5f00d4a
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MissingEventSubscriptionHandlerDiagnostic.java
@@ -0,0 +1,143 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.diagnostics;
+
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
+import com.github._1c_syntax.mdclasses.mdo.CommonModule;
+import com.github._1c_syntax.mdclasses.mdo.EventSubscription;
+import com.github._1c_syntax.mdclasses.metadata.additional.ConfigurationSource;
+import com.github._1c_syntax.mdclasses.metadata.additional.MDOType;
+import com.github._1c_syntax.mdclasses.metadata.additional.ModuleType;
+import org.eclipse.lsp4j.Range;
+
+import java.util.regex.Pattern;
+
+@DiagnosticMetadata(
+ type = DiagnosticType.ERROR,
+ severity = DiagnosticSeverity.BLOCKER,
+ minutesToFix = 5,
+ tags = {
+ DiagnosticTag.ERROR
+ },
+ scope = DiagnosticScope.BSL,
+ modules = {
+ // todo переделать, когда появится привязка к объектам метаданных
+ ModuleType.SessionModule
+ }
+)
+public class MissingEventSubscriptionHandlerDiagnostic extends AbstractDiagnostic {
+
+ /**
+ * Рендж на который будут повешены замечания
+ * Костыль, но пока так
+ */
+ private Range diagnosticRange;
+ private static final Pattern SPLIT_PATTERN = Pattern.compile("\\.");
+
+ @Override
+ protected void check() {
+
+ Ranges.getFirstSignificantTokenRange(documentContext.getTokens())
+ .ifPresent(range -> diagnosticRange = range);
+
+ if (diagnosticRange == null) {
+ // нет ренджа - нет и диагностик :)
+ return;
+ }
+
+ var configuration = documentContext.getServerContext().getConfiguration();
+ if (configuration.getConfigurationSource() == ConfigurationSource.EMPTY) {
+ return;
+ }
+
+ // для анализа выбираются все имеющиеся подписки на события
+ configuration.getChildren().stream()
+ .filter(mdo -> mdo.getType() == MDOType.EVENT_SUBSCRIPTION)
+ .map(mdo -> (EventSubscription) mdo)
+ .forEach((EventSubscription eventSubs) -> {
+ // проверка на пустой обработчик
+ if (eventSubs.getHandler().isEmpty()) {
+ addDiagnostic(eventSubs);
+ return;
+ }
+
+ var handlerParts = SPLIT_PATTERN.split(eventSubs.getHandler());
+
+ // правильный обработчик состоит из трех частей:
+ // - CommonModule - тип объекта, всегда постоянный: общий модуль
+ // - Имя - имя модуля
+ // - ИмяМетода - имя метода в модуле
+
+ if (handlerParts.length != 3) {
+ addDiagnostic("incorrectHandler", eventSubs, eventSubs.getHandler());
+ return;
+ }
+
+ // проверка на существование модуля
+ var module = configuration.getCommonModule(handlerParts[1]);
+ if (module.isEmpty()) {
+ addDiagnostic("missingModule", eventSubs, handlerParts[1]);
+ return;
+ }
+
+ var commonModule = module.get();
+ // проверка наличия у модуля серверного флага
+ if (!commonModule.isServer()) {
+ addDiagnostic("shouldBeServer", eventSubs, handlerParts[1]);
+ }
+
+ // проверка на наличие метода и его экспортности
+ checkMethod(eventSubs, handlerParts[2], commonModule);
+ });
+ }
+
+ private void checkMethod(EventSubscription eventSubs, String methodName, CommonModule commonModule) {
+ documentContext.getServerContext()
+ .getDocument(commonModule.getMdoReference().getMdoRef(), ModuleType.CommonModule)
+ .ifPresent(commonModuleContext -> {
+ var method = commonModuleContext.getSymbolTree().getMethods().stream()
+ .filter(methodSymbol -> methodSymbol.getName().equalsIgnoreCase(methodName))
+ .findFirst();
+ if (method.isEmpty()) {
+ addDiagnostic("missingMethod", eventSubs, commonModule.getName() + "." + methodName);
+ return;
+ }
+ if (!method.get().isExport()) {
+ addDiagnostic("nonExportMethod", eventSubs, commonModule.getName() + "." + methodName);
+ }
+ });
+ }
+
+ private void addDiagnostic(String messageString, EventSubscription eventSubs, String text) {
+ diagnosticStorage.addDiagnostic(diagnosticRange,
+ info.getResourceString(messageString, text, eventSubs.getName()));
+ }
+
+ private void addDiagnostic(EventSubscription eventSubs) {
+ diagnosticStorage.addDiagnostic(diagnosticRange, info.getMessage(eventSubs.getName()));
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MissingParameterDescriptionDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MissingParameterDescriptionDiagnostic.java
new file mode 100644
index 00000000000..2f9af87e556
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MissingParameterDescriptionDiagnostic.java
@@ -0,0 +1,165 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.diagnostics;
+
+import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodDescription;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.ParameterDefinition;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.description.ParameterDescription;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+import org.apache.commons.collections4.map.CaseInsensitiveMap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@DiagnosticMetadata(
+ type = DiagnosticType.CODE_SMELL,
+ severity = DiagnosticSeverity.MAJOR,
+ minutesToFix = 5,
+ tags = {
+ DiagnosticTag.STANDARD,
+ DiagnosticTag.BADPRACTICE
+ }
+)
+public class MissingParameterDescriptionDiagnostic extends AbstractSymbolTreeDiagnostic {
+
+ /**
+ * Анализируется только методы, имеющие описание
+ * Для удобства кидается несколько разных замечаний
+ */
+ @Override
+ public void visitMethod(MethodSymbol methodSymbol) {
+
+ var description = methodSymbol.getDescription();
+
+ boolean hasDescription = description
+ .map(methodDescription -> !methodDescription.isEmpty())
+ .orElse(false);
+
+ if (!hasDescription) {
+ return;
+ }
+
+ List parameters = methodSymbol.getParameters();
+ List parametersDescriptions = description
+ .map(MethodDescription::getParameters)
+ .orElse(Collections.emptyList());
+
+ // параметров и описания нет, что в принципе не ошибка
+ if (parameters.isEmpty() && parametersDescriptions.isEmpty()) {
+ return;
+ }
+
+ // параметров нет, но есть их описания, что есть ошибка
+ if (parameters.isEmpty()) {
+ addDiagnostic(methodSymbol, parametersDescriptions);
+ return;
+ }
+
+ if (parametersDescriptions.isEmpty()) {
+ if (!description.get().getLink().isEmpty()) {
+ // пока считаем ссылку наличием описания всего и вся
+ return;
+ }
+ // ошибка отсутствует описание всех параметров
+ diagnosticStorage.addDiagnostic(methodSymbol.getSubNameRange());
+ return;
+ }
+
+ // сопоставление параметров и описаний
+ checkParameterDescription(methodSymbol, parameters, parametersDescriptions);
+ }
+
+ private void checkParameterDescription(MethodSymbol methodSymbol,
+ List parameters,
+ List parametersDescriptions) {
+
+ AtomicBoolean hasMissingDescription = new AtomicBoolean(false);
+
+ var parametersDescriptionsCopy = new ArrayList<>(parametersDescriptions);
+ var descriptions = parametersDescriptions.stream()
+ .collect(
+ Collectors.toMap(
+ ParameterDescription::getName,
+ Function.identity(),
+ (first, second) -> first,
+ CaseInsensitiveMap::new));
+
+ parameters.forEach((ParameterDefinition parameter) -> {
+ var description = descriptions.get(parameter.getName());
+ // описание параметра отсутствует как таковое
+ if (description == null) {
+ addDiagnostic(parameter, "missingDescription");
+ hasMissingDescription.set(true);
+ return;
+ }
+
+ // параметр в описании есть, но нет типа и описания типа
+ if (description.getTypes().isEmpty() && description.getDescription().isEmpty()) {
+ addDiagnostic(parameter, "emptyDescription");
+ }
+
+ // найденный параметр удалим из кэша
+ parametersDescriptionsCopy.remove(description);
+ });
+
+ // лишние описания параметров, отсутствующие в сигнатуре
+ if (!parametersDescriptionsCopy.isEmpty()) {
+ hasMissingDescription.set(true);
+ addDiagnostic(methodSymbol, parametersDescriptionsCopy);
+ }
+
+ // проверить порядок параметров в описании
+ // но это имеет смысл только при отсутствии ошибок
+
+ if (!hasMissingDescription.get()) {
+ var paramDescriptionString = parametersDescriptions.stream()
+ .map(ParameterDescription::getName).collect(Collectors.joining(",")).toLowerCase(Locale.ENGLISH);
+ var paramString = parameters.stream()
+ .map(ParameterDefinition::getName).collect(Collectors.joining(",")).toLowerCase(Locale.ENGLISH);
+ // если строки не равны, значит порядок описаний не совпадает
+ if (!paramDescriptionString.equals(paramString)) {
+ diagnosticStorage.addDiagnostic(methodSymbol.getSubNameRange(), info.getResourceString("wrongOrder"));
+ }
+ }
+ }
+
+ private void addDiagnostic(ParameterDefinition parameter, String messageKey) {
+ diagnosticStorage.addDiagnostic(parameter.getRange(), info.getResourceString(messageKey, parameter.getName()));
+ }
+
+ private void addDiagnostic(MethodSymbol methodSymbol, List parametersDescriptions) {
+ var parametersString = parametersDescriptions.stream()
+ .map(ParameterDescription::getName).collect(Collectors.joining(", "));
+ diagnosticStorage.addDiagnostic(
+ methodSymbol.getSubNameRange(),
+ info.getResourceString("missingInSignature", parametersString));
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MissingReturnedValueDescriptionDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MissingReturnedValueDescriptionDiagnostic.java
new file mode 100644
index 00000000000..20672f50e7d
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MissingReturnedValueDescriptionDiagnostic.java
@@ -0,0 +1,100 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.diagnostics;
+
+import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodDescription;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.description.TypeDescription;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@DiagnosticMetadata(
+ type = DiagnosticType.CODE_SMELL,
+ severity = DiagnosticSeverity.MAJOR,
+ minutesToFix = 5,
+ tags = {
+ DiagnosticTag.STANDARD,
+ DiagnosticTag.BADPRACTICE
+ }
+)
+public class MissingReturnedValueDescriptionDiagnostic extends AbstractSymbolTreeDiagnostic {
+
+ /**
+ * Анализируется только методы, имеющие описание
+ * Для удобства кидается несколько разных замечаний
+ */
+ @Override
+ public void visitMethod(MethodSymbol methodSymbol) {
+
+ var description = methodSymbol.getDescription();
+
+ boolean hasDescription = description
+ .map(methodDescription -> !methodDescription.isEmpty())
+ .orElse(false);
+
+ if (!hasDescription) {
+ return;
+ }
+
+ List returnedValueDescription = description
+ .map(MethodDescription::getReturnedValue)
+ .orElse(Collections.emptyList());
+
+ // процедура и описания возвращаемого значения нет, все нормально
+ if (!methodSymbol.isFunction() && returnedValueDescription.isEmpty()) {
+ return;
+ }
+
+ // процедура не должна иметь описания
+ if (!methodSymbol.isFunction()) {
+ diagnosticStorage.addDiagnostic(methodSymbol.getSubNameRange(), info.getResourceString("isProcedure"));
+ return;
+ }
+
+ // функция без описания - ошибка
+ if (returnedValueDescription.isEmpty()) {
+ if (!description.get().getLink().isEmpty()) {
+ // пока считаем ссылку наличием описания всего и вся
+ return;
+ }
+ diagnosticStorage.addDiagnostic(methodSymbol.getSubNameRange(), info.getMessage());
+ return;
+ }
+
+ // тип возвращаемого значения должен иметь описание или быть сложным
+ var typesWithoutDescription = returnedValueDescription.stream()
+ .filter((TypeDescription typeDescription) ->
+ typeDescription.getDescription().isEmpty() && typeDescription.getParameters().isEmpty())
+ .map(TypeDescription::getName)
+ .collect(Collectors.joining(", "));
+ if (!typesWithoutDescription.isEmpty()) {
+ diagnosticStorage.addDiagnostic(methodSymbol.getSubNameRange(),
+ info.getResourceString("typesWithoutDescription", typesWithoutDescription));
+ }
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MissingSpaceDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MissingSpaceDiagnostic.java
index c2d54a4afd7..aef2968c2b7 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MissingSpaceDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MissingSpaceDiagnostic.java
@@ -67,6 +67,19 @@ public class MissingSpaceDiagnostic extends AbstractDiagnostic implements QuickF
private static final String UNARY = "+ - * / = % < > ( [ , Возврат Return <> <= >=";
+ /**
+ * Ключевые слова, требующие пробел слева и справа
+ */
+ private static final Set KEYWORDS_WITH_LEFT_RIGHT_SPACE = computeKeywordsWithLeftRightSpace();
+ /**
+ * Ключевые слова, требующие пробел слева
+ */
+ private static final Set KEYWORDS_WITH_LEFT_SPACE = computeKeywordsWithLeftSpace();
+ /**
+ * Ключевые слова, требующие пробел справа
+ */
+ private static final Set KEYWORDS_WITH_RIGHT_SPACE = computeKeywordsWithRightSpace();
+
@DiagnosticParameter(
type = String.class,
defaultValue = "" + DEFAULT_LIST_FOR_CHECK_LEFT
@@ -128,19 +141,21 @@ public void check() {
String tokenText = token.getText();
// проверяем слева
- if (setL.contains(tokenText) && (noSpaceLeft = noSpaceLeft(tokens, token))) {
+ if ((setL.contains(tokenText) || KEYWORDS_WITH_LEFT_SPACE.contains(token.getType()))
+ && (noSpaceLeft = noSpaceLeft(tokens, token))) {
leftComputed = true;
addDiagnostic(token, mainMessage, indexWordLeftMsg);
}
// проверяем справа
- if (setR.contains(tokenText) && (noSpaceRight = noSpaceRight(tokens, token))) {
+ if ((setR.contains(tokenText) || KEYWORDS_WITH_RIGHT_SPACE.contains(token.getType()))
+ && (noSpaceRight = noSpaceRight(tokens, token))) {
rightComputed = true;
addDiagnostic(token, mainMessage, indexWordRightMsg);
}
// проверяем слева и справа
- if (setLR.contains(tokenText)) {
+ if (setLR.contains(tokenText) || KEYWORDS_WITH_LEFT_RIGHT_SPACE.contains(token.getType())) {
if (!leftComputed) {
noSpaceLeft = noSpaceLeft(tokens, token);
}
@@ -275,4 +290,33 @@ private boolean isUnaryChar(List tokens, Token t) {
private static String getErrorMessage(String formatString, String errorMessage, String tokenText) {
return String.format(formatString, errorMessage, tokenText).intern();
}
+
+ private static Set computeKeywordsWithLeftRightSpace() {
+ return Set.of(
+ BSLParser.TO_KEYWORD,
+ BSLParser.IN_KEYWORD,
+ BSLParser.OR_KEYWORD,
+ BSLParser.AND_KEYWORD
+ );
+ }
+
+ private static Set computeKeywordsWithLeftSpace() {
+ return Set.of(
+ BSLParser.EXPORT_KEYWORD,
+ BSLParser.THEN_KEYWORD,
+ BSLParser.DO_KEYWORD
+ );
+ }
+
+ private static Set computeKeywordsWithRightSpace() {
+ return Set.of(
+ BSLParser.IF_KEYWORD,
+ BSLParser.ELSIF_KEYWORD,
+ BSLParser.WHILE_KEYWORD,
+ BSLParser.FOR_KEYWORD,
+ BSLParser.NOT_KEYWORD,
+ BSLParser.EACH_KEYWORD
+ );
+ }
+
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/NestedFunctionInParametersDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/NestedFunctionInParametersDiagnostic.java
index 4a765ff2b2e..7e5274236e6 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/NestedFunctionInParametersDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/NestedFunctionInParametersDiagnostic.java
@@ -33,7 +33,7 @@
@DiagnosticMetadata(
type = DiagnosticType.CODE_SMELL,
severity = DiagnosticSeverity.MINOR,
- minutesToFix = 5,
+ minutesToFix = 2,
tags = {
DiagnosticTag.STANDARD,
DiagnosticTag.BRAINOVERLOAD,
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/OrdinaryAppSupportDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/OrdinaryAppSupportDiagnostic.java
new file mode 100644
index 00000000000..314bdb1e37f
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/OrdinaryAppSupportDiagnostic.java
@@ -0,0 +1,79 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.diagnostics;
+
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
+import com.github._1c_syntax.mdclasses.metadata.Configuration;
+import com.github._1c_syntax.mdclasses.metadata.additional.ModuleType;
+import lombok.RequiredArgsConstructor;
+import org.eclipse.lsp4j.Range;
+
+@DiagnosticMetadata(
+ type = DiagnosticType.CODE_SMELL,
+ severity = DiagnosticSeverity.MAJOR,
+ scope = DiagnosticScope.BSL,
+ modules = {
+ ModuleType.SessionModule
+ },
+ minutesToFix = 1,
+ tags = {
+ DiagnosticTag.STANDARD,
+ DiagnosticTag.UNPREDICTABLE
+ }
+)
+@RequiredArgsConstructor
+public class OrdinaryAppSupportDiagnostic extends AbstractDiagnostic {
+
+ private final LanguageServerConfiguration serverConfiguration;
+
+ @Override
+ protected void check() {
+
+ if (!serverConfiguration.getDiagnosticsOptions().isOrdinaryAppSupport()) {
+ return;
+ }
+
+ Ranges.getFirstSignificantTokenRange(documentContext.getTokens())
+ .ifPresent(this::checkProperties);
+
+ }
+
+ private void checkProperties(Range range) {
+
+ Configuration configuration = documentContext.getServerContext().getConfiguration();
+ if (!configuration.isUseManagedFormInOrdinaryApplication()) {
+ diagnosticStorage.addDiagnostic(range, info.getResourceString("managedFormInOrdinaryApp"));
+ }
+
+ if (configuration.isUseOrdinaryFormInManagedApplication()) {
+ diagnosticStorage.addDiagnostic(range, info.getResourceString("ordinaryFormInManagedApp"));
+ }
+
+ }
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/RedundantAccessToObjectDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/RedundantAccessToObjectDiagnostic.java
new file mode 100644
index 00000000000..1d1dc5b0434
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/RedundantAccessToObjectDiagnostic.java
@@ -0,0 +1,195 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.diagnostics;
+
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticParameter;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+import com.github._1c_syntax.bsl.parser.BSLParser;
+import com.github._1c_syntax.mdclasses.metadata.additional.MDOType;
+import com.github._1c_syntax.mdclasses.metadata.additional.ModuleType;
+import com.github._1c_syntax.utils.CaseInsensitivePattern;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.eclipse.lsp4j.Diagnostic;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+@DiagnosticMetadata(
+ type = DiagnosticType.CODE_SMELL,
+ severity = DiagnosticSeverity.INFO,
+ minutesToFix = 1,
+ modules = {
+ ModuleType.CommonModule,
+ ModuleType.ObjectModule,
+ ModuleType.ManagerModule,
+ ModuleType.FormModule,
+ ModuleType.RecordSetModule
+ },
+ tags = {
+ DiagnosticTag.STANDARD,
+ DiagnosticTag.CLUMSY
+ },
+ scope = DiagnosticScope.BSL
+)
+public class RedundantAccessToObjectDiagnostic extends AbstractVisitorDiagnostic {
+
+ private static final Pattern PATTERN = CaseInsensitivePattern.compile("^ЭтотОбъект|ThisObject");
+ private static final Pattern PATTERN_WITH_DOT = CaseInsensitivePattern.compile("^(ЭтотОбъект|ThisObject)\\..*");
+
+ private static final boolean CHECK_OBJECT_MODULE = true;
+ private static final boolean CHECK_FORM_MODULE = true;
+ private static final boolean CHECK_RECORD_SET_MODULE = true;
+
+ private boolean needCheckName = false;
+ private boolean skipLValue = false;
+ private Pattern namePattern;
+ private Pattern namePatternWithDot;
+
+ @DiagnosticParameter(
+ type = Boolean.class,
+ defaultValue = "" + CHECK_OBJECT_MODULE
+ )
+ private boolean checkObjectModule = CHECK_OBJECT_MODULE;
+
+ @DiagnosticParameter(
+ type = Boolean.class,
+ defaultValue = "" + CHECK_FORM_MODULE
+ )
+ private boolean checkFormModule = CHECK_FORM_MODULE;
+
+ @DiagnosticParameter(
+ type = Boolean.class,
+ defaultValue = "" + CHECK_RECORD_SET_MODULE
+ )
+ private boolean checkRecordSetModule = CHECK_RECORD_SET_MODULE;
+
+ @Override
+ public List getDiagnostics(DocumentContext documentContext) {
+ var typeModule = documentContext.getModuleType();
+ if (typeModule == ModuleType.CommonModule || typeModule == ModuleType.ManagerModule) {
+ documentContext.getMdObject().ifPresent(mdObjectBase -> {
+ needCheckName = true;
+ skipLValue = true;
+ namePattern = CaseInsensitivePattern.compile(String.format("^%s", mdObjectBase.getName()));
+ namePatternWithDot = CaseInsensitivePattern.compile(
+ String.format(getManagerModuleName(mdObjectBase.getType()), mdObjectBase.getName())
+ );
+ });
+ }
+
+ if (skipModule(typeModule)) {
+ return new ArrayList<>();
+ }
+ return super.getDiagnostics(documentContext);
+ }
+
+ @Override
+ public ParseTree visitCallStatement(BSLParser.CallStatementContext ctx) {
+ if (ctx.globalMethodCall() != null && ctx.getStart() == ctx.globalMethodCall().getStart()) {
+ return super.visitCallStatement(ctx);
+ }
+
+ if (PATTERN_WITH_DOT.matcher(ctx.getText()).matches()) {
+ diagnosticStorage.addDiagnostic(ctx.getStart());
+ }
+
+ if (needCheckName && namePatternWithDot.matcher(ctx.getText()).matches()) {
+ diagnosticStorage.addDiagnostic(ctx.getStart());
+ }
+
+ return super.visitCallStatement(ctx);
+ }
+
+ @Override
+ public ParseTree visitComplexIdentifier(BSLParser.ComplexIdentifierContext ctx) {
+ var identifier = ctx.IDENTIFIER();
+ var modifiers = ctx.modifier();
+
+ if (identifier == null || modifiers.size() == 0) {
+ return ctx;
+ }
+
+ if (PATTERN.matcher(identifier.getText()).matches() && modifiers.get(0) != null) {
+ diagnosticStorage.addDiagnostic(ctx.getStart());
+ }
+
+ if (needCheckName && namePattern.matcher(identifier.getText()).matches() && modifiers.get(0) != null) {
+ diagnosticStorage.addDiagnostic(ctx.getStart());
+ }
+
+ return ctx;
+ }
+
+ @Override
+ public ParseTree visitLValue(BSLParser.LValueContext ctx) {
+ if (skipLValue) {
+ return ctx;
+ }
+
+ var identifier = ctx.IDENTIFIER();
+ var acceptor = ctx.acceptor();
+
+ if (identifier == null || acceptor == null) {
+ return ctx;
+ }
+
+ if (PATTERN.matcher(identifier.getText()).matches() && acceptor.accessProperty() != null) {
+ diagnosticStorage.addDiagnostic(ctx.getStart());
+ }
+
+ if (needCheckName && namePattern.matcher(identifier.getText()).matches() && acceptor.accessProperty() != null) {
+ diagnosticStorage.addDiagnostic(ctx.getStart());
+ }
+
+ return ctx;
+ }
+
+ private static String getManagerModuleName(MDOType objectType) {
+ if (objectType == MDOType.CATALOG) {
+ return "^(Справочники|Catalogs)\\.%s\\..*";
+ } else if (objectType == MDOType.DOCUMENT) {
+ return "^(Документы|Documents)\\.%s\\..*";
+ } else if (objectType == MDOType.ACCOUNTING_REGISTER) {
+ return "^(РегистрыБухгалтерии|AccountingRegisters)\\.%s\\..*";
+ } else if (objectType == MDOType.ACCUMULATION_REGISTER) {
+ return "^(РегистрыНакопления|AccumulationRegisters)\\.%s\\..*";
+ } else if (objectType == MDOType.CALCULATION_REGISTER) {
+ return "^(РегистрыРасчета|CalculationRegisters)\\.%s\\..*";
+ } else if (objectType == MDOType.INFORMATION_REGISTER) {
+ return "^(РегистрыСведений|InformationRegisters)\\.%s\\..*";
+ } else {
+ return "^%s\\..*";
+ }
+ }
+
+ private boolean skipModule(ModuleType typeModule) {
+ return typeModule == ModuleType.ObjectModule && !checkObjectModule
+ || typeModule == ModuleType.RecordSetModule && !checkRecordSetModule
+ || typeModule == ModuleType.FormModule && !checkFormModule;
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/RefOveruseDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/RefOveruseDiagnostic.java
new file mode 100644
index 00000000000..acfc00ebe95
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/RefOveruseDiagnostic.java
@@ -0,0 +1,138 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.diagnostics;
+
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+import com.github._1c_syntax.bsl.languageserver.utils.Trees;
+import com.github._1c_syntax.bsl.parser.BSLParserRuleContext;
+import com.github._1c_syntax.bsl.parser.SDBLParser;
+import com.github._1c_syntax.utils.CaseInsensitivePattern;
+import org.antlr.v4.runtime.tree.ParseTree;
+
+import java.util.Collection;
+import java.util.Optional;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+@DiagnosticMetadata(
+ type = DiagnosticType.CODE_SMELL,
+ severity = DiagnosticSeverity.MAJOR,
+ scope = DiagnosticScope.BSL,
+ minutesToFix = 5,
+ tags = {
+ DiagnosticTag.SQL,
+ DiagnosticTag.PERFORMANCE
+ }
+)
+public class RefOveruseDiagnostic extends AbstractSDBLVisitorDiagnostic {
+
+ private static final String REF_REGEX = "Ссылка|Reference";
+ private static final Pattern REF_PATTERN = CaseInsensitivePattern.compile(REF_REGEX);
+ private static final int BAD_CHILD_COUNT = 3;
+
+ @Override
+ public ParseTree visitQuery(SDBLParser.QueryContext ctx) {
+ var columnsCollection = Trees.findAllRuleNodes(ctx, SDBLParser.RULE_column);
+
+ if (columnsCollection.isEmpty()) {
+ return ctx;
+ }
+
+ var dataSourceCollection = Trees.findAllRuleNodes(ctx, SDBLParser.RULE_dataSource);
+
+ if (dataSourceCollection.stream().anyMatch(Trees::treeContainsErrors)) {
+ return ctx;
+ }
+
+ if (dataSourceCollection.isEmpty()) {
+ performSimpleCheck(columnsCollection);
+ return ctx;
+ }
+
+ Set tableNames = dataSourceCollection.stream()
+ .map(RefOveruseDiagnostic::getTableNameOrAlias)
+ .collect(Collectors.toSet());
+
+ columnsCollection.forEach(column -> checkColumnNode((SDBLParser.ColumnContext) column, tableNames));
+ return ctx;
+
+ }
+
+ private void performSimpleCheck(Collection columnsCollection) {
+ columnsCollection.stream()
+ .filter(columnNode -> columnNode.getChildCount() > BAD_CHILD_COUNT)
+ .map(column -> column.getChild(column.getChildCount() - 1))
+ .filter(lastChild -> REF_PATTERN.matcher(lastChild.getText()).matches())
+ .forEach(node -> diagnosticStorage.addDiagnostic((BSLParserRuleContext) node));
+ }
+
+ private void checkColumnNode(SDBLParser.ColumnContext ctx, Set tableNames) {
+
+ if (ctx.children == null) {
+ return;
+ }
+
+ var lastChild = ctx.getChild(Math.min(ctx.children.size(), ctx.children.size() - 1));
+ var penultimateChild = ctx.getChild(Math.min(ctx.children.size(), ctx.children.size() - 3));
+
+ if (lastChild != penultimateChild
+ && lastChild instanceof SDBLParser.IdentifierContext
+ && penultimateChild instanceof SDBLParser.IdentifierContext) {
+
+ performCheck(ctx, (SDBLParser.IdentifierContext) lastChild,
+ (SDBLParser.IdentifierContext) penultimateChild, tableNames);
+ }
+
+ }
+
+ private void performCheck(SDBLParser.ColumnContext ctx, SDBLParser.IdentifierContext lastChild,
+ SDBLParser.IdentifierContext penultimateChild, Set tableNames) {
+
+ if (!tableNames.contains(penultimateChild.getText()) &&
+ REF_PATTERN.matcher(lastChild.getText()).matches()) {
+ diagnosticStorage.addDiagnostic(ctx);
+ }
+ }
+
+ private static String getTableNameOrAlias(ParseTree dataSource) {
+ return Optional.of(dataSource)
+ .flatMap(dataSrc -> extractTextFromChild(dataSrc, SDBLParser.RULE_alias))
+ .or(() -> Optional.of(dataSource)
+ .flatMap(dataSrc -> extractTextFromChild(dataSrc, SDBLParser.RULE_table)))
+ .or(() -> Optional.of(dataSource)
+ .flatMap(dataSrc -> extractTextFromChild(dataSrc, SDBLParser.RULE_parameterTable)))
+ .orElse("");
+ }
+
+ private static Optional extractTextFromChild(ParseTree parseTree, int childRuleType) {
+ return Optional.of(parseTree)
+ .flatMap(tree -> Trees.getFirstChild(tree, childRuleType))
+ .flatMap(child -> Trees.getFirstChild(child, SDBLParser.RULE_identifier))
+ .map(BSLParserRuleContext::getText);
+ }
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/TypoDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/TypoDiagnostic.java
index 9e70380761a..35698328f91 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/TypoDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/TypoDiagnostic.java
@@ -73,7 +73,6 @@ public class TypoDiagnostic extends AbstractDiagnostic {
private static final Pattern SPACES_PATTERN = Pattern.compile("\\s+");
private static final Pattern QUOTE_PATTERN = Pattern.compile("\"");
- private static final Pattern NEWLINE_PATTERN = Pattern.compile("\\n");
private static final Integer[] rulesToFind = new Integer[]{
BSLParser.RULE_string,
@@ -107,15 +106,15 @@ public void configure(Map configuration) {
}
private String getWordsToIgnore() {
- String exceptions = NEWLINE_PATTERN.matcher(info.getResourceString("diagnosticExceptions")).replaceAll("");
+ String exceptions = SPACES_PATTERN.matcher(info.getResourceString("diagnosticExceptions")).replaceAll("");
if (!userWordsToIgnore.isEmpty()) {
- exceptions = exceptions + "," + NEWLINE_PATTERN.matcher(userWordsToIgnore).replaceAll("");
+ exceptions = exceptions + "," + SPACES_PATTERN.matcher(userWordsToIgnore).replaceAll("");
}
return exceptions.intern();
}
- private JLanguageToolPoolEntry acquireLanguageTool(String lang) {
+ JLanguageToolPoolEntry acquireLanguageTool(String lang) {
return getLanguageToolPoolMap().get(lang).checkOut();
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnusedLocalMethodDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnusedLocalMethodDiagnostic.java
index aaf2633ecd8..f380552ed17 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnusedLocalMethodDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnusedLocalMethodDiagnostic.java
@@ -52,7 +52,8 @@
minutesToFix = 1,
tags = {
DiagnosticTag.STANDARD,
- DiagnosticTag.SUSPICIOUS
+ DiagnosticTag.SUSPICIOUS,
+ DiagnosticTag.UNUSED
}
)
public class UnusedLocalMethodDiagnostic extends AbstractVisitorDiagnostic {
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnusedParametersDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnusedParametersDiagnostic.java
index 76e1b788ab3..e19b4c8d178 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnusedParametersDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnusedParametersDiagnostic.java
@@ -43,9 +43,11 @@
severity = DiagnosticSeverity.MAJOR,
scope = DiagnosticScope.OS,
minutesToFix = 5,
- tags = {DiagnosticTag.DESIGN}
+ tags = {
+ DiagnosticTag.DESIGN,
+ DiagnosticTag.UNUSED
+ }
)
-
public class UnusedParametersDiagnostic extends AbstractVisitorDiagnostic {
private static final Pattern HANDLER_PATTERN = CaseInsensitivePattern.compile(
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UsingModalWindowsDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UsingModalWindowsDiagnostic.java
index e74bca64582..9b7d8f3b3bd 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UsingModalWindowsDiagnostic.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UsingModalWindowsDiagnostic.java
@@ -23,6 +23,7 @@
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticCompatibilityMode;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticParameter;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
@@ -58,6 +59,12 @@ public class UsingModalWindowsDiagnostic extends AbstractVisitorDiagnostic {
private final HashMap pairMethods = new HashMap<>();
+ @DiagnosticParameter(
+ type = Boolean.class,
+ defaultValue = "false"
+ )
+ private boolean forceModalityMode;
+
public UsingModalWindowsDiagnostic() {
pairMethods.put("ВОПРОС", "ПоказатьВопрос");
pairMethods.put("DOQUERYBOX", "ShowQueryBox");
@@ -88,9 +95,10 @@ public UsingModalWindowsDiagnostic() {
@Override
public ParseTree visitFile(BSLParser.FileContext ctx) {
var configuration = documentContext.getServerContext().getConfiguration();
- // если использование модальных окон разрешено (без предупреждение), то
+ // если использование модальных окон разрешено (без предупреждение)
+ // и не установлен флаг игнорирования использования модальных окон, то
// ничего не диагностируется
- if (configuration.getModalityUseMode() == UseMode.USE) {
+ if (!forceModalityMode && configuration.getModalityUseMode() == UseMode.USE) {
return ctx;
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/metadata/DiagnosticInfo.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/metadata/DiagnosticInfo.java
index 34c8a04e13f..e41cdac8c8e 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/metadata/DiagnosticInfo.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/metadata/DiagnosticInfo.java
@@ -36,6 +36,7 @@
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -44,6 +45,7 @@ public class DiagnosticInfo {
private static final Map severityToLSPSeverityMap
= createSeverityToLSPSeverityMap();
+ private static final Map diagnosticTagMap = createDiagnosticTagMap();
private final Class extends BSLDiagnostic> diagnosticClass;
private final LanguageServerConfiguration configuration;
@@ -154,6 +156,13 @@ public List getTags() {
return new ArrayList<>(Arrays.asList(diagnosticMetadata.tags()));
}
+ public List getLSPTags() {
+ return getTags().stream()
+ .map(diagnosticTag -> diagnosticTagMap.getOrDefault(diagnosticTag, null))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
public List getParameters() {
return new ArrayList<>(diagnosticParameters);
}
@@ -186,4 +195,11 @@ private static Map cre
return map;
}
+
+ private static Map createDiagnosticTagMap() {
+ return Map.of(
+ DiagnosticTag.UNUSED, org.eclipse.lsp4j.DiagnosticTag.Unnecessary,
+ DiagnosticTag.DEPRECATED, org.eclipse.lsp4j.DiagnosticTag.Deprecated
+ );
+ }
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/metadata/DiagnosticTag.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/metadata/DiagnosticTag.java
index 99161a06208..be9b5861072 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/metadata/DiagnosticTag.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/metadata/DiagnosticTag.java
@@ -33,6 +33,7 @@ public enum DiagnosticTag {
SUSPICIOUS("Подозрительный код"),
UNPREDICTABLE("Непредсказуемо работающий код"),
DEPRECATED("Устаревшая функциональность"),
+ UNUSED("Неиспользуемый код"),
ERROR("Ошибочная конструкция"),
LOCALIZE("Проблемы локализации");
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/AbstractCommentFoldingRangeSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/AbstractCommentFoldingRangeSupplier.java
new file mode 100644
index 00000000000..505c0bcbd1a
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/AbstractCommentFoldingRangeSupplier.java
@@ -0,0 +1,78 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.folding;
+
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import org.antlr.v4.runtime.Token;
+import org.eclipse.lsp4j.FoldingRange;
+import org.eclipse.lsp4j.FoldingRangeKind;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Абстрактный сапплаер для получения областей сворачивания комментариев.
+ */
+public abstract class AbstractCommentFoldingRangeSupplier implements FoldingRangeSupplier {
+
+ @Override
+ public List getFoldingRanges(DocumentContext documentContext) {
+ List foldingRanges = new ArrayList<>();
+
+ List comments = getComments(documentContext);
+
+ int lastRangeStart = -1;
+ int previousLine = -1;
+
+ for (Token token : comments) {
+ int tokenLine = token.getLine();
+
+ if (tokenLine != previousLine + 1) {
+ if (lastRangeStart != previousLine) {
+ FoldingRange foldingRange = new FoldingRange(lastRangeStart - 1, previousLine - 1);
+ foldingRange.setKind(FoldingRangeKind.Comment);
+
+ foldingRanges.add(foldingRange);
+ }
+ // new range
+ lastRangeStart = tokenLine;
+ }
+
+ previousLine = tokenLine;
+ }
+
+ // add last range
+ if (lastRangeStart != previousLine) {
+ FoldingRange foldingRange = new FoldingRange(lastRangeStart - 1, previousLine - 1);
+ foldingRange.setKind(FoldingRangeKind.Comment);
+
+ foldingRanges.add(foldingRange);
+ }
+ return foldingRanges;
+ }
+
+ /**
+ * @param documentContext Контекст документа, для которого надо получить список комментариев
+ * @return Список токенов-комментариев
+ */
+ protected abstract List getComments(DocumentContext documentContext);
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/CodeBlockFoldingRangeSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/CodeBlockFoldingRangeSupplier.java
new file mode 100644
index 00000000000..3c179796378
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/CodeBlockFoldingRangeSupplier.java
@@ -0,0 +1,115 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.folding;
+
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import com.github._1c_syntax.bsl.parser.BSLParser;
+import com.github._1c_syntax.bsl.parser.BSLParserBaseVisitor;
+import lombok.Getter;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.TerminalNode;
+import org.eclipse.lsp4j.FoldingRange;
+import org.eclipse.lsp4j.FoldingRangeKind;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.CheckForNull;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Сапплаер областей сворачивания блоков кода: методов, условий, циклов, попыток.
+ */
+@Component
+public class CodeBlockFoldingRangeSupplier implements FoldingRangeSupplier {
+
+ @Override
+ public List getFoldingRanges(DocumentContext documentContext) {
+ CodeBlockVisitor codeBlockVisitor = new CodeBlockVisitor();
+ codeBlockVisitor.visitFile(documentContext.getAst());
+ return codeBlockVisitor.getRegionRanges();
+ }
+
+ private static class CodeBlockVisitor extends BSLParserBaseVisitor {
+
+ @Getter
+ private final List regionRanges = new ArrayList<>();
+
+ @Override
+ public ParseTree visitProcedure(BSLParser.ProcedureContext ctx) {
+ addRegionRange(ctx.procDeclaration().PROCEDURE_KEYWORD(), ctx.ENDPROCEDURE_KEYWORD());
+ return super.visitProcedure(ctx);
+ }
+
+ @Override
+ public ParseTree visitFunction(BSLParser.FunctionContext ctx) {
+ addRegionRange(ctx.funcDeclaration().FUNCTION_KEYWORD(), ctx.ENDFUNCTION_KEYWORD());
+ return super.visitFunction(ctx);
+ }
+
+ @Override
+ public ParseTree visitIfStatement(BSLParser.IfStatementContext ctx) {
+ addRegionRange(ctx.ifBranch().IF_KEYWORD(), ctx.ENDIF_KEYWORD());
+ return super.visitIfStatement(ctx);
+ }
+
+ @Override
+ public ParseTree visitWhileStatement(BSLParser.WhileStatementContext ctx) {
+ addRegionRange(ctx.WHILE_KEYWORD(), ctx.ENDDO_KEYWORD());
+ return super.visitWhileStatement(ctx);
+ }
+
+ @Override
+ public ParseTree visitForStatement(BSLParser.ForStatementContext ctx) {
+ addRegionRange(ctx.FOR_KEYWORD(), ctx.ENDDO_KEYWORD());
+ return super.visitForStatement(ctx);
+ }
+
+ @Override
+ public ParseTree visitForEachStatement(BSLParser.ForEachStatementContext ctx) {
+ addRegionRange(ctx.FOR_KEYWORD(), ctx.ENDDO_KEYWORD());
+ return super.visitForEachStatement(ctx);
+ }
+
+ @Override
+ public ParseTree visitTryStatement(BSLParser.TryStatementContext ctx) {
+ addRegionRange(ctx.TRY_KEYWORD(), ctx.ENDTRY_KEYWORD());
+ return super.visitTryStatement(ctx);
+ }
+
+ private void addRegionRange(@CheckForNull TerminalNode start, @CheckForNull TerminalNode stop) {
+ if (start == null || stop == null) {
+ return;
+ }
+
+ int startLine = start.getSymbol().getLine();
+ int stopLine = stop.getSymbol().getLine();
+
+ if (stopLine > startLine) {
+ FoldingRange foldingRange = new FoldingRange(startLine - 1, stopLine - 1);
+ foldingRange.setKind(FoldingRangeKind.Region);
+
+ regionRanges.add(foldingRange);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/CommentFoldingRangeSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/CommentFoldingRangeSupplier.java
new file mode 100644
index 00000000000..987b08ba40b
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/CommentFoldingRangeSupplier.java
@@ -0,0 +1,41 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.folding;
+
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import org.antlr.v4.runtime.Token;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * Сапплаер областей сворачивания блоков комментариев.
+ */
+@Component
+public class CommentFoldingRangeSupplier extends AbstractCommentFoldingRangeSupplier {
+
+ @Override
+ protected List getComments(DocumentContext documentContext) {
+ return documentContext.getComments();
+ }
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/FoldingRangeSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/FoldingRangeSupplier.java
new file mode 100644
index 00000000000..48aebd214b6
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/FoldingRangeSupplier.java
@@ -0,0 +1,39 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.folding;
+
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import org.eclipse.lsp4j.FoldingRange;
+
+import java.util.List;
+
+/**
+ * Базовый интерфейс для наполнения {@link com.github._1c_syntax.bsl.languageserver.providers.FoldingRangeProvider}
+ * данными о областях сворачивания.
+ */
+public interface FoldingRangeSupplier {
+ /**
+ * @param documentContext Контекст документа, для которого надо рассчитать области сворачивания
+ * @return Список областей сворачивания
+ */
+ List getFoldingRanges(DocumentContext documentContext);
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/PreprocIfFoldingRangeSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/PreprocIfFoldingRangeSupplier.java
new file mode 100644
index 00000000000..ff46bd3dc0f
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/PreprocIfFoldingRangeSupplier.java
@@ -0,0 +1,83 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.folding;
+
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import com.github._1c_syntax.bsl.parser.BSLParser;
+import com.github._1c_syntax.bsl.parser.BSLParserBaseVisitor;
+import lombok.Getter;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.eclipse.lsp4j.FoldingRange;
+import org.eclipse.lsp4j.FoldingRangeKind;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.List;
+
+/**
+ * Сапплаер областей сворачивания инструкций препроцессору #Если ... #КонецЕсли
.
+ */
+@Component
+public class PreprocIfFoldingRangeSupplier implements FoldingRangeSupplier {
+
+ @Override
+ public List getFoldingRanges(DocumentContext documentContext) {
+ PreprocIfVisitor preprocIfVisitor = new PreprocIfVisitor();
+ preprocIfVisitor.visitFile(documentContext.getAst());
+ return preprocIfVisitor.getRegionRanges();
+ }
+
+ private static class PreprocIfVisitor extends BSLParserBaseVisitor {
+
+ @Getter
+ private final List regionRanges = new ArrayList<>();
+ private final Deque preprocIfRegionStack = new ArrayDeque<>();
+
+ @Override
+ public ParseTree visitPreproc_if(BSLParser.Preproc_ifContext ctx) {
+ preprocIfRegionStack.push(ctx);
+ return super.visitPreproc_if(ctx);
+ }
+
+ @Override
+ public ParseTree visitPreproc_endif(BSLParser.Preproc_endifContext ctx) {
+
+ if (preprocIfRegionStack.isEmpty()) {
+ return super.visitPreproc_endif(ctx);
+ }
+
+ BSLParser.Preproc_ifContext regionStart = preprocIfRegionStack.pop();
+
+ int start = regionStart.getStart().getLine();
+ int stop = ctx.getStop().getLine();
+
+ FoldingRange foldingRange = new FoldingRange(start - 1, stop - 1);
+ foldingRange.setKind(FoldingRangeKind.Region);
+
+ regionRanges.add(foldingRange);
+
+ return super.visitPreproc_endif(ctx);
+ }
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/QueryCommentFoldingRangeSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/QueryCommentFoldingRangeSupplier.java
new file mode 100644
index 00000000000..aaae541d8f8
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/QueryCommentFoldingRangeSupplier.java
@@ -0,0 +1,51 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.folding;
+
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import com.github._1c_syntax.bsl.parser.SDBLLexer;
+import com.github._1c_syntax.bsl.parser.Tokenizer;
+import org.antlr.v4.runtime.Token;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Сапплаер областей сворачивания блоков комментариев в тексте запроса.
+ */
+@Component
+public class QueryCommentFoldingRangeSupplier extends AbstractCommentFoldingRangeSupplier {
+
+ @Override
+ protected List getComments(DocumentContext documentContext) {
+ return documentContext.getQueries().stream()
+ .map(Tokenizer::getTokens)
+ .flatMap(Collection::stream)
+ .filter(token -> token.getType() == SDBLLexer.LINE_COMMENT)
+ .sorted(Comparator.comparing(Token::getLine))
+ .collect(Collectors.toList());
+ }
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/QueryPackageFoldingRangeSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/QueryPackageFoldingRangeSupplier.java
new file mode 100644
index 00000000000..0f7e2192cbe
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/QueryPackageFoldingRangeSupplier.java
@@ -0,0 +1,61 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.folding;
+
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import com.github._1c_syntax.bsl.parser.SDBLParser;
+import com.github._1c_syntax.bsl.parser.Tokenizer;
+import org.eclipse.lsp4j.FoldingRange;
+import org.eclipse.lsp4j.FoldingRangeKind;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Сапплаер областей сворачивания для пакетов запросов.
+ */
+@Component
+public class QueryPackageFoldingRangeSupplier implements FoldingRangeSupplier {
+
+ @Override
+ public List getFoldingRanges(DocumentContext documentContext) {
+ return documentContext.getQueries().stream()
+ .map(Tokenizer::getAst)
+ .map(SDBLParser.QueryPackageContext::queries)
+ .flatMap(Collection::stream)
+ .map(QueryPackageFoldingRangeSupplier::toFoldingRange)
+ .filter(foldingRange -> foldingRange.getStartLine() != foldingRange.getEndLine())
+ .collect(Collectors.toList());
+ }
+
+ private static FoldingRange toFoldingRange(SDBLParser.QueriesContext queriesContext) {
+ FoldingRange foldingRange = new FoldingRange(
+ queriesContext.getStart().getLine() - 1,
+ queriesContext.getStop().getLine() - 1
+ );
+ foldingRange.setKind(FoldingRangeKind.Region);
+ return foldingRange;
+ }
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/RegionFoldingRangeSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/RegionFoldingRangeSupplier.java
new file mode 100644
index 00000000000..7999ed4a8f8
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/RegionFoldingRangeSupplier.java
@@ -0,0 +1,57 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.folding;
+
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.RegionSymbol;
+import org.eclipse.lsp4j.FoldingRange;
+import org.eclipse.lsp4j.FoldingRangeKind;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Сапплаер областей сворачивания областей (#Область ... #КонецОбласти
).
+ */
+@Component
+public class RegionFoldingRangeSupplier implements FoldingRangeSupplier {
+
+ @Override
+ public List getFoldingRanges(DocumentContext documentContext) {
+ return documentContext.getSymbolTree().getRegionsFlat().stream()
+ .map(RegionFoldingRangeSupplier::toFoldingRange)
+ .collect(Collectors.toList());
+ }
+
+ private static FoldingRange toFoldingRange(RegionSymbol regionSymbol) {
+
+ FoldingRange foldingRange = new FoldingRange(
+ regionSymbol.getStartRange().getStart().getLine(),
+ regionSymbol.getEndRange().getEnd().getLine()
+ );
+ foldingRange.setKind(FoldingRangeKind.Region);
+
+ return foldingRange;
+ }
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/UseFoldingRangeSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/UseFoldingRangeSupplier.java
new file mode 100644
index 00000000000..126e083b6c5
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/UseFoldingRangeSupplier.java
@@ -0,0 +1,59 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.folding;
+
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import com.github._1c_syntax.bsl.languageserver.utils.Trees;
+import com.github._1c_syntax.bsl.parser.BSLParser;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.eclipse.lsp4j.FoldingRange;
+import org.eclipse.lsp4j.FoldingRangeKind;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Сапплаер областей сворачивания импортов библиотек OneScript (#Использовать ...
).
+ */
+@Component
+public class UseFoldingRangeSupplier implements FoldingRangeSupplier {
+
+ @Override
+ public List getFoldingRanges(DocumentContext documentContext) {
+ BSLParser.FileContext fileContext = documentContext.getAst();
+ ParseTree[] uses = Trees.findAllRuleNodes(fileContext, BSLParser.RULE_use).toArray(new ParseTree[0]);
+
+ if (uses.length <= 1) {
+ return Collections.emptyList();
+ }
+
+ int start = ((BSLParser.UseContext) uses[0]).getStart().getLine();
+ int stop = ((BSLParser.UseContext) uses[uses.length - 1]).getStop().getLine();
+
+ FoldingRange foldingRange = new FoldingRange(start - 1, stop - 1);
+ foldingRange.setKind(FoldingRangeKind.Imports);
+
+ return Collections.singletonList(foldingRange);
+ }
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/package-info.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/package-info.java
new file mode 100644
index 00000000000..74dd0f0193c
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/package-info.java
@@ -0,0 +1,29 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+/**
+ * Пакет предназначен для реализации различных видов сворачивания ("folding"),
+ * используемых {@link com.github._1c_syntax.bsl.languageserver.providers.FoldingRangeProvider}.
+ */
+@ParametersAreNonnullByDefault
+package com.github._1c_syntax.bsl.languageserver.folding;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/jsonrpc/Diagnostics.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/jsonrpc/Diagnostics.java
new file mode 100644
index 00000000000..fe8ad6b3ffa
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/jsonrpc/Diagnostics.java
@@ -0,0 +1,52 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server 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.
+ *
+ * BSL Language Server 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 BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.jsonrpc;
+
+import lombok.Value;
+import org.eclipse.lsp4j.Diagnostic;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Ответ на запрос textDocument/x-diagnostics
.
+ *
+ * См. {@link com.github._1c_syntax.bsl.languageserver.BSLTextDocumentService#diagnostics(DiagnosticParams)}
+ */
+@Value
+public class Diagnostics {
+
+ /**
+ * Пустой ответ.
+ */
+ public static final Diagnostics EMPTY = new Diagnostics(Collections.emptyList(), 0);
+
+ /**
+ * Список рассчитанных диагностик документа.
+ */
+ List diagnostics;
+
+ /**
+ * Версия документа, для которого были рассчитаны диагностики.
+ */
+ Integer version;
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/jsonrpc/ProtocolExtension.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/jsonrpc/ProtocolExtension.java
index db0547e46cd..1cb7561974c 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/jsonrpc/ProtocolExtension.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/jsonrpc/ProtocolExtension.java
@@ -21,22 +21,20 @@
*/
package com.github._1c_syntax.bsl.languageserver.jsonrpc;
-import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
-import java.util.List;
import java.util.concurrent.CompletableFuture;
public interface ProtocolExtension {
/**
* @param params Параметры запроса.
- * @return Список диагностик.
+ * @return Список рассчитанных диагностик.
*/
@JsonRequest(
value = "textDocument/x-diagnostics",
useSegment = false
)
- CompletableFuture> diagnostics(DiagnosticParams params);
+ CompletableFuture diagnostics(DiagnosticParams params);
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/CodeActionProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/CodeActionProvider.java
index 441e4690ebc..e4dca5e0282 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/CodeActionProvider.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/CodeActionProvider.java
@@ -39,6 +39,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.stream.Collectors;
@Component
@@ -72,6 +73,9 @@ public static List createCodeActions(
codeAction.setDiagnostics(diagnostics);
codeAction.setEdit(edit);
codeAction.setKind(CodeActionKind.QuickFix);
+ if (diagnostics.size() == 1) {
+ codeAction.setIsPreferred(Boolean.TRUE);
+ }
return Collections.singletonList(codeAction);
@@ -82,8 +86,12 @@ public List> getCodeActions(
DocumentContext documentContext
) {
+ List only = Optional.ofNullable(params.getContext().getOnly())
+ .orElse(Collections.emptyList());
+
return codeActionSuppliers.stream()
.flatMap(codeActionSupplier -> codeActionSupplier.getCodeActions(params, documentContext).stream())
+ .filter(codeAction -> only.isEmpty() || only.contains(codeAction.getKind()))
.map(Either::forRight)
.collect(Collectors.toList());
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/CodeLensProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/CodeLensProvider.java
index 832a2375777..cc151602887 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/CodeLensProvider.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/CodeLensProvider.java
@@ -21,76 +21,25 @@
*/
package com.github._1c_syntax.bsl.languageserver.providers;
-import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
+import com.github._1c_syntax.bsl.languageserver.codelenses.CodeLensSupplier;
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
-import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
import lombok.RequiredArgsConstructor;
import org.eclipse.lsp4j.CodeLens;
-import org.eclipse.lsp4j.Command;
import org.springframework.stereotype.Component;
-import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
-import java.util.Map;
+import java.util.stream.Collectors;
@Component
@RequiredArgsConstructor
public final class CodeLensProvider {
-
- private final LanguageServerConfiguration configuration;
+ private final List codeLensSuppliers;
public List getCodeLens(DocumentContext documentContext) {
- List codeLenses = new ArrayList<>();
- codeLenses.addAll(getCognitiveComplexityCodeLenses(documentContext));
- codeLenses.addAll(getCyclomaticComplexityCodeLenses(documentContext));
- return codeLenses;
- }
-
- private List getCognitiveComplexityCodeLenses(DocumentContext documentContext) {
- List codeLenses = new ArrayList<>();
-
- if (configuration.getCodeLensOptions().isShowCognitiveComplexity()) {
- Map methodsComplexity = documentContext.getCognitiveComplexityData()
- .getMethodsComplexity();
-
- methodsComplexity.forEach((MethodSymbol methodSymbol, Integer complexity) -> {
- String title = String.format("Cognitive complexity is %d", complexity);
- Command command = new Command(title, "");
- CodeLens codeLens = new CodeLens(
- methodSymbol.getSubNameRange(),
- command,
- null
- );
-
- codeLenses.add(codeLens);
- });
- }
-
- return codeLenses;
+ return codeLensSuppliers.stream()
+ .map(codeLensSupplier -> codeLensSupplier.getCodeLenses(documentContext))
+ .flatMap(Collection::stream)
+ .collect(Collectors.toList());
}
-
- private List getCyclomaticComplexityCodeLenses(DocumentContext documentContext) {
- List codeLenses = new ArrayList<>();
-
- if (configuration.getCodeLensOptions().isShowCyclomaticComplexity()) {
-
- Map methodsComplexity = documentContext.getCyclomaticComplexityData()
- .getMethodsComplexity();
-
- methodsComplexity.forEach((MethodSymbol methodSymbol, Integer complexity) -> {
- String title = String.format("Cyclomatic complexity is %d", complexity);
- Command command = new Command(title, "");
- CodeLens codeLens = new CodeLens(
- methodSymbol.getSubNameRange(),
- command,
- null
- );
-
- codeLenses.add(codeLens);
- });
- }
-
- return codeLenses;
- }
-
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java
index 1f710655185..8e6132a176f 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java
@@ -27,28 +27,45 @@
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.PublishDiagnosticsParams;
import org.eclipse.lsp4j.services.LanguageClient;
+import org.eclipse.lsp4j.services.LanguageClientAware;
import org.springframework.stereotype.Component;
+import javax.annotation.CheckForNull;
import java.util.Collections;
import java.util.List;
+import java.util.function.Supplier;
@Slf4j
@Component
@RequiredArgsConstructor
-public final class DiagnosticProvider {
+public final class DiagnosticProvider implements LanguageClientAware {
public static final String SOURCE = "bsl-language-server";
- public void computeAndPublishDiagnostics(LanguageClient client, DocumentContext documentContext) {
- List diagnostics = documentContext.getDiagnostics();
+ @CheckForNull
+ private LanguageClient client;
- client.publishDiagnostics(new PublishDiagnosticsParams(documentContext.getUri().toString(), diagnostics));
+ public void computeAndPublishDiagnostics(DocumentContext documentContext) {
+ publishDiagnostics(documentContext, documentContext::getDiagnostics);
}
- public void publishEmptyDiagnosticList(LanguageClient client, DocumentContext documentContext) {
+ public void publishEmptyDiagnosticList(DocumentContext documentContext) {
+ publishDiagnostics(documentContext, Collections::emptyList);
+ }
+
+ private void publishDiagnostics(DocumentContext documentContext, Supplier> diagnostics) {
+ if (client == null) {
+ return;
+ }
+
client.publishDiagnostics(
- new PublishDiagnosticsParams(documentContext.getUri().toString(), Collections.emptyList())
+ new PublishDiagnosticsParams(documentContext.getUri().toString(), diagnostics.get(), documentContext.getVersion())
);
}
+ @Override
+ public void connect(LanguageClient client) {
+ this.client = client;
+ }
+
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/FoldingRangeProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/FoldingRangeProvider.java
index d32f7bb7c70..fa2502a6daa 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/FoldingRangeProvider.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/FoldingRangeProvider.java
@@ -22,243 +22,26 @@
package com.github._1c_syntax.bsl.languageserver.providers;
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
-import com.github._1c_syntax.bsl.languageserver.context.symbol.RegionSymbol;
-import com.github._1c_syntax.bsl.languageserver.utils.Trees;
-import com.github._1c_syntax.bsl.parser.BSLParser;
-import com.github._1c_syntax.bsl.parser.BSLParserBaseVisitor;
-import org.antlr.v4.runtime.Token;
-import org.antlr.v4.runtime.tree.ParseTree;
-import org.antlr.v4.runtime.tree.TerminalNode;
+import com.github._1c_syntax.bsl.languageserver.folding.FoldingRangeSupplier;
+import lombok.RequiredArgsConstructor;
import org.eclipse.lsp4j.FoldingRange;
-import org.eclipse.lsp4j.FoldingRangeKind;
import org.springframework.stereotype.Component;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Deque;
+import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
@Component
+@RequiredArgsConstructor
public final class FoldingRangeProvider {
- public List getFoldingRange(DocumentContext documentContext) {
-
- List foldingRanges = getCommentRanges(documentContext);
-
- CodeBlockRangeFinder codeBlockRangeFinder = new CodeBlockRangeFinder();
- codeBlockRangeFinder.visitFile(documentContext.getAst());
- List codeBlockRegionRanges = codeBlockRangeFinder.getRegionRanges();
-
- UseRangeFinder useRangeFinder = new UseRangeFinder();
- useRangeFinder.visitFile(documentContext.getAst());
- List useRegionRanges = useRangeFinder.getRegionRanges();
-
- RegionRangeFinder regionRangeFinder = new RegionRangeFinder(documentContext);
- List regionRanges = regionRangeFinder.getRegionRanges();
-
- PreprocIfRegionRangeFinder preprocIfRegionRangeFinder = new PreprocIfRegionRangeFinder();
- preprocIfRegionRangeFinder.visitFile(documentContext.getAst());
- List preprocRegionRanges = preprocIfRegionRangeFinder.getRegionRanges();
-
- foldingRanges.addAll(codeBlockRegionRanges);
- foldingRanges.addAll(useRegionRanges);
- foldingRanges.addAll(regionRanges);
- foldingRanges.addAll(preprocRegionRanges);
-
- return foldingRanges;
- }
-
- private List getCommentRanges(DocumentContext documentContext) {
- List foldingRanges = new ArrayList<>();
-
- int lastRangeStart = -1;
- int previousLine = -1;
- List comments = documentContext.getComments();
- for (Token token : comments) {
- int tokenLine = token.getLine();
-
- if (tokenLine != previousLine + 1) {
- if (lastRangeStart != previousLine) {
- FoldingRange foldingRange = new FoldingRange(lastRangeStart - 1, previousLine - 1);
- foldingRange.setKind(FoldingRangeKind.Comment);
-
- foldingRanges.add(foldingRange);
- }
- // new range
- lastRangeStart = tokenLine;
- }
-
- previousLine = tokenLine;
- }
-
- // add last range
- if (lastRangeStart != previousLine) {
- FoldingRange foldingRange = new FoldingRange(lastRangeStart - 1, previousLine - 1);
- foldingRange.setKind(FoldingRangeKind.Comment);
-
- foldingRanges.add(foldingRange);
- }
- return foldingRanges;
- }
-
- private static class UseRangeFinder extends BSLParserBaseVisitor {
-
- private final List regionRanges = new ArrayList<>();
-
- public List getRegionRanges() {
- return new ArrayList<>(regionRanges);
- }
-
- @Override
- public ParseTree visitFile(BSLParser.FileContext ctx) {
- ParseTree[] uses = Trees.findAllRuleNodes(ctx, BSLParser.RULE_use).toArray(new ParseTree[0]);
-
- if (uses.length <= 1) {
- return ctx;
- }
-
- int start = ((BSLParser.UseContext) uses[0]).getStart().getLine();
- int stop = ((BSLParser.UseContext) uses[uses.length - 1]).getStop().getLine();
-
- FoldingRange foldingRange = new FoldingRange(start - 1, stop - 1);
- foldingRange.setKind(FoldingRangeKind.Imports);
-
- regionRanges.add(foldingRange);
-
- return ctx;
- }
-
- }
-
- private static class CodeBlockRangeFinder extends BSLParserBaseVisitor {
-
- private final List regionRanges = new ArrayList<>();
-
- public List getRegionRanges() {
- return new ArrayList<>(regionRanges);
- }
-
- @Override
- public ParseTree visitProcedure(BSLParser.ProcedureContext ctx) {
- addRegionRange(ctx.procDeclaration().PROCEDURE_KEYWORD(), ctx.ENDPROCEDURE_KEYWORD());
- return super.visitProcedure(ctx);
- }
-
- @Override
- public ParseTree visitFunction(BSLParser.FunctionContext ctx) {
- addRegionRange(ctx.funcDeclaration().FUNCTION_KEYWORD(), ctx.ENDFUNCTION_KEYWORD());
- return super.visitFunction(ctx);
- }
-
- @Override
- public ParseTree visitIfStatement(BSLParser.IfStatementContext ctx) {
- addRegionRange(ctx.ifBranch().IF_KEYWORD(), ctx.ENDIF_KEYWORD());
- return super.visitIfStatement(ctx);
- }
-
- @Override
- public ParseTree visitWhileStatement(BSLParser.WhileStatementContext ctx) {
- addRegionRange(ctx.WHILE_KEYWORD(), ctx.ENDDO_KEYWORD());
- return super.visitWhileStatement(ctx);
- }
-
- @Override
- public ParseTree visitForStatement(BSLParser.ForStatementContext ctx) {
- addRegionRange(ctx.FOR_KEYWORD(), ctx.ENDDO_KEYWORD());
- return super.visitForStatement(ctx);
- }
-
- @Override
- public ParseTree visitForEachStatement(BSLParser.ForEachStatementContext ctx) {
- addRegionRange(ctx.FOR_KEYWORD(), ctx.ENDDO_KEYWORD());
- return super.visitForEachStatement(ctx);
- }
-
- @Override
- public ParseTree visitTryStatement(BSLParser.TryStatementContext ctx) {
- addRegionRange(ctx.TRY_KEYWORD(), ctx.ENDTRY_KEYWORD());
- return super.visitTryStatement(ctx);
- }
-
- private void addRegionRange(TerminalNode start, TerminalNode stop) {
- if (start == null || stop == null) {
- return;
- }
-
- int startLine = start.getSymbol().getLine();
- int stopLine = stop.getSymbol().getLine();
-
- if (stopLine > startLine) {
- FoldingRange foldingRange = new FoldingRange(startLine - 1, stopLine - 1);
- foldingRange.setKind(FoldingRangeKind.Region);
-
- regionRanges.add(foldingRange);
- }
- }
- }
-
- private static class RegionRangeFinder {
-
- private final List regionRanges;
-
- RegionRangeFinder(DocumentContext documentContext) {
- regionRanges = documentContext.getSymbolTree().getRegionsFlat().stream()
- .map(RegionRangeFinder::toFoldingRange)
- .collect(Collectors.toList());
- }
-
- List getRegionRanges() {
- return new ArrayList<>(regionRanges);
- }
-
- private static FoldingRange toFoldingRange(RegionSymbol regionSymbol) {
-
- FoldingRange foldingRange = new FoldingRange(
- regionSymbol.getStartRange().getStart().getLine(),
- regionSymbol.getEndRange().getEnd().getLine()
- );
- foldingRange.setKind(FoldingRangeKind.Region);
-
- return foldingRange;
- }
+ private final List foldingRangeSuppliers;
+ public List getFoldingRange(DocumentContext documentContext) {
+ return foldingRangeSuppliers.stream()
+ .map(foldingRangeSupplier -> foldingRangeSupplier.getFoldingRanges(documentContext))
+ .flatMap(Collection::stream)
+ .collect(Collectors.toList());
}
- private static class PreprocIfRegionRangeFinder extends BSLParserBaseVisitor {
-
- private final Deque preprocIfRegionStack = new ArrayDeque<>();
- private final List regionRanges = new ArrayList<>();
-
- public List getRegionRanges() {
- return new ArrayList<>(regionRanges);
- }
-
- @Override
- public ParseTree visitPreproc_if(BSLParser.Preproc_ifContext ctx) {
- preprocIfRegionStack.push(ctx);
- return super.visitPreproc_if(ctx);
- }
-
- @Override
- public ParseTree visitPreproc_endif(BSLParser.Preproc_endifContext ctx) {
-
- if (preprocIfRegionStack.isEmpty()) {
- return super.visitPreproc_endif(ctx);
- }
-
- BSLParser.Preproc_ifContext regionStart = preprocIfRegionStack.pop();
-
- int start = regionStart.getStart().getLine();
- int stop = ctx.getStop().getLine();
-
- FoldingRange foldingRange = new FoldingRange(start - 1, stop - 1);
- foldingRange.setKind(FoldingRangeKind.Region);
-
- regionRanges.add(foldingRange);
-
- return super.visitPreproc_endif(ctx);
- }
-
- }
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/FormatProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/FormatProvider.java
index 2fae789090a..4da30581004 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/FormatProvider.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/FormatProvider.java
@@ -162,6 +162,7 @@ private static List getTextEdits(
int lastLine = firstToken.getLine();
int previousTokenType = -1;
+ boolean previousIsUnary = false;
for (Token token : filteredTokens) {
int tokenType = token.getType();
@@ -222,7 +223,7 @@ private static List getTextEdits(
String currentIndentation = StringUtils.repeat(indentation, currentIndentLevel);
newTextBuilder.append("\n");
newTextBuilder.append(currentIndentation);
- } else if (needAddSpace(tokenType, previousTokenType)) {
+ } else if (needAddSpace(tokenType, previousTokenType, previousIsUnary)) {
newTextBuilder.append(' ');
} else {
// no-op
@@ -256,6 +257,7 @@ private static List