Skip to content

Commit

Permalink
Merge pull request #3228 from 1c-syntax/feature/extraEnffort
Browse files Browse the repository at this point in the history
Наценка за сложность
  • Loading branch information
theshadowco authored Jan 14, 2024
2 parents 8522790 + 9503336 commit 98c2d8e
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 36 deletions.
12 changes: 10 additions & 2 deletions docs/contributing/DiagnosticStructure.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@

- Тип диагностики `type` и ее важность `severity`, для каждой диагностики обязательно их определение. Для того, чтобы правильно выбрать тип и важность диагностики, можно обратиться к [статье](DiagnosticTypeAndSeverity.md).
- Время на исправление замечания `minutesToFix` (по умолчанию 0). Данное значение используется при расчете общего техдолга проекта в трудозатрах на исправление всех замечаний (сумма времени на исправление по всем обнаруженным замечаниям). Стоит указывать время, максимально реалистичное, которое разработчик должен потратить на исправление.
- С помощью параметра `extraMinForComplexity` можно динамически увеличивать время на исправление замечания для диагностик, в которых учитывается несколько нарушающих правило мест, например при расчете сложности метода.
- Набор тэгов `tag` диагностики, указывающих группы, к котором она относится. Подробнее о тэга в [статье](DiagnosticTag.md).
- Границы применимости `scope` (по умолчанию `ALL`, т.е. без ограничения). BSL LS поддерживает несколько языков (oscript и bsl) и диагностики могут применяться как к одному конкретному языку, так и ко всем сразу.
- Активность правила по-умолчанию `activatedByDefault` (по умолчанию `Истина`). При разработке экспериментальных, спорных либо не применимых в большинстве проектов, стоит по умолчанию отключать диагностику, активацию выполнит конечный пользователь решения.
- Режим совместимости `compatibilityMode`, по которому фильтруются диагностики при использовании метаданных. По умолчанию `UNDEFINED`.

- Список типов модулей `modules` для возможности ограничить анализируемую диагностикой область
- Признак возможности установить замечания на весь проект `canLocateOnProject`. Используется для диагностик не связанных с модулем исходного кода. На данный момент опция воспринимается только SonarQube, остальные инструменты игнорируют.
Последние два могут быть опущены.

Пример аннотации
Expand All @@ -64,8 +66,14 @@
compatibilityMode = DiagnosticCompatibilityMode.COMPATIBILITY_MODE_8_3_3, // Режим проверки совместимости с 8.3.3
tags = {
DiagnosticTag.STANDARD // Относится к диагностикам нарушения стандарта 1С
}
},
modules = {
ModuleType.CommonModule // Анализируются только общие модули
},
canLocateOnProject = false, // Замечание будет размещено только в привязке к модулю
extraMinForComplexity = 1 // За каждую дополнительную позицию замечания (`DiagnosticRelatedInformation`) будет добавлено по одной минуте
)

```

Класс должен реализовывать интерфейс `BSLDiagnostic`. Если диагностика основывается на AST дереве, то класс реализации должен быть унаследован от одного из классов ниже, реализующих `BSLDiagnostic`:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
minutesToFix = 15,
tags = {
DiagnosticTag.BRAINOVERLOAD
}
},
extraMinForComplexity = 1
)
public class CognitiveComplexityDiagnostic extends AbstractVisitorDiagnostic {

Expand Down Expand Up @@ -99,28 +100,6 @@ public ParseTree visitSub(BSLParser.SubContext ctx) {
Integer methodComplexity = documentContext.getCognitiveComplexityData().getMethodsComplexity().get(methodSymbol);

if (methodComplexity > complexityThreshold) {

List<DiagnosticRelatedInformation> relatedInformation = new ArrayList<>();

relatedInformation.add(RelatedInformation.create(
documentContext.getUri(),
methodSymbol.getSubNameRange(),
info.getMessage(methodSymbol.getName(), methodComplexity, complexityThreshold)
));

List<ComplexitySecondaryLocation> secondaryLocations =
documentContext.getCognitiveComplexityData().getMethodsComplexitySecondaryLocations().get(methodSymbol);

secondaryLocations.stream()
.map((ComplexitySecondaryLocation secondaryLocation) ->
RelatedInformation.create(
documentContext.getUri(),
secondaryLocation.getRange(),
secondaryLocation.getMessage()
)
)
.collect(Collectors.toCollection(() -> relatedInformation));

diagnosticStorage.addDiagnostic(
methodSymbol.getSubNameRange(),
info.getMessage(methodSymbol.getName(), methodComplexity, complexityThreshold),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
minutesToFix = 25,
tags = {
DiagnosticTag.BRAINOVERLOAD
}
},
extraMinForComplexity = 1
)
public class CyclomaticComplexityDiagnostic extends AbstractVisitorDiagnostic {
private static final int COMPLEXITY_THRESHOLD = 20;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,10 @@ public void addDiagnostic(
}

public void addDiagnostic(ParseTree tree) {
if (tree instanceof BSLParserRuleContext) {
addDiagnostic((BSLParserRuleContext) tree);
} else if (tree instanceof TerminalNode) {
addDiagnostic((TerminalNode) tree);
if (tree instanceof BSLParserRuleContext parserRuleContext) {
addDiagnostic(parserRuleContext);
} else if (tree instanceof TerminalNode terminalNode) {
addDiagnostic(terminalNode);
} else {
throw new IllegalArgumentException("Unsupported parameter type " + tree);
}
Expand Down Expand Up @@ -253,5 +253,4 @@ private static Diagnostic createDiagnostic(
}
return diagnostic;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,11 @@ private List<ParameterDefinition> calcNotAssignedParams(MethodSymbol method) {
return calcNotAssignedParams(method, parameterDefinitions);
}

private List<ParameterDefinition> calcNotAssignedParams(MethodSymbol method, List<ParameterDefinition> parameterDefinitions) {
private List<ParameterDefinition> calcNotAssignedParams(MethodSymbol method,
List<ParameterDefinition> parameterDefinitions) {
return parameterDefinitions.stream()
.filter(parameterDefinition -> isAssignedParam(method, parameterDefinition))
.collect(Collectors.toUnmodifiableList());
.toList();
}

private boolean isAssignedParam(MethodSymbol method, ParameterDefinition parameterDefinition) {
Expand All @@ -118,7 +119,8 @@ private boolean isAssignedParam(MethodSymbol method, ParameterDefinition paramet
.anyMatch(ref -> ref.getOccurrenceType() == OccurrenceType.DEFINITION));
}

private static Stream<VariableSymbol> getVariableByParameter(MethodSymbol method, ParameterDefinition parameterDefinition) {
private static Stream<VariableSymbol> getVariableByParameter(MethodSymbol method,
ParameterDefinition parameterDefinition) {
return method.getChildren().stream()
// в будущем могут появиться и другие символы, подчиненные методам
.filter(sourceDefinedSymbol -> sourceDefinedSymbol.getSymbolKind() == SymbolKind.Variable)
Expand Down Expand Up @@ -159,7 +161,7 @@ private static boolean isEqualCompilerDirective(MethodSymbol method) {
private static List<ParameterDefinition> getMethodParamsByRef(MethodSymbol methodSymbol) {
return methodSymbol.getParameters().stream()
.filter(parameterDefinition -> !parameterDefinition.isByValue())
.collect(Collectors.toUnmodifiableList());
.toList();
}

private static List<DiagnosticRelatedInformation> getRelatedInformation(List<Reference> references) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@ public boolean canLocateOnProject() {
return diagnosticMetadata.canLocateOnProject();
}

public double getExtraMinForComplexity() {
return diagnosticMetadata.extraMinForComplexity();
}

public Map<String, Object> getDefaultConfiguration() {
return diagnosticParameters.stream()
.collect(Collectors.toMap(DiagnosticParameterInfo::getName, DiagnosticParameterInfo::getDefaultValue));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,9 @@
* Замечания диагностики могут быть прикреплены на уровень анализируемого проекта (в частности в SonarQube)
*/
boolean canLocateOnProject() default false;

/**
* Надбавка ко времени исправления замечания за повышенную сложность
*/
double extraMinForComplexity() default 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class CyclomaticComplexityDiagnosticTest extends AbstractDiagnosticTest<Cyclomat
@Test
void test() {

assertThat(diagnosticInstance.getInfo().getExtraMinForComplexity()).isEqualTo(1);

// when
List<Diagnostic> diagnostics = getDiagnostics();

Expand All @@ -45,7 +47,6 @@ void test() {
assertThat(diagnostics, true)
.hasRange(0, 8, 0, 32);
assertThat(diagnostics.get(0).getRelatedInformation()).hasSize(21);

}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,13 @@ void testIAllDiagnostics() {
assertThat(diagnosticErrors).isEmpty();
}

@Test
void testExtraMinForComplexity() {
// нельзя ставить отрицательное значение
diagnosticInfos.forEach(diagnosticInfo ->
assertThat(diagnosticInfo.getExtraMinForComplexity())
.as(diagnosticInfo.getCode().getStringValue())
.isNotNegative()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ void testCanLocateOnProject() {
Assertions.assertThat(diagnosticInfo.isActivatedByDefault()).isTrue();
Assertions.assertThat(diagnosticInfo.getTags()).isNotEmpty();
Assertions.assertThat(diagnosticInfo.canLocateOnProject()).isTrue();
Assertions.assertThat(diagnosticInfo.getExtraMinForComplexity()).isZero();
}

@Test
Expand Down

0 comments on commit 98c2d8e

Please sign in to comment.