diff --git a/bundles/com.e1c.v8codestyle.bsl.ui/plugin.xml b/bundles/com.e1c.v8codestyle.bsl.ui/plugin.xml index 734358603..a8f6d735d 100644 --- a/bundles/com.e1c.v8codestyle.bsl.ui/plugin.xml +++ b/bundles/com.e1c.v8codestyle.bsl.ui/plugin.xml @@ -374,6 +374,8 @@ + + diff --git a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/Messages.java b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/Messages.java index 6108dca37..eec0f337f 100644 --- a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/Messages.java +++ b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/Messages.java @@ -44,6 +44,12 @@ final class Messages public static String OpenBslDocCommentViewFix_Details; + public static String MethodSemicolonExtraFix_Details; + public static String MethodSemicolonExtraFix_Description; + + public static String SemicolonMissngFix_Details; + public static String SemicolonMissingFix_Description; + public static String SelfReferenceFix_description; public static String SelfReferenceFix_details; diff --git a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/MethodSemicolonExtraFix.java b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/MethodSemicolonExtraFix.java new file mode 100644 index 000000000..f2fef6d7f --- /dev/null +++ b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/MethodSemicolonExtraFix.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (C) 2025, 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 + *******************************************************************************/ +package com.e1c.v8codestyle.bsl.ui.qfix; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.text.edits.DeleteEdit; +import org.eclipse.text.edits.TextEdit; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; +import org.eclipse.xtext.resource.XtextResource; + +import com._1c.g5.v8.dt.bsl.model.EmptyStatement; +import com.e1c.g5.v8.dt.bsl.check.qfix.IXtextBslModuleFixModel; +import com.e1c.g5.v8.dt.bsl.check.qfix.SingleVariantXtextBslModuleFix; +import com.e1c.g5.v8.dt.check.qfix.components.QuickFix; + +/** + * Removes extra semicolon + * + * @author Ivan Sergeev + */ +@QuickFix(checkId = "method-semicolon-extra", supplierId = "com.e1c.v8codestyle.bsl") +public class MethodSemicolonExtraFix + extends SingleVariantXtextBslModuleFix +{ + + @Override + protected void configureFix(FixConfigurer configurer) + { + configurer.interactive(true) + .description(Messages.MethodSemicolonExtraFix_Description) + .details(Messages.MethodSemicolonExtraFix_Description); + } + + @Override + protected TextEdit fixIssue(XtextResource state, IXtextBslModuleFixModel model) throws BadLocationException + { + EObject eobject = model.getElement(); + + if (!(eobject instanceof EmptyStatement)) + { + return null; + } + + INode node = NodeModelUtils.findActualNodeFor(eobject); + + if (node == null) + { + return null; + } + INode checkNode = node.getNextSibling(); + if (checkNode == null) + { + return null; + } + String checkText = checkNode.getText(); + INode checkNextNode = checkNode.getNextSibling(); + if (checkText.contains(";")) //$NON-NLS-1$ + { + return new DeleteEdit(checkNode.getTotalOffset(), checkNode.getTotalLength()); + } + else if (checkNextNode.getText().contains(";") && !(checkNextNode == null)) //$NON-NLS-1$ + { + return new DeleteEdit(checkNextNode.getTotalOffset(), checkNextNode.getTotalLength()); + } + return null; + } +} diff --git a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/SemicolonMissingFix.java b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/SemicolonMissingFix.java new file mode 100644 index 000000000..700f94513 --- /dev/null +++ b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/SemicolonMissingFix.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (C) 2025, 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 + *******************************************************************************/ +package com.e1c.v8codestyle.bsl.ui.qfix; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.text.edits.InsertEdit; +import org.eclipse.text.edits.TextEdit; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; +import org.eclipse.xtext.resource.XtextResource; + +import com._1c.g5.v8.dt.bsl.model.Conditional; +import com._1c.g5.v8.dt.bsl.model.Statement; +import com.e1c.g5.v8.dt.bsl.check.qfix.IXtextBslModuleFixModel; +import com.e1c.g5.v8.dt.bsl.check.qfix.SingleVariantXtextBslModuleFix; +import com.e1c.g5.v8.dt.check.qfix.components.QuickFix; + +/** + * Add missing semicolon + * + * @author Ivan Sergeev + */ +@QuickFix(checkId = "semicolon-missing", supplierId = "com.e1c.v8codestyle.bsl") +public class SemicolonMissingFix + extends SingleVariantXtextBslModuleFix +{ + + @Override + protected void configureFix(FixConfigurer configurer) + { + configurer.interactive(true) + .description(Messages.SemicolonMissingFix_Description) + .details(Messages.SemicolonMissngFix_Details); + } + + @Override + protected TextEdit fixIssue(XtextResource state, IXtextBslModuleFixModel model) throws BadLocationException + { + EObject eobject = model.getElement(); + if (!(eobject instanceof Statement) & !(eobject instanceof Conditional)) + { + return null; + } + + INode node = NodeModelUtils.findActualNodeFor(eobject); + if (node == null) + { + return null; + } + return new InsertEdit(node.getEndOffset(), ";"); //$NON-NLS-1$ + } +} diff --git a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages.properties b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages.properties index a4d9cab0f..c47dc9795 100644 --- a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages.properties +++ b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages.properties @@ -23,6 +23,10 @@ ManagerModuleNamedSelfReferenceFix_description=Remove excessive named self refer ManagerModuleNamedSelfReferenceFix_details=Remove excessive named self reference from manager module OpenBslDocCommentViewFix_Details=Open documentation comment data structure view and show current probleme object. OpenBslDocCommentViewFix_Description=Open documentation comment structure view +MethodSemicolonExtraFix_Details = Remove extra semicolon +MethodSemicolonExtraFix_Description = Remove extra semicolon +SemicolonMissingFix_Details = Add missing semicolon +SemicolonMissingFix_Description = Add missing semicolon SelfReferenceFix_description=Remove excessive self reference SelfReferenceFix_details=Remove excessive self reference SelfAssignFix_Description = Remove self-assign variable diff --git a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages_ru.properties b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages_ru.properties index 0fe5b29de..9db2c8579 100644 --- a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages_ru.properties +++ b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages_ru.properties @@ -41,6 +41,14 @@ ServerExecutionSafeModeFix_description = Включить безопасный ServerExecutionSafeModeFix_details = Добавить включение безопасного режима перед вызовом метода "Выполнить" или "Вычислить" +MethodSemicolonExtraFix_Details = Удалить лишнюю точку с запятой + +MethodSemicolonExtraFix_Description = Удалить лишнюю точку с запятой + +SemicolonMissingFix_Details = Добавить пропущенную точку с запятой + +SemicolonMissingFix_Description = Добавить пропущенную точку с запятой + UndefinedMethodFix_func_desc = Создать новую функцию в модуле UndefinedMethodFix_func_title = Создать функцию diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/method-semicolon-extra.md b/bundles/com.e1c.v8codestyle.bsl/markdown/method-semicolon-extra.md new file mode 100644 index 000000000..0b97fce30 --- /dev/null +++ b/bundles/com.e1c.v8codestyle.bsl/markdown/method-semicolon-extra.md @@ -0,0 +1,19 @@ +# Exta semicolon at the end of method declaration + +A semicolon at the end of a method declaration is not an error, but its absence is preferable. + +## Noncompliant Code Example + +Procedure procedureName(Parameters); + + A = 1; + +EndProcedure + +## Compliant Solution + +Procedure procedureName(Parameters) + + A = 1; + +EndProcedure \ No newline at end of file diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/ru/method-semicolon-extra.md b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/method-semicolon-extra.md new file mode 100644 index 000000000..1b0d7b93a --- /dev/null +++ b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/method-semicolon-extra.md @@ -0,0 +1,23 @@ +# Лишняя точка с запятой в конце объявления метода + +Точка с запятой в конце объявления метода не является ошибкой но предпочтительно отсутствие. + +## Неправильно + +Например, неправильно: + +Процедура Ааааa(); + + А = 1; + +КонецПроцедуры + +## Правильно + +Например, правельно: + +Процедура Ааааa() + + А = 1; + +КонецПроцедуры \ No newline at end of file diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/ru/semicolon-missing.md b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/semicolon-missing.md new file mode 100644 index 000000000..55a1872f0 --- /dev/null +++ b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/semicolon-missing.md @@ -0,0 +1,23 @@ +# Отсутствие точки с запятой в конце оператора + +Точка с запятой в конце последнего оператора блока не являеться обязательной, предпочтительно наличие. + +## Неправильно + +Например, неправильно: + +Процедура Ааааa() + + А = 1 + +КонецПроцедуры + +## Правильно + +Например, правельно: + +Процедура Ааааa() + + А = 1; + +КонецПроцедуры \ No newline at end of file diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/semicolon-missing.md b/bundles/com.e1c.v8codestyle.bsl/markdown/semicolon-missing.md new file mode 100644 index 000000000..7b56a96a1 --- /dev/null +++ b/bundles/com.e1c.v8codestyle.bsl/markdown/semicolon-missing.md @@ -0,0 +1,19 @@ +# Missing semicolon at the end of statement + +The semicolon at the end of the last statement is not required, but is preferred. + +## Noncompliant Code Example + +Procedure procedureName(Parameters) + + A = 1 + +EndProcedure + +## Compliant Solution + +Procedure procedureName(Parameters) + + A = 1; + +EndProcedure \ No newline at end of file diff --git a/bundles/com.e1c.v8codestyle.bsl/plugin.xml b/bundles/com.e1c.v8codestyle.bsl/plugin.xml index 72973bf41..4d1a3fdfe 100644 --- a/bundles/com.e1c.v8codestyle.bsl/plugin.xml +++ b/bundles/com.e1c.v8codestyle.bsl/plugin.xml @@ -393,7 +393,11 @@ + class="com.e1c.v8codestyle.bsl.check.MethodSemicolonExtraCheck"> + + allItems = BslUtil.allStatements(method); + if (allItems.isEmpty()) + { + return; + } + + if (allItems.get(0) instanceof EmptyStatement) + { + INode node = NodeModelUtils.findActualNodeFor(allItems.get(0)); + + if (node == null) + { + return; + } + INode checkNode = node.getNextSibling(); + + if (checkNode == null) + { + return; + } + String checkText = checkNode.getText(); + INode checkNodeNext = checkNode.getNextSibling(); + if (checkText.contains(";")) //$NON-NLS-1$ + { + + DirectLocation directLocation = new DirectLocation(checkNode.getOffset(), checkNode.getLength(), + checkNode.getStartLine(), allItems.get(0)); + + Issue issue = new BslDirectLocationIssue(Messages.MethodSemicolonExtraCheck_Issue, directLocation); + + resultAceptor.addIssue(issue); + } + else if (checkNodeNext.getText().contains(";") && checkNodeNext != null) //$NON-NLS-1$ + { + DirectLocation directLocation = new DirectLocation(checkNodeNext.getOffset(), checkNodeNext.getLength(), + checkNodeNext.getStartLine(), allItems.get(0)); + + Issue issue = new BslDirectLocationIssue(Messages.MethodSemicolonExtraCheck_Issue, directLocation); + + resultAceptor.addIssue(issue); + } + } + } +} diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/SemicolonMissingCheck.java b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/SemicolonMissingCheck.java new file mode 100644 index 000000000..5e41a592d --- /dev/null +++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/SemicolonMissingCheck.java @@ -0,0 +1,300 @@ +/******************************************************************************* + * Copyright (C) 2025, 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 + *******************************************************************************/ +package com.e1c.v8codestyle.bsl.check; + +import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.METHOD; + +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.nodemodel.BidiTreeIterator; +import org.eclipse.xtext.nodemodel.ILeafNode; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; + +import com._1c.g5.v8.dt.bsl.model.Conditional; +import com._1c.g5.v8.dt.bsl.model.EmptyStatement; +import com._1c.g5.v8.dt.bsl.model.ForStatement; +import com._1c.g5.v8.dt.bsl.model.IfPreprocessorStatement; +import com._1c.g5.v8.dt.bsl.model.IfStatement; +import com._1c.g5.v8.dt.bsl.model.Method; +import com._1c.g5.v8.dt.bsl.model.ReturnStatement; +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.util.BslUtil; +import com.e1c.g5.v8.dt.check.BslDirectLocationIssue; +import com.e1c.g5.v8.dt.check.CheckComplexity; +import com.e1c.g5.v8.dt.check.DirectLocation; +import com.e1c.g5.v8.dt.check.ICheckParameters; +import com.e1c.g5.v8.dt.check.Issue; +import com.e1c.g5.v8.dt.check.components.ModuleTopObjectNameFilterExtension; +import com.e1c.g5.v8.dt.check.settings.IssueSeverity; +import com.e1c.g5.v8.dt.check.settings.IssueType; +import com.e1c.v8codestyle.check.CommonSenseCheckExtension; +import com.e1c.v8codestyle.internal.bsl.BslPlugin; + +/** + * Checks in method missing semicolon + * + * @author Ivan Sergeev + */ +public class SemicolonMissingCheck + extends AbstractModuleStructureCheck +{ + private static final String CHECK_ID = "semicolon-missing"; //$NON-NLS-1$ + + @Override + public String getCheckId() + { + return CHECK_ID; + } + + @Override + protected void configureCheck(CheckConfigurer builder) + { + builder.title(Messages.SemicolonMissingCheck_Title) + .description(Messages.SemicolonMissingCheck_Description) + .complexity(CheckComplexity.NORMAL) + .severity(IssueSeverity.MINOR) + .issueType(IssueType.CODE_STYLE) + .extension(new ModuleTopObjectNameFilterExtension()) + .extension(new CommonSenseCheckExtension(getCheckId(), BslPlugin.PLUGIN_ID)) + .module() + .checkedObjectType(METHOD); + } + + @Override + protected void check(Object object, ResultAcceptor resultAcceptor, ICheckParameters parameters, + IProgressMonitor monitor) + { + INode node = null; + + Method method = (Method)object; + + List allItems = BslUtil.allStatements(method); + if (allItems.isEmpty()) + { + return; + } + for (Statement statement : allItems) + { + if (!(statement instanceof EmptyStatement)) + { + node = NodeModelUtils.findActualNodeFor(statement); + if (node == null) + { + continue; + } + INode checkNode = node.getNextSibling(); + if (checkNode == null) + { + resolveAddIssue(node, statement, resultAcceptor); + continue; + } + if (!checkNode.getText().contains(";")) //$NON-NLS-1$ + { + INode checkNextNode = checkNode.getNextSibling(); + if (checkNextNode == null) + { + resolveAddIssue(node, statement, resultAcceptor); + continue; + } + if (!checkNextNode.getText().contains(";")) //$NON-NLS-1$ + { + resolveAddIssue(node, statement, resultAcceptor); + } + } + if (!statement.eContents().isEmpty()) + { + checkSemicolon(statement.eContents(), resultAcceptor); + } + } + } + } + + private void checkSemicolon(List eObjects, ResultAcceptor resultAcceptor) + { + if (eObjects.isEmpty()) + { + return; + } + + for (EObject eObject : eObjects) + { + if (!(eObject instanceof Statement)) + { + if (eObject instanceof Conditional) + { + INode node = NodeModelUtils.findActualNodeFor(eObject); + if (node == null) + { + continue; + } + String nodeText = node.getText(); + BidiTreeIterator treeIterator = null; + treeIterator = node.getAsTreeIterable().reverse().iterator(); + INode lastNode = treeIterator.next(); + + if (lastNode == null) + { + continue; + } + String checkText = lastNode.getText(); + + if (!checkText.contains(";") && !nodeText.isEmpty()) //$NON-NLS-1$ + { + if (checkText.toLowerCase().contains("#EndRegion".toLowerCase()) //$NON-NLS-1$ + || checkText.toLowerCase().contains("#КонецОбласти".toLowerCase())) //$NON-NLS-1$ + { + checkSemicolon(eObject.eContents(), resultAcceptor); + } + else if (checkText.toLowerCase().contains("#EndIf".toLowerCase()) //$NON-NLS-1$ + || checkText.toLowerCase().contains("#КонецЕсли".toLowerCase())) //$NON-NLS-1$ + { + checkSemicolon(eObject.eContents(), resultAcceptor); + } + else if (eObject.eContents().isEmpty()) + { + resolveAddIssue(node, eObject, resultAcceptor); + } + } + } + checkSemicolon(eObject.eContents(), resultAcceptor); + } + else if (eObject instanceof EmptyStatement) + { + continue; + } + else if (eObject instanceof IfPreprocessorStatement) + { + checkSemicolon(eObject.eContents(), resultAcceptor); + } + else if (eObject.eContainingFeature().isMany() && eObject.eContainer() != null + && eObject.eContainer().eGet(eObject.eContainingFeature()) instanceof List statementCollection) + { + if (!statementCollection.isEmpty() + && statementCollection.get(statementCollection.size() - 1) == eObject) + { + INode node = NodeModelUtils.findActualNodeFor(eObject); + if (node == null) + { + continue; + } + String nodeText = node.getText(); + if (eObject instanceof SimpleStatement) + { + INode checkNode = node.getNextSibling(); + if (checkNode == null) + { + if (!nodeText.contains(";") && !nodeText.isEmpty()) //$NON-NLS-1$ + { + resolveAddIssue(node, eObject, resultAcceptor); + } + continue; + } + if (!checkNode.getText().contains(";")) //$NON-NLS-1$ + { + INode checkNextNode = checkNode.getNextSibling(); + if (checkNextNode == null) + { + resolveAddIssue(node, eObject, resultAcceptor); + continue; + } + if (!checkNextNode.getText().contains(";")) //$NON-NLS-1$ + { + resolveAddIssue(node, eObject, resultAcceptor); + } + } + } + else if (eObject instanceof IfStatement || eObject instanceof ForStatement) + { + INode checkNode = node.getNextSibling(); + if (checkNode == null) + { + resolveAddIssue(node, eObject, resultAcceptor); + continue; + } + if (!checkNode.getText().contains(";")) //$NON-NLS-1$ + { + INode checkNextNode = checkNode.getNextSibling(); + if (checkNextNode == null) + { + resolveAddIssue(node, eObject, resultAcceptor); + continue; + } + if (!checkNextNode.getText().contains(";")) //$NON-NLS-1$ + { + resolveAddIssue(node, eObject, resultAcceptor); + } + } + checkSemicolon(eObject.eContents(), resultAcceptor); + } + else if (eObject instanceof Statement) + { + INode checkNode = node.getNextSibling(); + if (checkNode == null) + { + if (eObject instanceof ReturnStatement) + { + resolveAddIssue(node, eObject, resultAcceptor); + } + continue; + } + if (!checkNode.getText().contains(";")) //$NON-NLS-1$ + { + INode checkNextNode = checkNode.getNextSibling(); + if (checkNextNode == null) + { + resolveAddIssue(node, eObject, resultAcceptor); + continue; + } + if (!checkNextNode.getText().contains(";")) //$NON-NLS-1$ + { + resolveAddIssue(node, eObject, resultAcceptor); + } + } + if (!eObject.eContents().isEmpty()) + { + checkSemicolon(eObject.eContents(), resultAcceptor); + } + } + } + } + } + } + + private static void resolveAddIssue(INode node, EObject eObject, ResultAcceptor resultAcceptor) + { + if (eObject instanceof SimpleStatement || eObject instanceof ReturnStatement) + { + resultAcceptor.addIssue(Messages.SemicolonMissingCheck_Issue, eObject); + return; + } + LinkedList allLeafNodes = new LinkedList<>(); + node.getLeafNodes().forEach(allLeafNodes::add); + ILeafNode lastNode = allLeafNodes.pollLast(); + + if (lastNode == null) + { + return; + } + DirectLocation directLocation = + new DirectLocation(lastNode.getOffset(), lastNode.getLength(), lastNode.getStartLine(), eObject); + + Issue issue = new BslDirectLocationIssue(Messages.SemicolonMissingCheck_Issue, directLocation); + + resultAcceptor.addIssue(issue); + } +} 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 d16924a55..69993f88d 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 @@ -414,6 +414,18 @@ OptionalFormParameterAccessCheck_Optional_form_parameter_access = Optional form OptionalFormParameterAccessCheck_title = Optional form parameter access +MethodSemicolonExtraCheck_Description = Extra Semicolon + +MethodSemicolonExtraCheck_Title = Extra Semicolon + +MethodSemicolonExtraCheck_Issue = Method declaration contains extra semicolon + +SemicolonMissingCheck_Description = Missing semicolon + +SemicolonMissingCheck_Title = Missing semicolon + +SemicolonMissingCheck_Issue = Semicolon is missing + QueryInLoop_Loop_has_method_with_query__0 = Loop has method with query "{0}" QueryInLoop_Loop_has_query = Loop has query 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 e6be51abf..97de800dd 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 @@ -458,11 +458,17 @@ RollbackTransactionCheck_Transactions_is_broken = Нарушена схема р RollbackTransactionCheck_Transactions_is_broken_des = Вызов "ОтменитьТранзакцию()" находится вне конструкции "Попытка... Исключение". Отсутствует вызов "НачатьТранзакцию()", хотя вызываются "ОтменитьТранзакцию()". Для вызова "НачатьТранзакцию()" отсутствует парный вызов "ЗафиксироватьТранзакцию()". Между "Исключение" и "ОтменитьТранзакцию()" есть исполняемый код, который может вызвать исключение. -SelfAssignCheck_Title = Присвоение переменной самой себе +MethodSemicolonExtraCheck_Description = Лишняя точка с запятой -SelfAssignCheck_Description = Проверяет, что переменная присвоена сама себе +MethodSemicolonExtraCheck_Title = Лишняя точка с запятой -SelfAssignCheck_Self_assign_issue = Эта переменная присвоена сама себе +MethodSemicolonExtraCheck_Issue = Объявление метода содержит лишнюю точку с запятой + +SemicolonMissingCheck_Description = Пропущена точка с запятой + +SemicolonMissingCheck_Title = Пропущена точка с запятой + +SemicolonMissingCheck_Issue = Пропущена точка с запятой SelfReferenceCheck_Description = Избыточное обращение внутри модуля через псевдоним "ЭтотОбъект" (к методу, свойству или реквизиту) diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/extra-semicolon-method-after.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/extra-semicolon-method-after.bsl new file mode 100644 index 000000000..541492620 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/extra-semicolon-method-after.bsl @@ -0,0 +1,13 @@ + +#Region Aaaa + +Procedure Test(); + +EndProcedure + +Procedure NonContain() + +EndProcedure + +#EndRegion + diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/extra-semicolon-method-before.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/extra-semicolon-method-before.bsl new file mode 100644 index 000000000..4687313c8 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/extra-semicolon-method-before.bsl @@ -0,0 +1,13 @@ + +#Region Aaaa + +Procedure NonContain() + +EndProcedure + +Procedure Test(); + +EndProcedure + +#EndRegion + diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/method-declaration-contain-semicolon.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/method-declaration-contain-semicolon.bsl new file mode 100644 index 000000000..4ccd43c36 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/method-declaration-contain-semicolon.bsl @@ -0,0 +1,8 @@ + +#Region Aaaa + +Procedure Test (); + +EndProcedure + +#EndRegion diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-return-statement.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-return-statement.bsl new file mode 100644 index 000000000..80b7b384f --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-return-statement.bsl @@ -0,0 +1,11 @@ +#Region Abcd + +Function Aaaa() + + test = 1; + + return test + +EndFunction + +#EndRegion diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statemen-sub-statement-after.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statemen-sub-statement-after.bsl new file mode 100644 index 000000000..a188ee009 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statemen-sub-statement-after.bsl @@ -0,0 +1,15 @@ +#Region Abcd + +Procedure Aaaa() + + If True Then + + Test= Test + 1 + + EndIf; + + NoTest = 2; + +EndProcedure + +#EndRegion diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-before.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-before.bsl new file mode 100644 index 000000000..0c13e5579 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-before.bsl @@ -0,0 +1,12 @@ + +#Region Abcd + +Procedure Aaaa() + + A = 1; + Test = 1 + +EndProcedure + +#EndRegion + diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-else-ifelse-statement.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-else-ifelse-statement.bsl new file mode 100644 index 000000000..e3615107e --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-else-ifelse-statement.bsl @@ -0,0 +1,17 @@ +#Region Abcd + +Function Aaaa() + + If True Then + + NoTest = 1; + + Else + + Test = 2 + + EndIf; + +EndFunction + +#EndRegion \ No newline at end of file diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-if-ifelse-statement.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-if-ifelse-statement.bsl new file mode 100644 index 000000000..a5801d985 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-if-ifelse-statement.bsl @@ -0,0 +1,17 @@ +#Region Abcd + +Function Aaaa() + + If True Then + + Test = 1 + + Else + + NoTest = 2; + + EndIf; + +EndFunction + +#EndRegion \ No newline at end of file diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-if-preprocessor.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-if-preprocessor.bsl new file mode 100644 index 000000000..3c679295c --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-if-preprocessor.bsl @@ -0,0 +1,13 @@ +#Region Abcd + +Procedure Aaaa() + +#If Server Then + + Test = Test + 1 + +#EndIf + +EndProcedure + +#EndRegion diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-sub-statement-before.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-sub-statement-before.bsl new file mode 100644 index 000000000..1c53f89fe --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-sub-statement-before.bsl @@ -0,0 +1,15 @@ +#Region Abcd + +Procedure Aaaa() + + NoTest = 2; + + If True Then + + Test= Test + 1 + + EndIf; + +EndProcedure + +#EndRegion diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-sub-statement.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-sub-statement.bsl new file mode 100644 index 000000000..0b5c9fc97 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement-sub-statement.bsl @@ -0,0 +1,14 @@ + +#Region Abcd + +Procedure Aaaa() + +If True Then + +Test = 1 + +EndIf; + +EndProcedure + +#EndRegion diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement.bsl new file mode 100644 index 000000000..e022efd46 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/missing-semicolon-statement.bsl @@ -0,0 +1,10 @@ + +#Region Abcd + +Procedure Aaaa() + + Test = 2 + +EndProcedure + +#EndRegion diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/non-contain-extra-semicolon-method.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/non-contain-extra-semicolon-method.bsl new file mode 100644 index 000000000..445693946 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/non-contain-extra-semicolon-method.bsl @@ -0,0 +1,8 @@ + +#Region NotEmpty + +Procedure Test() + +EndProcedure + +#EndRegion diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/non-missing-semicolon-statement-next-string.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/non-missing-semicolon-statement-next-string.bsl new file mode 100644 index 000000000..1456a5deb --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/non-missing-semicolon-statement-next-string.bsl @@ -0,0 +1,10 @@ +#Region Abcd + +Function Aaaa() + + test = 1 + ; + +EndFunction + +#EndRegion diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/non-missing-semicolon-statement-space.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/non-missing-semicolon-statement-space.bsl new file mode 100644 index 000000000..f5d399e53 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/non-missing-semicolon-statement-space.bsl @@ -0,0 +1,9 @@ +#Region Abcd + +Function Aaaa() + + test = 1 ; + +EndFunction + +#EndRegion diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/non-missing-semicolon-statement.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/non-missing-semicolon-statement.bsl new file mode 100644 index 000000000..b63b13565 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/non-missing-semicolon-statement.bsl @@ -0,0 +1,10 @@ + +#Region Abcd + +Procedure Aaaa() + + Test = 1; + +EndProcedure + +#EndRegion diff --git a/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/MethodSemicolonExtraCheckTest.java b/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/MethodSemicolonExtraCheckTest.java new file mode 100644 index 000000000..5153ff878 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/MethodSemicolonExtraCheckTest.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (C) 2025, 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 + *******************************************************************************/ +package com.e1c.v8codestyle.bsl.check.itests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.Test; + +import com._1c.g5.v8.dt.validation.marker.Marker; +import com._1c.g5.v8.dt.validation.marker.StandardExtraInfo; +import com.e1c.v8codestyle.bsl.check.MethodSemicolonExtraCheck; + +/** + * Tests for {@link MerhodSemicolonExtraCheck} check. + * + * @author Ivan Sergeev + */ +public class MethodSemicolonExtraCheckTest + extends AbstractSingleModuleTestBase +{ + + public MethodSemicolonExtraCheckTest() + { + super(MethodSemicolonExtraCheck.class); + } + + /** + * Test method declaration contain extra semicolon. + * + * @throws Exception the exception + */ + @Test + public void testMethodDeclarationExtraSemicolon() throws Exception + { + updateModule(FOLDER_RESOURCE + "method-declaration-contain-semicolon.bsl"); + + List markers = getModuleMarkers(); + assertEquals(1, markers.size()); + Marker marker = markers.get(0); + assertEquals(Integer.valueOf(4), marker.getExtraInfo().get(StandardExtraInfo.TEXT_LINE)); + } + + /** + * Test method after another method. + * + * @throws Exception the exception + */ + @Test + public void testMethodAfter() throws Exception + { + updateModule(FOLDER_RESOURCE + "extra-semicolon-method-after.bsl"); + + List markers = getModuleMarkers(); + assertEquals(1, markers.size()); + Marker marker = markers.get(0); + assertEquals(Integer.valueOf(4), marker.getExtraInfo().get(StandardExtraInfo.TEXT_LINE)); + } + + /** + * Test method before another method. + * + * @throws Exception the exception + */ + @Test + public void testMethodBefore() throws Exception + { + updateModule(FOLDER_RESOURCE + "extra-semicolon-method-before.bsl"); + + List markers = getModuleMarkers(); + assertEquals(1, markers.size()); + Marker marker = markers.get(0); + assertEquals(Integer.valueOf(8), marker.getExtraInfo().get(StandardExtraInfo.TEXT_LINE)); + } + + /** + * Test method declaration not contain extra semicolon. + * + * @throws Exception the exception + */ + @Test + public void testMethodDeclarationNoExtraSemicolon() throws Exception + { + updateModule(FOLDER_RESOURCE + "non-contain-extra-semicolon-method.bsl"); + + List markers = getModuleMarkers(); + assertTrue(markers.isEmpty()); + + } +} \ No newline at end of file diff --git a/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/SemicolonMissingCheckTest.java b/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/SemicolonMissingCheckTest.java new file mode 100644 index 000000000..7a6223d3b --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/SemicolonMissingCheckTest.java @@ -0,0 +1,226 @@ +/******************************************************************************* + * Copyright (C) 2025, 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 + *******************************************************************************/ +package com.e1c.v8codestyle.bsl.check.itests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.Test; + +import com._1c.g5.v8.dt.validation.marker.Marker; +import com._1c.g5.v8.dt.validation.marker.StandardExtraInfo; +import com.e1c.v8codestyle.bsl.check.SemicolonMissingCheck; + +/** + * Tests for {@link SemicolonMissingCheck} check. + * + * @author Ivan Sergeev + */ +public class SemicolonMissingCheckTest + extends AbstractSingleModuleTestBase +{ + + public SemicolonMissingCheckTest() + { + super(SemicolonMissingCheck.class); + } + + /** + * Test statement missing semicolon. + * + * @throws Exception the exception + */ + @Test + public void testStatementMissingSemicolon() throws Exception + { + updateModule(FOLDER_RESOURCE + "missing-semicolon-statement.bsl"); + + List markers = getModuleMarkers(); + assertEquals(1, markers.size()); + Marker marker = markers.get(0); + assertEquals(Integer.valueOf(6), marker.getExtraInfo().get(StandardExtraInfo.TEXT_LINE)); + } + + /** + * Test statement missing semicolon. + * + * @throws Exception the exception + */ + @Test + public void testReturnStatementMissingSemicolon() throws Exception + { + updateModule(FOLDER_RESOURCE + "missing-semicolon-return-statement.bsl"); + + List markers = getModuleMarkers(); + assertEquals(1, markers.size()); + Marker marker = markers.get(0); + assertEquals(Integer.valueOf(7), marker.getExtraInfo().get(StandardExtraInfo.TEXT_LINE)); + } + + /** + * Test statement in sub statement after another statement. + * + * @throws Exception the exception + */ + @Test + public void testStatementSubStatementAfter() throws Exception + { + updateModule(FOLDER_RESOURCE + "missing-semicolon-statemen-sub-statement-after.bsl"); + + List markers = getModuleMarkers(); + assertEquals(1, markers.size()); + Marker marker = markers.get(0); + assertEquals(Integer.valueOf(7), marker.getExtraInfo().get(StandardExtraInfo.TEXT_LINE)); + } + + /** + * Test statement in sub statement before another statement. + * + * @throws Exception the exception + */ + @Test + public void testStatementSubStatementBefore() throws Exception + { + updateModule(FOLDER_RESOURCE + "missing-semicolon-statement-sub-statement-before.bsl"); + + List markers = getModuleMarkers(); + assertEquals(1, markers.size()); + Marker marker = markers.get(0); + assertEquals(Integer.valueOf(9), marker.getExtraInfo().get(StandardExtraInfo.TEXT_LINE)); + } + + + /** + * Test statement before another statement. + * + * @throws Exception the exception + */ + @Test + public void testStatementBefore() throws Exception + { + updateModule(FOLDER_RESOURCE + "missing-semicolon-statement-before.bsl"); + + List markers = getModuleMarkers(); + assertEquals(1, markers.size()); + Marker marker = markers.get(0); + assertEquals(Integer.valueOf(7), marker.getExtraInfo().get(StandardExtraInfo.TEXT_LINE)); + } + + /** + * Test statement in if preprocessor. + * + * @throws Exception the exception + */ + @Test + public void testStatementInIfPrepocessor() throws Exception + { + updateModule(FOLDER_RESOURCE + "missing-semicolon-statement-if-preprocessor.bsl"); + + List markers = getModuleMarkers(); + assertEquals(1, markers.size()); + Marker marker = markers.get(0); + assertEquals(Integer.valueOf(7), marker.getExtraInfo().get(StandardExtraInfo.TEXT_LINE)); + } + + /** + * Test statement sub statement. + * + * @throws Exception the exception + */ + @Test + public void testStatementSubStatement() throws Exception + { + updateModule(FOLDER_RESOURCE + "missing-semicolon-statement-sub-statement.bsl"); + + List markers = getModuleMarkers(); + assertEquals(1, markers.size()); + Marker marker = markers.get(0); + assertEquals(Integer.valueOf(8), marker.getExtraInfo().get(StandardExtraInfo.TEXT_LINE)); + } + + /** + * Test statement sub statement. + * + * @throws Exception the exception + */ + @Test + public void testStatementInIfStatement() throws Exception + { + updateModule(FOLDER_RESOURCE + "missing-semicolon-statement-if-ifelse-statement.bsl"); + + List markers = getModuleMarkers(); + assertEquals(1, markers.size()); + Marker marker = markers.get(0); + assertEquals(Integer.valueOf(7), marker.getExtraInfo().get(StandardExtraInfo.TEXT_LINE)); + } + + /** + * Test statement sub statement. + * + * @throws Exception the exception + */ + @Test + public void testStatementInElse() throws Exception + { + updateModule(FOLDER_RESOURCE + "missing-semicolon-statement-else-ifelse-statement.bsl"); + + List markers = getModuleMarkers(); + assertEquals(1, markers.size()); + Marker marker = markers.get(0); + assertEquals(Integer.valueOf(11), marker.getExtraInfo().get(StandardExtraInfo.TEXT_LINE)); + } + + /** + * Test statement no missing semicolon. + * + * @throws Exception the exception + */ + @Test + public void testStatementNoMissingSemicolon() throws Exception + { + updateModule(FOLDER_RESOURCE + "non-missing-semicolon-statement.bsl"); + + List markers = getModuleMarkers(); + assertTrue(markers.isEmpty()); + } + + /** + * Test statement no missing semicolon. + * + * @throws Exception the exception + */ + @Test + public void testStatemetSemicolonSpace() throws Exception + { + updateModule(FOLDER_RESOURCE + "non-missing-semicolon-statement-space.bsl"); + + List markers = getModuleMarkers(); + assertTrue(markers.isEmpty()); + } + + /** + * Test statement no missing semicolon. + * + * @throws Exception the exception + */ + @Test + public void testStatementSemicolonNextString() throws Exception + { + updateModule(FOLDER_RESOURCE + "non-missing-semicolon-statement-next-string.bsl"); + + List markers = getModuleMarkers(); + assertTrue(markers.isEmpty()); + } +}