-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(diagnostic): Новое правило "Обращение к отсутствующему методу об…
…щего модуля MissingCommonModuleMethod "- ГОТОВО (#2827) * Реализация правила * Обращение к приватным методам * Исключил ФП параметры с именами общих модулей * переименовал правило * документация + настройка правила * добавил тег правила * уточнил сообщения правила * использован символьный репозиторий вместо работы с аст-деревом * @CleanupContextBeforeClassAndAfterEachTestMethod * реализованы недостающие кейсы * убрал комментарий * комментарий про приватные методы исключил срабатывание на внутренних вызовах внутри общих модулей * Поправил текст сообщения исправил замечания из ПР * исправил замечания из ПР * кейс для покрытия * уточнил проверку приватных методов * замечание СонарЛинт
- Loading branch information
Showing
8 changed files
with
292 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Обращение к отсутствующему методу общего модуля (MissingCommonModuleMethod) | ||
|
||
<!-- Блоки выше заполняются автоматически, не трогать --> | ||
## Описание диагностики | ||
<!-- Описание диагностики заполняется вручную. Необходимо понятным языком описать смысл и схему работу --> | ||
Правило регистрирует ошибочные обращения к методам общих модулей. | ||
Находятся проблемные варианты | ||
- когда метода нет в указанном общем модуле | ||
- когда метод есть в общем модуле, но метод не является экспортным | ||
- когда у общего модуля отсутствуют исходники, все обращения к любым его методам помечаются как ошибочные | ||
|
||
Исключаются варианты | ||
- когда имя переменной совпадает с именем общего модуля | ||
## Примеры | ||
<!-- В данном разделе приводятся примеры, на которые диагностика срабатывает, а также можно привести пример, как можно исправить ситуацию --> | ||
|
||
## Источники | ||
<!-- Необходимо указывать ссылки на все источники, из которых почерпнута информация для создания диагностики --> | ||
<!-- Примеры источников | ||
* Источник: [Стандарт: Тексты модулей](https://its.1c.ru/db/v8std#content:456:hdoc) | ||
* Полезная информация: [Отказ от использования модальных окон](https://its.1c.ru/db/metod8dev#content:5272:hdoc) | ||
* Источник: [Cognitive complexity, ver. 1.4](https://www.sonarsource.com/docs/CognitiveComplexity.pdf) --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Referencing a missing common module method (MissingCommonModuleMethod) | ||
|
||
<!-- Блоки выше заполняются автоматически, не трогать --> | ||
## Description | ||
<!-- Описание диагностики заполняется вручную. Необходимо понятным языком описать смысл и схему работу --> | ||
|
||
## Examples | ||
<!-- В данном разделе приводятся примеры, на которые диагностика срабатывает, а также можно привести пример, как можно исправить ситуацию --> | ||
|
||
## Sources | ||
<!-- Необходимо указывать ссылки на все источники, из которых почерпнута информация для создания диагностики --> | ||
<!-- Примеры источников | ||
* Источник: [Стандарт: Тексты модулей](https://its.1c.ru/db/v8std#content:456:hdoc) | ||
* Полезная информация: [Отказ от использования модальных окон](https://its.1c.ru/db/metod8dev#content:5272:hdoc) | ||
* Источник: [Cognitive complexity, ver. 1.4](https://www.sonarsource.com/docs/CognitiveComplexity.pdf) --> |
128 changes: 128 additions & 0 deletions
128
...github/_1c_syntax/bsl/languageserver/diagnostics/MissingCommonModuleMethodDiagnostic.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/* | ||
* This file is a part of BSL Language Server. | ||
* | ||
* Copyright (c) 2018-2022 | ||
* Alexey Sosnoviy <[email protected]>, Nikita Fedkin <[email protected]> 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.references.model.LocationRepository; | ||
import com.github._1c_syntax.bsl.languageserver.references.model.OccurrenceType; | ||
import com.github._1c_syntax.bsl.languageserver.references.model.SymbolOccurrence; | ||
import com.github._1c_syntax.bsl.languageserver.utils.Trees; | ||
import com.github._1c_syntax.bsl.parser.BSLParserRuleContext; | ||
import com.github._1c_syntax.bsl.types.ConfigurationSource; | ||
import com.github._1c_syntax.bsl.types.ModuleType; | ||
import lombok.AllArgsConstructor; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.Value; | ||
import org.antlr.v4.runtime.tree.ParseTree; | ||
import org.eclipse.lsp4j.Range; | ||
import org.eclipse.lsp4j.SymbolKind; | ||
|
||
import java.util.Optional; | ||
|
||
@DiagnosticMetadata( | ||
type = DiagnosticType.ERROR, | ||
severity = DiagnosticSeverity.BLOCKER, | ||
scope = DiagnosticScope.BSL, | ||
minutesToFix = 5, | ||
tags = { | ||
DiagnosticTag.ERROR | ||
} | ||
) | ||
|
||
@RequiredArgsConstructor | ||
public class MissingCommonModuleMethodDiagnostic extends AbstractDiagnostic { | ||
public static final String PRIVATE_METHOD_MESSAGE = "privateMethod"; | ||
private final LocationRepository locationRepository; | ||
|
||
private static String getMethodNameByLocation(BSLParserRuleContext node, Range range) { | ||
return Trees.findTerminalNodeContainsPosition(node, range.getEnd()) | ||
.map(ParseTree::getText) | ||
.orElseThrow(); | ||
} | ||
|
||
@Override | ||
protected void check() { | ||
if (documentContext.getServerContext().getConfiguration().getConfigurationSource() == ConfigurationSource.EMPTY){ | ||
return; | ||
} | ||
locationRepository.getSymbolOccurrencesByLocationUri(documentContext.getUri()) | ||
.filter(symbolOccurrence -> symbolOccurrence.getOccurrenceType() == OccurrenceType.REFERENCE) | ||
.filter(symbolOccurrence -> symbolOccurrence.getSymbol().getSymbolKind() == SymbolKind.Method) | ||
.filter(symbolOccurrence -> symbolOccurrence.getSymbol().getModuleType() == ModuleType.CommonModule) | ||
.map(this::getReferenceToMethodCall) | ||
.flatMap(Optional::stream) | ||
.forEach(this::fireIssue); | ||
} | ||
|
||
private Optional<CallData> getReferenceToMethodCall(SymbolOccurrence symbolOccurrence) { | ||
final var symbol = symbolOccurrence.getSymbol(); | ||
final var document = documentContext.getServerContext() | ||
.getDocument(symbol.getMdoRef(), symbol.getModuleType()) | ||
.orElseThrow(); | ||
final var mdObject = document.getMdObject().orElseThrow(); | ||
|
||
// т.к. через refIndex.getReferences нельзя получить приватные методы, приходится обходить символы модуля | ||
final var methodSymbol = document | ||
.getSymbolTree().getMethodSymbol(symbol.getSymbolName()); | ||
if (methodSymbol.isEmpty()){ | ||
final var location = symbolOccurrence.getLocation(); | ||
// Нельзя использовать symbol.getSymbolName(), т.к. имя в нижнем регистре | ||
return Optional.of( | ||
new CallData(mdObject.getName(), | ||
getMethodNameByLocation(documentContext.getAst(), location.getRange()), | ||
location.getRange(), false, false)); | ||
} | ||
// вызовы приватных методов внутри самого модуля пропускаем | ||
if (document.getUri().equals(documentContext.getUri())){ | ||
return Optional.empty(); | ||
} | ||
return methodSymbol | ||
.filter(methodSymbol2 -> !methodSymbol2.isExport()) | ||
.map(methodSymbol1 -> new CallData(mdObject.getName(), | ||
methodSymbol1.getName(), | ||
symbolOccurrence.getLocation().getRange(), true, true)); | ||
} | ||
|
||
private void fireIssue(CallData callData) { | ||
final String message; | ||
if (!callData.exists){ | ||
message = info.getMessage(callData.methodName, callData.moduleName); | ||
} else { | ||
message = info.getResourceString(PRIVATE_METHOD_MESSAGE, callData.methodName, callData.moduleName); | ||
} | ||
diagnosticStorage.addDiagnostic(callData.moduleMethodRange, message); | ||
} | ||
|
||
@Value | ||
@AllArgsConstructor | ||
private static class CallData { | ||
String moduleName; | ||
String methodName; | ||
Range moduleMethodRange; | ||
boolean nonExport; | ||
boolean exists; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletions
4
...c_syntax/bsl/languageserver/diagnostics/MissingCommonModuleMethodDiagnostic_en.properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
diagnosticMessage=The method %s of %s common module does not exist | ||
diagnosticName=Referencing a missing common module method | ||
|
||
privateMethod=Correct the reference to the non export %s method of the common module %s |
4 changes: 4 additions & 0 deletions
4
...c_syntax/bsl/languageserver/diagnostics/MissingCommonModuleMethodDiagnostic_ru.properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
diagnosticMessage=Метод %s общего модуля %s не существует | ||
diagnosticName=Обращение к отсутствующему методу общего модуля | ||
|
||
privateMethod=Исправьте обращение к закрытому, неэкспортному методу %s общего модуля %s |
70 changes: 70 additions & 0 deletions
70
...ub/_1c_syntax/bsl/languageserver/diagnostics/MissingCommonModuleMethodDiagnosticTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/* | ||
* This file is a part of BSL Language Server. | ||
* | ||
* Copyright (c) 2018-2022 | ||
* Alexey Sosnoviy <[email protected]>, Nikita Fedkin <[email protected]> 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.util.CleanupContextBeforeClassAndAfterEachTestMethod; | ||
import com.github._1c_syntax.utils.Absolute; | ||
import org.eclipse.lsp4j.Diagnostic; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import java.util.List; | ||
|
||
import static com.github._1c_syntax.bsl.languageserver.util.Assertions.assertThat; | ||
|
||
@CleanupContextBeforeClassAndAfterEachTestMethod | ||
class MissingCommonModuleMethodDiagnosticTest extends AbstractDiagnosticTest<MissingCommonModuleMethodDiagnostic> { | ||
|
||
private static final String PATH_TO_METADATA = "src/test/resources/metadata/designer"; | ||
|
||
MissingCommonModuleMethodDiagnosticTest() { | ||
super(MissingCommonModuleMethodDiagnostic.class); | ||
} | ||
|
||
@Test | ||
void test() { | ||
initServerContext(Absolute.path(PATH_TO_METADATA)); | ||
|
||
List<Diagnostic> diagnostics = getDiagnostics(); | ||
|
||
assertThat(diagnostics, true) | ||
.hasMessageOnRange("Метод МетодНесуществующий общего модуля ПервыйОбщийМодуль не существует", 1, 22, 41) | ||
.hasMessageOnRange("Метод ДругойМетодНесуществующий общего модуля ПервыйОбщийМодуль не существует", 2, 26, 51) | ||
.hasMessageOnRange("Метод ЕщеМетодНесуществующий общего модуля ПервыйОбщийМодуль не существует", 3, 22, 44) | ||
.hasMessageOnRange("Метод ЕщеОдинМетодНесуществующий общего модуля ПервыйОбщийМодуль не существует", 4, 22, 48) | ||
.hasMessageOnRange("Метод ЕщеДругойМетодНесуществующий общего модуля ПервыйОбщийМодуль не существует", 5, 26, 54) | ||
|
||
.hasMessageOnRange("Исправьте обращение к закрытому, неэкспортному методу РегистрацияИзмененийПередУдалением общего модуля ПервыйОбщийМодуль", 11, 22, 56) | ||
.hasMessageOnRange("Исправьте обращение к закрытому, неэкспортному методу Тест общего модуля ПервыйОбщийМодуль", 12, 26, 30) | ||
.hasMessageOnRange("Исправьте обращение к закрытому, неэкспортному методу Тест общего модуля ПервыйОбщийМодуль", 13, 22, 26) | ||
.hasMessageOnRange("Исправьте обращение к закрытому, неэкспортному методу Тест общего модуля ПервыйОбщийМодуль", 14, 22, 26) | ||
.hasMessageOnRange("Исправьте обращение к закрытому, неэкспортному методу Тест общего модуля ПервыйОбщийМодуль", 15, 26, 30) | ||
.hasSize(10); | ||
} | ||
|
||
@Test | ||
void testWithoutMetadata() { | ||
|
||
List<Diagnostic> diagnostics = getDiagnostics(); | ||
|
||
assertThat(diagnostics).isEmpty(); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
src/test/resources/diagnostics/MissingCommonModuleMethodDiagnostic.bsl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
Процедура Тест1() | ||
ПервыйОбщийМодуль.МетодНесуществующий(1, 2); // ошибка | ||
А = ПервыйОбщийМодуль.ДругойМетодНесуществующий(); // ошибка | ||
ПервыйОбщийМодуль.ЕщеМетодНесуществующий().Добавить(); // ошибка | ||
ПервыйОбщийМодуль.ЕщеОдинМетодНесуществующий().Реквизит = 10; // ошибка | ||
Б = ПервыйОбщийМодуль.ЕщеДругойМетодНесуществующий().Добавить(); // ошибка | ||
|
||
НесуществующийОбщийМодульИлиПростоПеременная.МетодНесуществующий(1, 2); // не ошибка | ||
КонецПроцедуры | ||
|
||
Процедура Тест2_ОбращениеКПриватномуМетоду() | ||
ПервыйОбщийМодуль.РегистрацияИзмененийПередУдалением(Источник, Отказ); // ошибка | ||
А = ПервыйОбщийМодуль.Тест(); // ошибка | ||
ПервыйОбщийМодуль.Тест().Добавить(); // ошибка | ||
ПервыйОбщийМодуль.Тест().Реквизит = 10; // ошибка | ||
Б = ПервыйОбщийМодуль.Тест().Добавить(); // ошибка | ||
КонецПроцедуры | ||
|
||
Процедура Тест3() | ||
ПервыйОбщийМодуль.НеУстаревшаяПроцедура(); // не ошибка | ||
А = ПервыйОбщийМодуль.НеУстаревшаяФункция(); // не ошибка | ||
ПервыйОбщийМодуль.НеУстаревшаяФункция().Добавить(); // не ошибка | ||
ПервыйОбщийМодуль.НеУстаревшаяФункция().Реквизит = 10; // не ошибка | ||
Б = ПервыйОбщийМодуль.НеУстаревшаяФункция().Добавить(); // не ошибка | ||
КонецПроцедуры | ||
|
||
Процедура Тест4_ИмяПараметр(ПервыйОбщийМодуль) | ||
ПервыйОбщийМодуль.МетодНесуществующий(1, 2); // не ошибка | ||
А = ПервыйОбщийМодуль.ДругойМетодНесуществующий(); // не ошибка | ||
ПервыйОбщийМодуль.ЕщеМетодНесуществующий().Добавить(); // не ошибка | ||
ПервыйОбщийМодуль.ЕщеОдинМетодНесуществующий().Реквизит = 10; // не ошибка | ||
Б = ПервыйОбщийМодуль.ЕщеДругойМетодНесуществующий().Добавить(); // не ошибка | ||
КонецПроцедуры | ||
|
||
Процедура Тест5_МодулиМенеджеров() | ||
Справочники.Справочник1.НесуществующийМетод(); // пока не ошибка | ||
КонецПроцедуры |