Skip to content

Commit 5cd5187

Browse files
committed
Добавил проверку цикломатической сложности
1 parent 7b98a37 commit 5cd5187

10 files changed

+483
-1
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#### Код модулей
1919

2020
- Проверка когнитивной сложности методов
21+
- Проверка цикломатической сложности методов
2122

2223

2324
#### Запросы
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# The cyclomatic complexity of the method is exceeded
2+
3+
Thomas J. McCabe developed a cyclomatic metric for code testing tasks.
4+
His proposed method calculates the number of linearly independent program execution threads.
5+
The difficulty value corresponds to the number of tests required.
6+
7+
The most effective way to reduce the complexity score is to decompose the code and simplify logical expressions.
8+
9+
## Compute rules:
10+
11+
### Increments:
12+
13+
- Loops:
14+
```bsl
15+
For Item In Collection Do
16+
// code
17+
EndDo;
18+
```
19+
```bsl
20+
For index = 1 To N Do
21+
// code
22+
EndDo;
23+
```
24+
```bsl
25+
While Conditional Do
26+
// code
27+
EndDo;
28+
```
29+
- Conditional statements:
30+
```bsl
31+
If Conditional Then // +1 point
32+
// code
33+
EndIf;
34+
35+
If Conditional Then // too +1 point
36+
// code
37+
Else
38+
// code
39+
EndIf;
40+
```
41+
```bsl
42+
If Conditional1 Then // +1 point
43+
// code
44+
ElseIf Conditional2 Then // +1 additional point
45+
// code
46+
ElseIf Conditional3 Then // +1 additional point
47+
// code
48+
Else // the Else does not increase the complexity
49+
// code
50+
EndIf;
51+
```
52+
- Try-Exception blocks:
53+
```bsl
54+
Try
55+
// code
56+
Exception
57+
// code
58+
EndTry;
59+
```
60+
- Booleands operands: AND, OR
61+
- Trenary operator:
62+
```bsl
63+
?(Coditional, Value1, Value2);
64+
```
65+
- Procedure or Function initially has a complexity equal to 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Превышение цикломатической сложности метода
2+
3+
Томас Дж. Маккейб для задач тестирования кода разработал цикломатическую метрику.
4+
Предложенный им метод вычисляет количество линейно независимых потоков исполнения программы.
5+
Значение сложности соответствует числу необходимы тестов.
6+
7+
Наиболее эффективным способом уменьшения показателя сложности является декомпозиция кода и упрощение логических выражений.
8+
9+
## Правила вычисления:
10+
11+
### Конструкции, увеличивающие цикломатическую сложность:
12+
13+
- Циклы:
14+
```bsl
15+
Для Каждого Элемент Из Коллекция Цикл
16+
// код
17+
КонецЦикла;
18+
```
19+
```bsl
20+
Для Индекс = 1 По Гранца Цикл
21+
// код
22+
КонецЦикла;
23+
```
24+
```bsl
25+
Пока Условие Цикл
26+
// код
27+
КонецЦикла;
28+
```
29+
- Условия:
30+
```bsl
31+
// ветвление увеличивает цикломатическу сложность на единицу, не зависимо от наличия/отсутствия блока Иначе
32+
Если Условие Тогда // +1 к сложности
33+
// Код
34+
КонецЕсли;
35+
36+
Если Условие Тогда // тоже +1 к сложности за всю конструкцию
37+
// Код
38+
Иначе
39+
// Код
40+
КонецЕсли;
41+
```
42+
```bsl
43+
// Каждый блок ИначеЕсли увеличивает сложность на дополнительную единицу
44+
Если Условие1 Тогда // +1 за условный блок
45+
// код
46+
ИначеЕсли Условие2 Тогда // +1 дополнительно за ветвь
47+
// код
48+
ИначеЕсли Условие3 Тогда // +1 дополнительно за ветвь
49+
// код
50+
Иначе // блок иначе не увеличивает сложность
51+
// код
52+
КонецЕсли;
53+
```
54+
- Блок обработки исключения:
55+
```bsl
56+
Попытка
57+
// код
58+
Исключение
59+
// код
60+
КонецПопытки;
61+
```
62+
- Логические операции И, ИЛИ
63+
- Тренарный оператор:
64+
```bsl
65+
?(Условие, Значение1, Значение2);
66+
```
67+
- Процедура или Функция изначально имеет сложность равную 1

bundles/com.e1c.v8codestyle.bsl/plugin.xml

+4
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,10 @@
351351
category="com.e1c.v8codestyle.bsl"
352352
class="com.e1c.v8codestyle.bsl.check.CognitiveComplexityCheck">
353353
</check>
354+
<check
355+
category="com.e1c.v8codestyle.bsl"
356+
class="com.e1c.v8codestyle.bsl.check.CyclomaticComplexityCheck">
357+
</check>
354358
</extension>
355359
<extension
356360
point="org.eclipse.core.runtime.preferences">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/*******************************************************************************
2+
* Copyright (C) 2023, 1C-Soft LLC and others.
3+
*
4+
* This program and the accompanying materials are made
5+
* available under the terms of the Eclipse Public License 2.0
6+
* which is available at https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Manaev Konstantin - initial API and implementation
12+
*******************************************************************************/
13+
package com.e1c.v8codestyle.bsl;
14+
15+
import org.eclipse.core.runtime.IProgressMonitor;
16+
import org.eclipse.emf.common.util.EList;
17+
18+
import com._1c.g5.v8.dt.bsl.model.BinaryExpression;
19+
import com._1c.g5.v8.dt.bsl.model.BinaryOperation;
20+
import com._1c.g5.v8.dt.bsl.model.Conditional;
21+
import com._1c.g5.v8.dt.bsl.model.DynamicFeatureAccess;
22+
import com._1c.g5.v8.dt.bsl.model.Expression;
23+
import com._1c.g5.v8.dt.bsl.model.FeatureAccess;
24+
import com._1c.g5.v8.dt.bsl.model.FunctionStyleCreator;
25+
import com._1c.g5.v8.dt.bsl.model.IfStatement;
26+
import com._1c.g5.v8.dt.bsl.model.IndexAccess;
27+
import com._1c.g5.v8.dt.bsl.model.Invocation;
28+
import com._1c.g5.v8.dt.bsl.model.LoopStatement;
29+
import com._1c.g5.v8.dt.bsl.model.Method;
30+
import com._1c.g5.v8.dt.bsl.model.OperatorStyleCreator;
31+
import com._1c.g5.v8.dt.bsl.model.SimpleStatement;
32+
import com._1c.g5.v8.dt.bsl.model.Statement;
33+
import com._1c.g5.v8.dt.bsl.model.TryExceptStatement;
34+
import com._1c.g5.v8.dt.bsl.model.UnaryExpression;
35+
import com._1c.g5.v8.dt.bsl.model.WhileStatement;
36+
37+
/**
38+
* The cyclomatic complexity processor.
39+
*
40+
* @author Manaev Konstantin
41+
*/
42+
public final class CyclomaticComplexityProcessor
43+
implements IComplexityProcessor
44+
{
45+
46+
private static final String TRENARY_OPERATOR = "?"; //$NON-NLS-1$
47+
48+
@Override
49+
public int compute(Method method, IProgressMonitor monitor)
50+
{
51+
int complexityValue = 1;
52+
String uniqueName = method.getName();
53+
for (Statement statement : method.allStatements())
54+
{
55+
if (monitor.isCanceled())
56+
{
57+
return 0;
58+
}
59+
complexityValue += computeStatementComplexity(statement, uniqueName, monitor);
60+
}
61+
return complexityValue;
62+
}
63+
64+
private int computeStatementComplexity(Statement statement, String methodName,
65+
IProgressMonitor monitor)
66+
{
67+
int complexityValue = 0;
68+
if (statement instanceof LoopStatement)
69+
{
70+
complexityValue++;
71+
if (statement instanceof WhileStatement)
72+
{
73+
complexityValue += computeExpressionComplexity(((WhileStatement)statement).getPredicate(),
74+
methodName, monitor);
75+
}
76+
for (Statement substatement : ((LoopStatement)statement).getStatements())
77+
{
78+
if (monitor.isCanceled())
79+
{
80+
return 0;
81+
}
82+
complexityValue += computeStatementComplexity(substatement, methodName, monitor);
83+
}
84+
}
85+
else if (statement instanceof IfStatement)
86+
{
87+
IfStatement ifStatement = (IfStatement)statement;
88+
Conditional ifPart = ifStatement.getIfPart();
89+
complexityValue += computeConditionalComplexity(ifPart, methodName, monitor);
90+
for (Conditional elseIfPart : ifStatement.getElsIfParts())
91+
{
92+
if (monitor.isCanceled())
93+
{
94+
return 0;
95+
}
96+
complexityValue += computeConditionalComplexity(elseIfPart, methodName, monitor);
97+
}
98+
EList<Statement> substatements = ifStatement.getElseStatements();
99+
if (!substatements.isEmpty())
100+
{
101+
for (Statement substatement : substatements)
102+
{
103+
if (monitor.isCanceled())
104+
{
105+
return 0;
106+
}
107+
complexityValue += computeStatementComplexity(substatement, methodName, monitor);
108+
}
109+
}
110+
}
111+
else if (statement instanceof TryExceptStatement)
112+
{
113+
TryExceptStatement tryExceptStatement = (TryExceptStatement)statement;
114+
for (Statement substatement : tryExceptStatement.getTryStatements())
115+
{
116+
if (monitor.isCanceled())
117+
{
118+
return 0;
119+
}
120+
complexityValue += computeStatementComplexity(substatement, methodName, monitor);
121+
}
122+
for (Statement substatement : tryExceptStatement.getExceptStatements())
123+
{
124+
if (monitor.isCanceled())
125+
{
126+
return 0;
127+
}
128+
complexityValue++;
129+
complexityValue += computeStatementComplexity(substatement, methodName, monitor);
130+
}
131+
}
132+
else if (statement instanceof SimpleStatement)
133+
{
134+
SimpleStatement simpleStatement = (SimpleStatement)statement;
135+
complexityValue += computeExpressionComplexity(simpleStatement.getLeft(), methodName, monitor);
136+
Expression right = simpleStatement.getRight();
137+
if (right != null)
138+
{
139+
complexityValue += computeExpressionComplexity(right, methodName, monitor);
140+
}
141+
}
142+
143+
return complexityValue;
144+
}
145+
146+
private int computeConditionalComplexity(Conditional conditional, String methodName,
147+
IProgressMonitor monitor)
148+
{
149+
int complexityValue = 1;
150+
complexityValue += computeExpressionComplexity(conditional.getPredicate(), methodName, monitor);
151+
for (Statement substatement : conditional.getStatements())
152+
{
153+
if (monitor.isCanceled())
154+
{
155+
return 0;
156+
}
157+
complexityValue += computeStatementComplexity(substatement, methodName, monitor);
158+
}
159+
return complexityValue;
160+
}
161+
162+
private int computeExpressionComplexity(Expression expression, String methodName,
163+
IProgressMonitor monitor)
164+
{
165+
int complexityValue = 0;
166+
if (expression instanceof BinaryExpression)
167+
{
168+
BinaryExpression binaryExpression = (BinaryExpression)expression;
169+
BinaryOperation operation = binaryExpression.getOperation();
170+
if (operation == BinaryOperation.AND || operation == BinaryOperation.OR)
171+
{
172+
complexityValue++;
173+
}
174+
complexityValue +=
175+
computeExpressionComplexity(binaryExpression.getLeft(), methodName, monitor);
176+
complexityValue +=
177+
computeExpressionComplexity(binaryExpression.getRight(), methodName, monitor);
178+
}
179+
else if (expression instanceof UnaryExpression)
180+
{
181+
complexityValue += computeExpressionComplexity(((UnaryExpression)expression).getOperand(),
182+
methodName, monitor);
183+
}
184+
else if (expression instanceof DynamicFeatureAccess)
185+
{
186+
complexityValue += computeExpressionComplexity(((DynamicFeatureAccess)expression).getSource(),
187+
methodName, monitor);
188+
}
189+
else if (expression instanceof Invocation)
190+
{
191+
Invocation invocation = (Invocation)expression;
192+
193+
FeatureAccess method = invocation.getMethodAccess();
194+
if (method.getName().equals(TRENARY_OPERATOR))
195+
{
196+
complexityValue++;
197+
}
198+
for (Expression parameter : invocation.getParams())
199+
{
200+
if (monitor.isCanceled())
201+
{
202+
return 0;
203+
}
204+
complexityValue += computeExpressionComplexity(parameter, methodName, monitor);
205+
}
206+
}
207+
else if (expression instanceof IndexAccess)
208+
{
209+
IndexAccess indexAccess = (IndexAccess)expression;
210+
complexityValue += computeExpressionComplexity(indexAccess.getSource(), methodName, monitor);
211+
complexityValue += computeExpressionComplexity(indexAccess.getIndex(), methodName, monitor);
212+
}
213+
else if (expression instanceof FunctionStyleCreator)
214+
{
215+
FunctionStyleCreator creator = (FunctionStyleCreator)expression;
216+
complexityValue +=
217+
computeExpressionComplexity(creator.getTypeNameExpression(), methodName, monitor);
218+
Expression params = creator.getParamsExpression();
219+
if (params != null)
220+
{
221+
complexityValue += computeExpressionComplexity(params, methodName, monitor);
222+
}
223+
}
224+
else if (expression instanceof OperatorStyleCreator)
225+
{
226+
for (Expression parameter : ((OperatorStyleCreator)expression).getParams())
227+
{
228+
if (monitor.isCanceled())
229+
{
230+
return 0;
231+
}
232+
complexityValue += computeExpressionComplexity(parameter, methodName, monitor);
233+
}
234+
}
235+
return complexityValue;
236+
}
237+
}

0 commit comments

Comments
 (0)