Skip to content

Commit aad14a0

Browse files
committed
Черновик проверки когнитивной сложности
1 parent f4095b1 commit aad14a0

File tree

4 files changed

+232
-0
lines changed

4 files changed

+232
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# TODO: description
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# TODO: описание

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

+4
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,10 @@
347347
category="com.e1c.v8codestyle.bsl"
348348
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.check.DeprecatedProcedureOutsideDeprecatedRegionCheck">
349349
</check>
350+
<check
351+
category="com.e1c.v8codestyle.bsl"
352+
class="com.e1c.v8codestyle.bsl.check.CognitiveComplexityCheck">
353+
</check>
350354
</extension>
351355
<extension
352356
point="org.eclipse.core.runtime.preferences">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
package com.e1c.v8codestyle.bsl.check;
2+
3+
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.METHOD;
4+
import static com._1c.g5.v8.dt.mcore.McorePackage.Literals.NAMED_ELEMENT__NAME;
5+
6+
import java.util.Set;
7+
8+
import org.eclipse.core.runtime.IProgressMonitor;
9+
import org.eclipse.emf.common.util.EList;
10+
11+
import com._1c.g5.v8.dt.bsl.model.BinaryExpression;
12+
import com._1c.g5.v8.dt.bsl.model.BinaryOperation;
13+
import com._1c.g5.v8.dt.bsl.model.Conditional;
14+
import com._1c.g5.v8.dt.bsl.model.DynamicFeatureAccess;
15+
import com._1c.g5.v8.dt.bsl.model.Expression;
16+
import com._1c.g5.v8.dt.bsl.model.FunctionStyleCreator;
17+
import com._1c.g5.v8.dt.bsl.model.GotoStatement;
18+
import com._1c.g5.v8.dt.bsl.model.IfStatement;
19+
import com._1c.g5.v8.dt.bsl.model.IndexAccess;
20+
import com._1c.g5.v8.dt.bsl.model.Invocation;
21+
import com._1c.g5.v8.dt.bsl.model.LoopStatement;
22+
import com._1c.g5.v8.dt.bsl.model.Method;
23+
import com._1c.g5.v8.dt.bsl.model.OperatorStyleCreator;
24+
import com._1c.g5.v8.dt.bsl.model.SimpleStatement;
25+
import com._1c.g5.v8.dt.bsl.model.Statement;
26+
import com._1c.g5.v8.dt.bsl.model.TryExceptStatement;
27+
import com._1c.g5.v8.dt.bsl.model.UnaryExpression;
28+
import com._1c.g5.v8.dt.bsl.model.WhileStatement;
29+
import com.e1c.g5.v8.dt.check.CheckComplexity;
30+
import com.e1c.g5.v8.dt.check.ICheckParameters;
31+
import com.e1c.g5.v8.dt.check.components.BasicCheck;
32+
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
33+
import com.e1c.g5.v8.dt.check.settings.IssueType;
34+
import com.e1c.v8codestyle.check.CommonSenseCheckExtension;
35+
import com.e1c.v8codestyle.internal.bsl.BslPlugin;
36+
37+
public final class CognitiveComplexityCheck
38+
extends BasicCheck
39+
{
40+
41+
private static final String CHECK_ID = "cognitive-complexity"; //$NON-NLS-1$
42+
private static Set<BinaryOperation> COMPLEXITY_OPERATORS = Set.of(BinaryOperation.OR, BinaryOperation.AND);
43+
44+
@Override
45+
public String getCheckId()
46+
{
47+
return CHECK_ID;
48+
}
49+
50+
@Override
51+
protected void configureCheck(CheckConfigurer builder)
52+
{
53+
builder.title("Когнитивная сложность")
54+
.description("Когнитивная сложность")
55+
.complexity(CheckComplexity.NORMAL)
56+
.severity(IssueSeverity.MINOR)
57+
.issueType(IssueType.WARNING)
58+
.extension(new CommonSenseCheckExtension(getCheckId(), BslPlugin.PLUGIN_ID))
59+
.module()
60+
.checkedObjectType(METHOD)
61+
.parameter("complexityThreshold", Integer.class, "15", "Допустимая сложность");
62+
}
63+
64+
@Override
65+
protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
66+
IProgressMonitor monitor)
67+
{
68+
int complexityValue = 0;
69+
int nestedLevel = 0;
70+
Method method = (Method)object;
71+
for (Statement statement : method.getStatements())
72+
{
73+
if (monitor.isCanceled())
74+
{
75+
return;
76+
}
77+
complexityValue += computeStatementComplexity(statement, nestedLevel, monitor);
78+
}
79+
int complexityThreshold = parameters.getInt("complexityThreshold");
80+
if (complexityValue > complexityThreshold)
81+
{
82+
resultAceptor.addIssue("Когнитивная сложность " + Integer.toString(complexityValue), NAMED_ELEMENT__NAME);
83+
}
84+
}
85+
86+
private int computeStatementComplexity(Statement statement, int nestedLevel, IProgressMonitor monitor)
87+
{
88+
int complexityValue = 0;
89+
if (monitor.isCanceled())
90+
{
91+
return complexityValue;
92+
}
93+
if (statement instanceof LoopStatement)
94+
{
95+
complexityValue += 1 + nestedLevel;
96+
if (statement instanceof WhileStatement)
97+
{
98+
complexityValue +=
99+
computeExpressionComplexity(((WhileStatement)statement).getPredicate(), nestedLevel, monitor);
100+
}
101+
for (Statement substatement : ((LoopStatement)statement).getStatements())
102+
{
103+
complexityValue += computeStatementComplexity(substatement, nestedLevel + 1, monitor);
104+
}
105+
}
106+
else if (statement instanceof IfStatement)
107+
{
108+
complexityValue += nestedLevel;
109+
IfStatement ifStatement = (IfStatement)statement;
110+
Conditional ifPart = ifStatement.getIfPart();
111+
complexityValue += computeConditionalComplexity(ifPart, nestedLevel, monitor);
112+
for (Conditional elseIfPart : ifStatement.getElsIfParts())
113+
{
114+
complexityValue += computeConditionalComplexity(elseIfPart, nestedLevel, monitor);
115+
}
116+
EList<Statement> substatements = ifStatement.getElseStatements();
117+
if (!substatements.isEmpty())
118+
{
119+
complexityValue++;
120+
for (Statement substatement : substatements)
121+
{
122+
complexityValue += computeStatementComplexity(substatement, nestedLevel + 1, monitor);
123+
}
124+
}
125+
}
126+
else if (statement instanceof TryExceptStatement)
127+
{
128+
TryExceptStatement tryExceptStatement = (TryExceptStatement)statement;
129+
for (Statement substatement : tryExceptStatement.getTryStatements())
130+
{
131+
complexityValue += computeStatementComplexity(substatement, nestedLevel, monitor);
132+
}
133+
for (Statement substatement : tryExceptStatement.getExceptStatements())
134+
{
135+
complexityValue += nestedLevel + 1;
136+
complexityValue += computeStatementComplexity(substatement, nestedLevel + 1, monitor);
137+
}
138+
}
139+
else if (statement instanceof GotoStatement)
140+
{
141+
complexityValue++;
142+
}
143+
else if (statement instanceof SimpleStatement)
144+
{
145+
SimpleStatement simpleStatement = (SimpleStatement)statement;
146+
complexityValue += computeExpressionComplexity(simpleStatement.getLeft(), nestedLevel, monitor);
147+
Expression right = simpleStatement.getRight();
148+
if (right != null)
149+
{
150+
complexityValue += computeExpressionComplexity(right, nestedLevel, monitor);
151+
}
152+
}
153+
154+
return complexityValue;
155+
}
156+
157+
private int computeConditionalComplexity(Conditional conditional, int nestedLevel, IProgressMonitor monitor)
158+
{
159+
int complexityValue = 1;
160+
complexityValue += computeExpressionComplexity(conditional.getPredicate(), nestedLevel, monitor);
161+
for (Statement substatement : conditional.getStatements())
162+
{
163+
complexityValue += computeStatementComplexity(substatement, nestedLevel + 1, monitor);
164+
}
165+
return complexityValue;
166+
}
167+
168+
private int computeExpressionComplexity(Expression expression, int nestedLevel, IProgressMonitor monitor)
169+
{
170+
// TODO: увеличивать вложенность для тренарного оператора и вложенного метода
171+
// TODO: увелисть сложность для тренарного оператора и рекурсивного вызова
172+
int complexityValue = 0;
173+
if (expression instanceof BinaryExpression)
174+
{
175+
BinaryExpression binaryExpression = (BinaryExpression)expression;
176+
if (COMPLEXITY_OPERATORS.contains(binaryExpression.getOperation()))
177+
{
178+
complexityValue++;
179+
}
180+
complexityValue += computeExpressionComplexity(binaryExpression.getLeft(), nestedLevel, monitor);
181+
complexityValue += computeExpressionComplexity(binaryExpression.getRight(), nestedLevel, monitor);
182+
}
183+
else if (expression instanceof UnaryExpression)
184+
{
185+
complexityValue +=
186+
computeExpressionComplexity(((UnaryExpression)expression).getOperand(), nestedLevel, monitor);
187+
}
188+
else if (expression instanceof DynamicFeatureAccess)
189+
{
190+
complexityValue +=
191+
computeExpressionComplexity(((DynamicFeatureAccess)expression).getSource(), nestedLevel, monitor);
192+
}
193+
else if (expression instanceof Invocation)
194+
{
195+
Invocation invocation = (Invocation)expression;
196+
for (Expression parameter : invocation.getParams())
197+
{
198+
complexityValue += computeExpressionComplexity(parameter, nestedLevel, monitor);
199+
}
200+
}
201+
else if (expression instanceof IndexAccess)
202+
{
203+
IndexAccess indexAccess = (IndexAccess)expression;
204+
complexityValue += computeExpressionComplexity(indexAccess.getSource(), nestedLevel, monitor);
205+
complexityValue += computeExpressionComplexity(indexAccess.getIndex(), nestedLevel, monitor);
206+
}
207+
else if (expression instanceof FunctionStyleCreator)
208+
{
209+
FunctionStyleCreator creator = (FunctionStyleCreator)expression;
210+
complexityValue += computeExpressionComplexity(creator.getTypeNameExpression(), nestedLevel, monitor);
211+
Expression params = creator.getParamsExpression();
212+
if (params != null)
213+
{
214+
complexityValue += computeExpressionComplexity(params, nestedLevel, monitor);
215+
}
216+
}
217+
else if (expression instanceof OperatorStyleCreator)
218+
{
219+
for (Expression parameter : ((OperatorStyleCreator)expression).getParams())
220+
{
221+
complexityValue += computeExpressionComplexity(parameter, nestedLevel, monitor);
222+
}
223+
}
224+
return complexityValue;
225+
}
226+
}

0 commit comments

Comments
 (0)