diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3ad672efd..2d998e845 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,8 @@
#### Код модулей
+- Проверка когнитивной сложности методов
+- Проверка цикломатической сложности методов
- В проверку использования нерекомендуемых методов (use-non-recommended-method) добавлен метод ПолучитьФорму(GetForm)
#### Запросы
diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/cognitive-complexity.md b/bundles/com.e1c.v8codestyle.bsl/markdown/cognitive-complexity.md
new file mode 100644
index 000000000..07be3330d
--- /dev/null
+++ b/bundles/com.e1c.v8codestyle.bsl/markdown/cognitive-complexity.md
@@ -0,0 +1,158 @@
+# The cognitive complexity of the method is exceeded
+
+The high score of the cognitive complexity to complicate perception and maintainability of the written code.
+
+The most effective way to reduce the complexity score is to decompose the code and simplify logical expressions.
+
+## Compute rules:
+
+### Increments:
+
+- Conditional statements:
+```bsl
+If Conditional1 Then // +1 point
+ // Code
+ElseIf Conditional2 Then // +1 point
+ // Code
+Else // +1 point
+ // Code
+EndIf;
+```
+- Trenary operator:
+```bsl
+?(conditional, positive_code, negative_code); // +1 point
+```
+- Loops:
+```bsl
+For Each Element In Collection Do // +1 point
+ // code
+EndDo;
+```
+```bsl
+For index = 1 To N Do // +1 point
+ // code
+EndDo;
+```
+```bsl
+While True Do // +1 point
+ // code
+EndDo;
+```
+- Exception block:
+```bsl
+...
+Exception // +1 point
+ // code
+EndTry;
+```
+- GoTo:
+```bsl
+Goto ~Label; // +1 point
+```
+- boolean operands AND, OR
+```bsl
+ conditional1 = predicate1 OR predicate2; // +1 point
+ conditional2 = predicate1 AND predicate2; // +1 point
+```
+- recursive call:
+```bsl
+Procedure RecursiveCall(Collection)
+ If conditional Then
+ RecursiveCall(...); // +1 point
+ EndIf;
+EndProcedure
+```
+
+### Nesting increments:
+
+- IF-part of conditional statement:
+```bsl
+If conditional1 then // +nesting level
+ // code
+ElseIf conditional2 then
+ // code
+Else
+ // code
+EndIf;
+```
+- Trenary operator:
+```bsl
+ ?(conditional, value1, value2); // +nesting level
+```
+- Loops:
+```bsl
+For Each Element In Collection Do // +nesting level
+ // code
+EndDo;
+```
+```bsl
+For index = 1 To N Do // +nesting level
+ // code
+EndDo;
+```
+```bsl
+While True Do // +nesting level
+ // code
+EndDo;
+```
+- exception block:
+```bsl
+...
+Exception // +nesting level
+ // code
+EndTry;
+```
+
+### Nesting level:
+
+- Conditional statements:
+```bsl
+If Conditional1 Then // increment depth
+ // Code
+ElseIf Conditional2 Then // increment depth
+ // Code
+Else // increment depth
+ // Code
+EndIf;
+```
+
+- Trenary operator:
+```bsl
+?(
+ conditional,
+ // increment depth,
+ // increment depth
+)
+```
+- Loops:
+```bsl
+For Each Element In Collection Do
+ // increment depth
+EndDo;
+```
+```bsl
+For index = 1 To N Do
+ // increment depth
+EndDo;
+```
+```bsl
+While True Do
+ // increment depth
+EndDo;
+```
+- Exception block:
+```bsl
+...
+Exception
+ // increment depth
+EndTry;
+```
+- Nesting method:
+```bsl
+Method(
+ // increment depth
+ NestingMethod(
+ // increment depth
+ )
+);
+```
diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/cyclomatic-complexity.md b/bundles/com.e1c.v8codestyle.bsl/markdown/cyclomatic-complexity.md
new file mode 100644
index 000000000..17ab654c1
--- /dev/null
+++ b/bundles/com.e1c.v8codestyle.bsl/markdown/cyclomatic-complexity.md
@@ -0,0 +1,65 @@
+# The cyclomatic complexity of the method is exceeded
+
+Thomas J. McCabe developed a cyclomatic metric for code testing tasks.
+His proposed method calculates the number of linearly independent program execution threads.
+The difficulty value corresponds to the number of tests required.
+
+The most effective way to reduce the complexity score is to decompose the code and simplify logical expressions.
+
+## Compute rules:
+
+### Increments:
+
+- Loops:
+```bsl
+For Item In Collection Do
+ // code
+EndDo;
+```
+```bsl
+For index = 1 To N Do
+ // code
+EndDo;
+```
+```bsl
+While Conditional Do
+ // code
+EndDo;
+```
+- Conditional statements:
+```bsl
+If Conditional Then // +1 point
+ // code
+EndIf;
+
+If Conditional Then // too +1 point
+ // code
+Else
+ // code
+EndIf;
+```
+```bsl
+If Conditional1 Then // +1 point
+ // code
+ElseIf Conditional2 Then // +1 additional point
+ // code
+ElseIf Conditional3 Then // +1 additional point
+ // code
+Else // the Else does not increase the complexity
+ // code
+EndIf;
+```
+- Try-Exception blocks:
+```bsl
+Try
+ // code
+Exception
+ // code
+EndTry;
+```
+- Booleands operands: AND, OR
+- Trenary operator:
+```bsl
+?(Coditional, Value1, Value2);
+```
+- Procedure or Function initially has a complexity equal to 1
diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/ru/cognitive-complexity.md b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/cognitive-complexity.md
new file mode 100644
index 000000000..ca78b9fd0
--- /dev/null
+++ b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/cognitive-complexity.md
@@ -0,0 +1,158 @@
+# Превышение когнитивной сложности метода
+
+Высокое значение показателя говорит о сложности восприятия и сопровождаемости написанного кода.
+
+Наиболее эффективным способом уменьшения показателя сложности является декомпозиция кода и упрощение логических выражений.
+
+## Правила вычисления:
+
+### Конструкции увеличивающие сложность:
+
+- Ветви условного оператора:
+```bsl
+Если Условие1 Тогда // +1 к сложности
+ // код
+ИначеЕсли Условие2 Тогда // +1 к сложности
+ // код
+Иначе // +1 к сложности
+ // код
+КонецЕсли;
+```
+- тренарный оператор:
+```bsl
+?(условие, позитивный исход, негативный исход); // +1 к сложности
+```
+- циклы:
+```bsl
+Для Каждого Элемент Из Коллекция Цикл // +1 к сложности
+ // код
+КонецЦикла;
+```
+```bsl
+Для Индекс = 1 По Граница Цикл // +1 к сложности
+ // код
+КонецЦикла;
+```
+```bsl
+Пока Условия Цикл // +1 к сложности
+ // код
+КонецЦикла;
+```
+- ветвь исключения в блоке попытки:
+```bsl
+...
+Исключение // +1 к сложности
+ // код
+КонецПопытки;
+```
+- переход к метке
+```bsl
+Перейти ~Метка; // +1 к сложности
+```
+- логические операнды И, ИЛИ
+```bsl
+ Условие1 = Предикат1 ИЛИ Предикат2; // +1 к сложности
+ Условие2 = Предикат1 И Предикат2; // +1 к сложности
+```
+- рекурсивный вызов
+```bsl
+Процедура РекурсивныйОбход(Коллекция)
+ Если Условие Тогда
+ РекурсивныйОбход(...); // +1 к сложности
+ КонецЕсли;
+КонецПроцедуры
+```
+
+### Конструкции получающие дополнительный штраф на уровень вложенности:
+
+- Условный оператор (не зависимо от количества ветвей):
+```bsl
+Если Условие1 Тогда // штраф +уровень_вложенности
+ // код
+ИначеЕсли Условие2 Тогда
+ // код
+Иначе
+ // код
+КонецЕсли;
+```
+- тренарный оператор:
+```bsl
+ ?(Условие, Значение1, Значение2); // штраф +уровень_вложенности
+```
+- циклы:
+```bsl
+Для Каждого Элемент Из Коллекция Цикл // штраф +уровень_вложенности
+ // код
+КонецЦикла;
+```
+```bsl
+Для Индекс = 1 По Граница Цикл // штраф +уровень_вложенности
+ // код
+КонецЦикла;
+```
+```bsl
+Пока Условия Цикл // штраф +уровень_вложенности
+ // код
+КонецЦикла;
+```
+- ветвь исключения в попытке:
+```bsl
+...
+Исключение // штраф +уровень_вложенности
+ // код
+КонецПопытки;
+```
+
+### Конструкции увеличивающие уровень вложенности:
+
+- ветви условного оператора:
+```bsl
+Если Условие1 Тогда
+ // увеличение вложенности
+ИначеЕсли Условие2 Тогда
+ // увеличение вложенности
+Иначе
+ // увеличение вложенности
+КонецЕсли;
+```
+
+- тренарный оператор:
+```bsl
+?(
+ условие,
+ // увеличение вложенности,
+ // увеличение вложенности
+)
+```
+- циклы:
+```bsl
+Для Каждого Элемент Из Коллекция Цикл
+ // увеличение вложенности
+КонецЦикла;
+```
+```bsl
+Для Индекс = 1 По Граница Цикл
+ // увеличение вложенности
+КонецЦикла;
+```
+```bsl
+Пока Условия Цикл
+ // увеличение вложенности
+КонецЦикла;
+```
+- ветвь исключения в блоке попытки:
+```bsl
+...
+Исключение
+ // увеличение вложенности
+КонецПопытки;
+```
+- вложенный вызов:
+```bsl
+ВызовМетода(
+ // увеличение вложенности
+ ВложенныйВызов(
+ // увеличение вложенности
+ )
+);
+```
diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/ru/cyclomatic-complexity.md b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/cyclomatic-complexity.md
new file mode 100644
index 000000000..310b845d9
--- /dev/null
+++ b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/cyclomatic-complexity.md
@@ -0,0 +1,67 @@
+# Превышение цикломатической сложности метода
+
+Томас Дж. Маккейб для задач тестирования кода разработал цикломатическую метрику.
+Предложенный им метод вычисляет количество линейно независимых потоков исполнения программы.
+Значение сложности соответствует числу необходимы тестов.
+
+Наиболее эффективным способом уменьшения показателя сложности является декомпозиция кода и упрощение логических выражений.
+
+## Правила вычисления:
+
+### Конструкции, увеличивающие цикломатическую сложность:
+
+- Циклы:
+```bsl
+Для Каждого Элемент Из Коллекция Цикл
+ // код
+КонецЦикла;
+```
+```bsl
+Для Индекс = 1 По Гранца Цикл
+ // код
+КонецЦикла;
+```
+```bsl
+Пока Условие Цикл
+ // код
+КонецЦикла;
+```
+- Условия:
+```bsl
+// ветвление увеличивает цикломатическу сложность на единицу, не зависимо от наличия/отсутствия блока Иначе
+Если Условие Тогда // +1 к сложности
+ // Код
+КонецЕсли;
+
+Если Условие Тогда // тоже +1 к сложности за всю конструкцию
+ // Код
+Иначе
+ // Код
+КонецЕсли;
+```
+```bsl
+// Каждый блок ИначеЕсли увеличивает сложность на дополнительную единицу
+Если Условие1 Тогда // +1 за условный блок
+ // код
+ИначеЕсли Условие2 Тогда // +1 дополнительно за ветвь
+ // код
+ИначеЕсли Условие3 Тогда // +1 дополнительно за ветвь
+ // код
+Иначе // блок иначе не увеличивает сложность
+ // код
+КонецЕсли;
+```
+- Блок обработки исключения:
+```bsl
+Попытка
+ // код
+Исключение
+ // код
+КонецПопытки;
+```
+- Логические операции И, ИЛИ
+- Тренарный оператор:
+```bsl
+?(Условие, Значение1, Значение2);
+```
+- Процедура или Функция изначально имеет сложность равную 1
diff --git a/bundles/com.e1c.v8codestyle.bsl/plugin.xml b/bundles/com.e1c.v8codestyle.bsl/plugin.xml
index 7d684c473..a52286265 100644
--- a/bundles/com.e1c.v8codestyle.bsl/plugin.xml
+++ b/bundles/com.e1c.v8codestyle.bsl/plugin.xml
@@ -347,6 +347,14 @@
category="com.e1c.v8codestyle.bsl"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.check.DeprecatedProcedureOutsideDeprecatedRegionCheck">
+
+
+
+
diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/CognitiveComplexityProcessor.java b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/CognitiveComplexityProcessor.java
new file mode 100644
index 000000000..a401f183e
--- /dev/null
+++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/CognitiveComplexityProcessor.java
@@ -0,0 +1,249 @@
+/*******************************************************************************
+ * Copyright (C) 2023, 1C-Soft LLC and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Manaev Konstantin - initial API and implementation
+ *******************************************************************************/
+package com.e1c.v8codestyle.bsl;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.EList;
+
+import com._1c.g5.v8.dt.bsl.model.BinaryExpression;
+import com._1c.g5.v8.dt.bsl.model.BinaryOperation;
+import com._1c.g5.v8.dt.bsl.model.Conditional;
+import com._1c.g5.v8.dt.bsl.model.DynamicFeatureAccess;
+import com._1c.g5.v8.dt.bsl.model.Expression;
+import com._1c.g5.v8.dt.bsl.model.FeatureAccess;
+import com._1c.g5.v8.dt.bsl.model.FunctionStyleCreator;
+import com._1c.g5.v8.dt.bsl.model.GotoStatement;
+import com._1c.g5.v8.dt.bsl.model.IfStatement;
+import com._1c.g5.v8.dt.bsl.model.IndexAccess;
+import com._1c.g5.v8.dt.bsl.model.Invocation;
+import com._1c.g5.v8.dt.bsl.model.LoopStatement;
+import com._1c.g5.v8.dt.bsl.model.Method;
+import com._1c.g5.v8.dt.bsl.model.OperatorStyleCreator;
+import com._1c.g5.v8.dt.bsl.model.SimpleStatement;
+import com._1c.g5.v8.dt.bsl.model.Statement;
+import com._1c.g5.v8.dt.bsl.model.StaticFeatureAccess;
+import com._1c.g5.v8.dt.bsl.model.TryExceptStatement;
+import com._1c.g5.v8.dt.bsl.model.UnaryExpression;
+import com._1c.g5.v8.dt.bsl.model.WhileStatement;
+
+/**
+ * The cognitive complexity processor.
+ *
+ * @author Manaev Konstantin
+ */
+public final class CognitiveComplexityProcessor
+ implements IComplexityProcessor
+{
+ private static final String TRENARY_OPERATOR = "?"; //$NON-NLS-1$
+
+ @Override
+ public int compute(Method method, IProgressMonitor monitor)
+ {
+ int nestedLevel = 0;
+ int complexityValue = 0;
+ String uniqueName = method.getName();
+ for (Statement statement : method.allStatements())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeStatementComplexity(statement, nestedLevel, uniqueName, monitor);
+ }
+ return complexityValue;
+ }
+
+ private int computeStatementComplexity(Statement statement, int nestedLevel, String methodName,
+ IProgressMonitor monitor)
+ {
+ int complexityValue = 0;
+ if (statement instanceof LoopStatement)
+ {
+ complexityValue += 1 + nestedLevel;
+ if (statement instanceof WhileStatement)
+ {
+ complexityValue += computeExpressionComplexity(((WhileStatement)statement).getPredicate(), nestedLevel,
+ methodName, monitor);
+ }
+ for (Statement substatement : ((LoopStatement)statement).getStatements())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeStatementComplexity(substatement, nestedLevel + 1, methodName, monitor);
+ }
+ }
+ else if (statement instanceof IfStatement)
+ {
+ complexityValue += nestedLevel;
+ IfStatement ifStatement = (IfStatement)statement;
+ Conditional ifPart = ifStatement.getIfPart();
+ complexityValue += computeConditionalComplexity(ifPart, nestedLevel, methodName, monitor);
+ for (Conditional elseIfPart : ifStatement.getElsIfParts())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeConditionalComplexity(elseIfPart, nestedLevel, methodName, monitor);
+ }
+ EList substatements = ifStatement.getElseStatements();
+ if (!substatements.isEmpty())
+ {
+ complexityValue++;
+ for (Statement substatement : substatements)
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeStatementComplexity(substatement, nestedLevel + 1, methodName, monitor);
+ }
+ }
+ }
+ else if (statement instanceof TryExceptStatement)
+ {
+ TryExceptStatement tryExceptStatement = (TryExceptStatement)statement;
+ for (Statement substatement : tryExceptStatement.getTryStatements())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeStatementComplexity(substatement, nestedLevel, methodName, monitor);
+ }
+ for (Statement substatement : tryExceptStatement.getExceptStatements())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += nestedLevel + 1;
+ complexityValue += computeStatementComplexity(substatement, nestedLevel + 1, methodName, monitor);
+ }
+ }
+ else if (statement instanceof GotoStatement)
+ {
+ complexityValue++;
+ }
+ else if (statement instanceof SimpleStatement)
+ {
+ SimpleStatement simpleStatement = (SimpleStatement)statement;
+ complexityValue += computeExpressionComplexity(simpleStatement.getLeft(), nestedLevel, methodName, monitor);
+ Expression right = simpleStatement.getRight();
+ if (right != null)
+ {
+ complexityValue += computeExpressionComplexity(right, nestedLevel, methodName, monitor);
+ }
+ }
+
+ return complexityValue;
+ }
+
+ private int computeConditionalComplexity(Conditional conditional, int nestedLevel, String methodName,
+ IProgressMonitor monitor)
+ {
+ int complexityValue = 1;
+ complexityValue += computeExpressionComplexity(conditional.getPredicate(), nestedLevel, methodName, monitor);
+ for (Statement substatement : conditional.getStatements())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeStatementComplexity(substatement, nestedLevel + 1, methodName, monitor);
+ }
+ return complexityValue;
+ }
+
+ private int computeExpressionComplexity(Expression expression, int nestedLevel, String methodName,
+ IProgressMonitor monitor)
+ {
+ int complexityValue = 0;
+ if (expression instanceof BinaryExpression)
+ {
+ BinaryExpression binaryExpression = (BinaryExpression)expression;
+ BinaryOperation operation = binaryExpression.getOperation();
+ if (operation == BinaryOperation.AND || operation == BinaryOperation.OR)
+ {
+ complexityValue++;
+ }
+ complexityValue +=
+ computeExpressionComplexity(binaryExpression.getLeft(), nestedLevel, methodName, monitor);
+ complexityValue +=
+ computeExpressionComplexity(binaryExpression.getRight(), nestedLevel, methodName, monitor);
+ }
+ else if (expression instanceof UnaryExpression)
+ {
+ complexityValue += computeExpressionComplexity(((UnaryExpression)expression).getOperand(), nestedLevel,
+ methodName, monitor);
+ }
+ else if (expression instanceof DynamicFeatureAccess)
+ {
+ complexityValue += computeExpressionComplexity(((DynamicFeatureAccess)expression).getSource(), nestedLevel,
+ methodName, monitor);
+ }
+ else if (expression instanceof Invocation)
+ {
+ Invocation invocation = (Invocation)expression;
+
+ FeatureAccess method = invocation.getMethodAccess();
+ if (method.getName().equals(TRENARY_OPERATOR))
+ {
+ complexityValue += 1 + nestedLevel;
+ }
+ else if (method instanceof StaticFeatureAccess && method.getName().equalsIgnoreCase(methodName))
+ {
+ complexityValue++;
+ }
+ for (Expression parameter : invocation.getParams())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeExpressionComplexity(parameter, nestedLevel + 1, methodName, monitor);
+ }
+ }
+ else if (expression instanceof IndexAccess)
+ {
+ IndexAccess indexAccess = (IndexAccess)expression;
+ complexityValue += computeExpressionComplexity(indexAccess.getSource(), nestedLevel, methodName, monitor);
+ complexityValue += computeExpressionComplexity(indexAccess.getIndex(), nestedLevel, methodName, monitor);
+ }
+ else if (expression instanceof FunctionStyleCreator)
+ {
+ FunctionStyleCreator creator = (FunctionStyleCreator)expression;
+ complexityValue +=
+ computeExpressionComplexity(creator.getTypeNameExpression(), nestedLevel, methodName, monitor);
+ Expression params = creator.getParamsExpression();
+ if (params != null)
+ {
+ complexityValue += computeExpressionComplexity(params, nestedLevel, methodName, monitor);
+ }
+ }
+ else if (expression instanceof OperatorStyleCreator)
+ {
+ for (Expression parameter : ((OperatorStyleCreator)expression).getParams())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeExpressionComplexity(parameter, nestedLevel, methodName, monitor);
+ }
+ }
+ return complexityValue;
+ }
+}
diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/CyclomaticComplexityProcessor.java b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/CyclomaticComplexityProcessor.java
new file mode 100644
index 000000000..b8b847960
--- /dev/null
+++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/CyclomaticComplexityProcessor.java
@@ -0,0 +1,237 @@
+/*******************************************************************************
+ * Copyright (C) 2023, 1C-Soft LLC and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Manaev Konstantin - initial API and implementation
+ *******************************************************************************/
+package com.e1c.v8codestyle.bsl;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.EList;
+
+import com._1c.g5.v8.dt.bsl.model.BinaryExpression;
+import com._1c.g5.v8.dt.bsl.model.BinaryOperation;
+import com._1c.g5.v8.dt.bsl.model.Conditional;
+import com._1c.g5.v8.dt.bsl.model.DynamicFeatureAccess;
+import com._1c.g5.v8.dt.bsl.model.Expression;
+import com._1c.g5.v8.dt.bsl.model.FeatureAccess;
+import com._1c.g5.v8.dt.bsl.model.FunctionStyleCreator;
+import com._1c.g5.v8.dt.bsl.model.IfStatement;
+import com._1c.g5.v8.dt.bsl.model.IndexAccess;
+import com._1c.g5.v8.dt.bsl.model.Invocation;
+import com._1c.g5.v8.dt.bsl.model.LoopStatement;
+import com._1c.g5.v8.dt.bsl.model.Method;
+import com._1c.g5.v8.dt.bsl.model.OperatorStyleCreator;
+import com._1c.g5.v8.dt.bsl.model.SimpleStatement;
+import com._1c.g5.v8.dt.bsl.model.Statement;
+import com._1c.g5.v8.dt.bsl.model.TryExceptStatement;
+import com._1c.g5.v8.dt.bsl.model.UnaryExpression;
+import com._1c.g5.v8.dt.bsl.model.WhileStatement;
+
+/**
+ * The cyclomatic complexity processor.
+ *
+ * @author Manaev Konstantin
+ */
+public final class CyclomaticComplexityProcessor
+ implements IComplexityProcessor
+{
+
+ private static final String TRENARY_OPERATOR = "?"; //$NON-NLS-1$
+
+ @Override
+ public int compute(Method method, IProgressMonitor monitor)
+ {
+ int complexityValue = 1;
+ String uniqueName = method.getName();
+ for (Statement statement : method.allStatements())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeStatementComplexity(statement, uniqueName, monitor);
+ }
+ return complexityValue;
+ }
+
+ private int computeStatementComplexity(Statement statement, String methodName,
+ IProgressMonitor monitor)
+ {
+ int complexityValue = 0;
+ if (statement instanceof LoopStatement)
+ {
+ complexityValue++;
+ if (statement instanceof WhileStatement)
+ {
+ complexityValue += computeExpressionComplexity(((WhileStatement)statement).getPredicate(),
+ methodName, monitor);
+ }
+ for (Statement substatement : ((LoopStatement)statement).getStatements())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeStatementComplexity(substatement, methodName, monitor);
+ }
+ }
+ else if (statement instanceof IfStatement)
+ {
+ IfStatement ifStatement = (IfStatement)statement;
+ Conditional ifPart = ifStatement.getIfPart();
+ complexityValue += computeConditionalComplexity(ifPart, methodName, monitor);
+ for (Conditional elseIfPart : ifStatement.getElsIfParts())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeConditionalComplexity(elseIfPart, methodName, monitor);
+ }
+ EList substatements = ifStatement.getElseStatements();
+ if (!substatements.isEmpty())
+ {
+ for (Statement substatement : substatements)
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeStatementComplexity(substatement, methodName, monitor);
+ }
+ }
+ }
+ else if (statement instanceof TryExceptStatement)
+ {
+ TryExceptStatement tryExceptStatement = (TryExceptStatement)statement;
+ for (Statement substatement : tryExceptStatement.getTryStatements())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeStatementComplexity(substatement, methodName, monitor);
+ }
+ for (Statement substatement : tryExceptStatement.getExceptStatements())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue++;
+ complexityValue += computeStatementComplexity(substatement, methodName, monitor);
+ }
+ }
+ else if (statement instanceof SimpleStatement)
+ {
+ SimpleStatement simpleStatement = (SimpleStatement)statement;
+ complexityValue += computeExpressionComplexity(simpleStatement.getLeft(), methodName, monitor);
+ Expression right = simpleStatement.getRight();
+ if (right != null)
+ {
+ complexityValue += computeExpressionComplexity(right, methodName, monitor);
+ }
+ }
+
+ return complexityValue;
+ }
+
+ private int computeConditionalComplexity(Conditional conditional, String methodName,
+ IProgressMonitor monitor)
+ {
+ int complexityValue = 1;
+ complexityValue += computeExpressionComplexity(conditional.getPredicate(), methodName, monitor);
+ for (Statement substatement : conditional.getStatements())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeStatementComplexity(substatement, methodName, monitor);
+ }
+ return complexityValue;
+ }
+
+ private int computeExpressionComplexity(Expression expression, String methodName,
+ IProgressMonitor monitor)
+ {
+ int complexityValue = 0;
+ if (expression instanceof BinaryExpression)
+ {
+ BinaryExpression binaryExpression = (BinaryExpression)expression;
+ BinaryOperation operation = binaryExpression.getOperation();
+ if (operation == BinaryOperation.AND || operation == BinaryOperation.OR)
+ {
+ complexityValue++;
+ }
+ complexityValue +=
+ computeExpressionComplexity(binaryExpression.getLeft(), methodName, monitor);
+ complexityValue +=
+ computeExpressionComplexity(binaryExpression.getRight(), methodName, monitor);
+ }
+ else if (expression instanceof UnaryExpression)
+ {
+ complexityValue += computeExpressionComplexity(((UnaryExpression)expression).getOperand(),
+ methodName, monitor);
+ }
+ else if (expression instanceof DynamicFeatureAccess)
+ {
+ complexityValue += computeExpressionComplexity(((DynamicFeatureAccess)expression).getSource(),
+ methodName, monitor);
+ }
+ else if (expression instanceof Invocation)
+ {
+ Invocation invocation = (Invocation)expression;
+
+ FeatureAccess method = invocation.getMethodAccess();
+ if (method.getName().equals(TRENARY_OPERATOR))
+ {
+ complexityValue++;
+ }
+ for (Expression parameter : invocation.getParams())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeExpressionComplexity(parameter, methodName, monitor);
+ }
+ }
+ else if (expression instanceof IndexAccess)
+ {
+ IndexAccess indexAccess = (IndexAccess)expression;
+ complexityValue += computeExpressionComplexity(indexAccess.getSource(), methodName, monitor);
+ complexityValue += computeExpressionComplexity(indexAccess.getIndex(), methodName, monitor);
+ }
+ else if (expression instanceof FunctionStyleCreator)
+ {
+ FunctionStyleCreator creator = (FunctionStyleCreator)expression;
+ complexityValue +=
+ computeExpressionComplexity(creator.getTypeNameExpression(), methodName, monitor);
+ Expression params = creator.getParamsExpression();
+ if (params != null)
+ {
+ complexityValue += computeExpressionComplexity(params, methodName, monitor);
+ }
+ }
+ else if (expression instanceof OperatorStyleCreator)
+ {
+ for (Expression parameter : ((OperatorStyleCreator)expression).getParams())
+ {
+ if (monitor.isCanceled())
+ {
+ return 0;
+ }
+ complexityValue += computeExpressionComplexity(parameter, methodName, monitor);
+ }
+ }
+ return complexityValue;
+ }
+}
diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/IComplexityProcessor.java b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/IComplexityProcessor.java
new file mode 100644
index 000000000..cedf6bd7b
--- /dev/null
+++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/IComplexityProcessor.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (C) 2023, 1C-Soft LLC and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Manaev Konstantin - initial API and implementation
+ *******************************************************************************/
+package com.e1c.v8codestyle.bsl;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import com._1c.g5.v8.dt.bsl.model.Method;
+
+/**
+ * The processor of method's complexity.
+ * This processor compute complexity score by method.
+ *
+ *
+ * @author Manaev Konstantin
+ */
+public interface IComplexityProcessor
+{
+
+ /**
+ * Compute complexity score by method.
+ *
+ * @param method the method, cannot be {@code null}.
+ * @param monitor the progress monitor, cannot be {@code null}.
+ * @return score of complexity
+ */
+ int compute(Method method, IProgressMonitor monitor);
+}
diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/CognitiveComplexityCheck.java b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/CognitiveComplexityCheck.java
new file mode 100644
index 000000000..103ee55bb
--- /dev/null
+++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/CognitiveComplexityCheck.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (C) 2023, 1C-Soft LLC and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * 1C-Soft LLC - initial API and implementation
+ * Manaev Konstantin - issue #1117
+ *******************************************************************************/
+package com.e1c.v8codestyle.bsl.check;
+
+import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.METHOD;
+import static com._1c.g5.v8.dt.mcore.McorePackage.Literals.NAMED_ELEMENT__NAME;
+
+import java.text.MessageFormat;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import com._1c.g5.v8.dt.bsl.model.Method;
+import com.e1c.g5.v8.dt.check.CheckComplexity;
+import com.e1c.g5.v8.dt.check.ICheckParameters;
+import com.e1c.g5.v8.dt.check.components.BasicCheck;
+import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
+import com.e1c.g5.v8.dt.check.settings.IssueType;
+import com.e1c.v8codestyle.bsl.CognitiveComplexityProcessor;
+import com.e1c.v8codestyle.bsl.IComplexityProcessor;
+import com.e1c.v8codestyle.check.CommonSenseCheckExtension;
+import com.e1c.v8codestyle.internal.bsl.BslPlugin;
+
+/**
+ * Checks the method that a cognitive complexity is less a threshold.
+ *
+ * @author Manaev Konstantin
+ */
+public final class CognitiveComplexityCheck
+ extends BasicCheck
+{
+
+ private static final String CHECK_ID = "cognitive-complexity"; //$NON-NLS-1$
+ private static final String PARAM_COMPLEXTITY_THRESHOLD = "complexityThreshold"; //$NON-NLS-1$
+ private static final String DEFAULT_COMPLEXITY_THRESHOLD = "15"; //$NON-NLS-1$
+
+ @Override
+ public String getCheckId()
+ {
+ return CHECK_ID;
+ }
+
+ @Override
+ protected void configureCheck(CheckConfigurer builder)
+ {
+ builder.title(Messages.CognitiveComplexityCheck_title)
+ .description(MessageFormat.format(Messages.CognitiveComplexityCheck_description, DEFAULT_COMPLEXITY_THRESHOLD))
+ .complexity(CheckComplexity.NORMAL)
+ .severity(IssueSeverity.MINOR)
+ .issueType(IssueType.WARNING)
+ .extension(new CommonSenseCheckExtension(getCheckId(), BslPlugin.PLUGIN_ID))
+ .module()
+ .checkedObjectType(METHOD)
+ .parameter(PARAM_COMPLEXTITY_THRESHOLD, Integer.class, DEFAULT_COMPLEXITY_THRESHOLD,
+ Messages.CognitiveComplexityCheck_param_threshold_name);
+ }
+
+ @Override
+ protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
+ IProgressMonitor monitor)
+ {
+
+ Method method = (Method)object;
+ if (method != null)
+ {
+ IComplexityProcessor processor = new CognitiveComplexityProcessor();
+ int complexityValue = processor.compute(method, monitor);
+
+ int complexityThreshold = parameters.getInt(PARAM_COMPLEXTITY_THRESHOLD);
+ if (complexityValue > complexityThreshold)
+ {
+ resultAceptor.addIssue(MessageFormat.format(Messages.CognitiveComplexityCheck_issue_message,
+ Integer.toString(complexityValue), Integer.toString(complexityThreshold)), NAMED_ELEMENT__NAME);
+ }
+ }
+
+ }
+
+}
diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/CyclomaticComplexityCheck.java b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/CyclomaticComplexityCheck.java
new file mode 100644
index 000000000..2b9e0b1b3
--- /dev/null
+++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/CyclomaticComplexityCheck.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (C) 2023, 1C-Soft LLC and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * 1C-Soft LLC - initial API and implementation
+ * Manaev Konstantin - issue #1117
+ *******************************************************************************/
+package com.e1c.v8codestyle.bsl.check;
+
+import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.METHOD;
+import static com._1c.g5.v8.dt.mcore.McorePackage.Literals.NAMED_ELEMENT__NAME;
+
+import java.text.MessageFormat;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import com._1c.g5.v8.dt.bsl.model.Method;
+import com.e1c.g5.v8.dt.check.CheckComplexity;
+import com.e1c.g5.v8.dt.check.ICheckParameters;
+import com.e1c.g5.v8.dt.check.components.BasicCheck;
+import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
+import com.e1c.g5.v8.dt.check.settings.IssueType;
+import com.e1c.v8codestyle.bsl.CyclomaticComplexityProcessor;
+import com.e1c.v8codestyle.bsl.IComplexityProcessor;
+import com.e1c.v8codestyle.check.CommonSenseCheckExtension;
+import com.e1c.v8codestyle.internal.bsl.BslPlugin;
+
+public final class CyclomaticComplexityCheck
+ extends BasicCheck
+{
+ private static final String CHECK_ID = "cyclomatic-complexity"; //$NON-NLS-1$
+ private static final String PARAM_COMPLEXTITY_THRESHOLD = "complexityThreshold"; //$NON-NLS-1$
+ private static final String DEFAULT_COMPLEXITY_THRESHOLD = "20"; //$NON-NLS-1$
+
+ @Override
+ public String getCheckId()
+ {
+ return CHECK_ID;
+ }
+
+ @Override
+ protected void configureCheck(CheckConfigurer builder)
+ {
+ builder.title(Messages.CyclomaticComplexity_title)
+ .description(MessageFormat.format(Messages.CyclomaticComplexity_description, DEFAULT_COMPLEXITY_THRESHOLD))
+ .complexity(CheckComplexity.NORMAL)
+ .severity(IssueSeverity.MINOR)
+ .issueType(IssueType.WARNING)
+ .extension(new CommonSenseCheckExtension(getCheckId(), BslPlugin.PLUGIN_ID))
+ .module()
+ .checkedObjectType(METHOD)
+ .parameter(PARAM_COMPLEXTITY_THRESHOLD, Integer.class, DEFAULT_COMPLEXITY_THRESHOLD,
+ Messages.CyclomaticComplexity_param_threshold_name);
+ }
+
+ @Override
+ protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
+ IProgressMonitor monitor)
+ {
+
+ Method method = (Method)object;
+ if (method != null)
+ {
+ IComplexityProcessor processor = new CyclomaticComplexityProcessor();
+ int complexityValue = processor.compute(method, monitor);
+
+ int complexityThreshold = parameters.getInt(PARAM_COMPLEXTITY_THRESHOLD);
+ if (complexityValue > complexityThreshold)
+ {
+ resultAceptor.addIssue(MessageFormat.format(Messages.CyclomaticComplexity_issues_message,
+ Integer.toString(complexityValue), Integer.toString(complexityThreshold)), NAMED_ELEMENT__NAME);
+ }
+ }
+
+ }
+
+}
diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/Messages.java b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/Messages.java
index 2846ab91c..d9d209e05 100644
--- a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/Messages.java
+++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/Messages.java
@@ -61,6 +61,14 @@ final class Messages
public static String ChangeAndValidateInsteadOfAroundCheck_Use_ChangeAndValidate_instead_of_Around;
public static String ChangeAndValidateInsteadOfAroundCheck_title;
+ public static String CognitiveComplexityCheck_description;
+
+ public static String CognitiveComplexityCheck_issue_message;
+
+ public static String CognitiveComplexityCheck_param_threshold_name;
+
+ public static String CognitiveComplexityCheck_title;
+
public static String CommitTransactionCheck_Commit_transaction_must_be_in_try_catch;
public static String CommitTransactionCheck_No_begin_transaction_for_commit_transaction;
@@ -109,6 +117,14 @@ final class Messages
public static String ConsecutiveEmptyLines_Title;
+ public static String CyclomaticComplexity_description;
+
+ public static String CyclomaticComplexity_issues_message;
+
+ public static String CyclomaticComplexity_param_threshold_name;
+
+ public static String CyclomaticComplexity_title;
+
public static String DeprecatedProcedureOutsideDeprecatedRegionCheck_Deprecated_function_out_of_deprecated_area;
public static String DeprecatedProcedureOutsideDeprecatedRegionCheck_description;
diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages.properties b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages.properties
index 5ce5b72a8..29fae8618 100644
--- a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages.properties
+++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages.properties
@@ -62,6 +62,14 @@ ChangeAndValidateInsteadOfAroundCheck_description = Checks that pragma &ChangeAn
ChangeAndValidateInsteadOfAroundCheck_title = Use pragma &ChangeAndValidate instead of &Around
+CognitiveComplexityCheck_description=The cognitive complexity of the method is more then {0}
+
+CognitiveComplexityCheck_issue_message=Reduce the cognitive complexity of the method from {0} to {1}
+
+CognitiveComplexityCheck_param_threshold_name=Complexity threshold
+
+CognitiveComplexityCheck_title=The cognitive complexity of the method is exceeded
+
CommitTransactionCheck_Commit_transaction_must_be_in_try_catch = Commit transaction must be in a try-catch
CommitTransactionCheck_No_begin_transaction_for_commit_transaction = There is no begin transaction for commit transaction
@@ -96,6 +104,14 @@ ConsecutiveEmptyLines_Sequence_of_empty_lines_between__0__and__1__is_greator_tha
ConsecutiveEmptyLines_Title = Consecutive empty lines
+CyclomaticComplexity_description=The cyclomatic complexity of the method is more then {0}
+
+CyclomaticComplexity_issues_message=Reduce the cyclomatic complexity of the method from {0} to {1}
+
+CyclomaticComplexity_param_threshold_name=Complexity threshold
+
+CyclomaticComplexity_title=The cyclomatic complexity of the method is exceeded
+
DeprecatedProcedureOutsideDeprecatedRegionCheck_Deprecated_function_out_of_deprecated_area = The deprecated procedure (function) "{0}" should be placed in the Deprecated region of the Public region in a common module area
DeprecatedProcedureOutsideDeprecatedRegionCheck_description = Deprecated procedure (function) should be placed in the Deprecated region of the Public region in a common module area
diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages_ru.properties b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages_ru.properties
index 8f953cee6..e94aa4a17 100644
--- a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages_ru.properties
+++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages_ru.properties
@@ -62,6 +62,14 @@ ChangeAndValidateInsteadOfAroundCheck_description = Проверяет, что
ChangeAndValidateInsteadOfAroundCheck_title = Используется аннотация &ИзменениеИКонтроль вместо &Вместо
+CognitiveComplexityCheck_description=Когнитивная сложность метода больше {0}
+
+CognitiveComplexityCheck_issue_message=Понизьте когнитивную сложность метода с {0} до {1}
+
+CognitiveComplexityCheck_param_threshold_name=Допустимая сложность
+
+CognitiveComplexityCheck_title=Превышена когнитивная сложность метода
+
CommitTransactionCheck_Commit_transaction_must_be_in_try_catch = Вызов "ЗафиксироватьТранзакцию()" находится вне конструкции "Попытка... Исключение"
CommitTransactionCheck_No_begin_transaction_for_commit_transaction = Отсутствует вызов "НачатьТранзакцию()", хотя вызываются "ЗафиксироватьТранзакцию()"
@@ -100,6 +108,14 @@ ConsecutiveEmptyLines_Sequence_of_empty_lines_between__0__and__1__is_greator_tha
ConsecutiveEmptyLines_Title = Последовательность пустых строк
+CyclomaticComplexity_description=Цикломатическая сложность больше {0}
+
+CyclomaticComplexity_issues_message=Понизьте цикломатическую сложность с {0} до {1}
+
+CyclomaticComplexity_param_threshold_name=Допустимая сложность
+
+CyclomaticComplexity_title=Превышена цикломатическая сложность
+
DeprecatedProcedureOutsideDeprecatedRegionCheck_Deprecated_function_out_of_deprecated_area = Устаревшую процедуру (функцию) "{0}" следует перенести в область общего модуля УстаревшиеПроцедурыИФункции, размещенную внутри области ПрограммныйИнтерфейс
DeprecatedProcedureOutsideDeprecatedRegionCheck_description = Устаревшую процедуру (функцию) следует перенести в область общего модуля УстаревшиеПроцедурыИФункции, размещенную внутри области ПрограммныйИнтерфейс