From 1b056b185bba542acf4f65a914232f6564e064db Mon Sep 17 00:00:00 2001 From: Dmitriy Marmyshev Date: Mon, 10 Oct 2022 19:48:54 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D1=82=D0=B0=D0=BD=D0=B4=D0=B0=D1=80?= =?UTF-8?q?=D1=82=20492:=20=D0=98=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D1=87=D0=B8=D0=BA=20=D1=81=D0=BE=D0=B1=D1=8B=D1=82=D0=B8?= =?UTF-8?q?=D0=B9,=20=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E=D1=87=D0=B0?= =?UTF-8?q?=D0=B5=D0=BC=D1=8B=D0=B9=20=D0=B8=D0=B7=20=D0=BA=D0=BE=D0=B4?= =?UTF-8?q?=D0=B0=20=D0=B8=20=D0=BD=D0=B5=20=D1=81=D0=BE=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B6=D0=B0=D1=89=D0=B8=D0=B9=20=D0=BF=D1=80=D0=B5=D1=84=D0=B8?= =?UTF-8?q?=D0=BA=D1=81=D0=B0=20"=D0=9F=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B0=D0=B5=D0=BC=D1=8B=D0=B9=5F".=20#392?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + .../module-attachable-event-handler-name.md | 31 ++++ .../module-attachable-event-handler-name.md | 31 ++++ bundles/com.e1c.v8codestyle.bsl/plugin.xml | 4 + .../AttachableEventHandlerNameCheck.java | 151 ++++++++++++++++++ .../e1c/v8codestyle/bsl/check/Messages.java | 8 + .../v8codestyle/bsl/check/messages.properties | 8 + .../bsl/check/messages_ru.properties | 8 + .../module-attachable-event-handler-name.bsl | 17 ++ .../AttachableEventHandlerNameCheckTest.java | 54 +++++++ 10 files changed, 313 insertions(+) create mode 100644 bundles/com.e1c.v8codestyle.bsl/markdown/module-attachable-event-handler-name.md create mode 100644 bundles/com.e1c.v8codestyle.bsl/markdown/ru/module-attachable-event-handler-name.md create mode 100644 bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/AttachableEventHandlerNameCheck.java create mode 100644 tests/com.e1c.v8codestyle.bsl.itests/resources/module-attachable-event-handler-name.bsl create mode 100644 tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/AttachableEventHandlerNameCheckTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index a445e07a..215e1fa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Добавление типизированного значения в не типизированную коллекцию - Устаревшая процедура (функция) расположена вне области "УстаревшиеПроцедурыИФункции" +- Использован обработчик событий, подключаемый из кода и не содержащий префикса "Подключаемый_" #### Запросы diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/module-attachable-event-handler-name.md b/bundles/com.e1c.v8codestyle.bsl/markdown/module-attachable-event-handler-name.md new file mode 100644 index 00000000..3a318445 --- /dev/null +++ b/bundles/com.e1c.v8codestyle.bsl/markdown/module-attachable-event-handler-name.md @@ -0,0 +1,31 @@ +# Attachable event handler name + +Programmatically added event handler name should match pattern: **Attachable_** prefix + +## Noncompliant Code Example + +```bsl +// Parameters: +// Item - FormField +Procedure Incorrect(Item) + + Item.SetAction("OnChange", "IncorrectOnChange"); + +EndProcedure +``` + +## Compliant Solution + +```bsl +// Parameters: +// Item - FormField +Procedure Correct(Item) + + Item.SetAction("OnChange", "Attachable_CorrectOnChange"); + +EndProcedure +``` + +## See + +- [Form module event handlers attached in code](https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_Development_Standards/Code_conventions/Using_1C_Enterprise_language_structures/Form_module_event_handlers_attached_in_code/) diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/ru/module-attachable-event-handler-name.md b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/module-attachable-event-handler-name.md new file mode 100644 index 00000000..94d39a07 --- /dev/null +++ b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/module-attachable-event-handler-name.md @@ -0,0 +1,31 @@ +# Имя подключаемого обработчка события + +Имя программно добавленного обработчика события должно соответствать шаблону: префикс **Подключаемый_** + +## Неправильно + +```bsl +// Параметры: +// Элемент - FormField +Процедура Неправильно(Элемент) + + Элемент.SetAction("ПриИзменении", "НеправильноПриИзменении"); + +КонецПроцедуры +``` + +## Правильно + +```bsl +// Параметры: +// Элемент - FormField +Процедура Правильно(Элемент) + + Элемент.SetAction("ПриИзменении", "Подключаемый_ПравильноПриИзменении"); + +КонецПроцедуры +``` + +## См. + +- [Обработчики событий модуля формы, подключаемые из кода](https://its.1c.ru/db/v8std#content:492:hdoc) diff --git a/bundles/com.e1c.v8codestyle.bsl/plugin.xml b/bundles/com.e1c.v8codestyle.bsl/plugin.xml index dc8b6ed9..9a684ab6 100644 --- a/bundles/com.e1c.v8codestyle.bsl/plugin.xml +++ b/bundles/com.e1c.v8codestyle.bsl/plugin.xml @@ -299,6 +299,10 @@ category="com.e1c.v8codestyle.bsl" class="com.e1c.v8codestyle.bsl.check.BeginTransactionCheck"> + + diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/AttachableEventHandlerNameCheck.java b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/AttachableEventHandlerNameCheck.java new file mode 100644 index 00000000..4a42b7e5 --- /dev/null +++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/AttachableEventHandlerNameCheck.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright (C) 2022, 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.INVOCATION; + +import java.text.MessageFormat; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.xtext.EcoreUtil2; + +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.Invocation; +import com._1c.g5.v8.dt.bsl.model.ModuleType; +import com._1c.g5.v8.dt.bsl.model.StringLiteral; +import com._1c.g5.v8.dt.bsl.resource.TypesComputer; +import com._1c.g5.v8.dt.common.StringUtils; +import com._1c.g5.v8.dt.mcore.Environmental; +import com._1c.g5.v8.dt.mcore.TypeItem; +import com._1c.g5.v8.dt.mcore.util.McoreUtil; +import com._1c.g5.v8.dt.platform.IEObjectTypeNames; +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.check.StandardCheckExtension; +import com.e1c.v8codestyle.internal.bsl.BslPlugin; +import com.google.inject.Inject; + +/** + * The check finds invocation {@code object.SetAction("Event", "Attachable_HandlerName");} and validate that handler + * name matches pattern for attachable procedures. + * Form modules should be excluded because local methods must be found by direct reference. + * + * @author Dmitriy Marmyshev + */ +public class AttachableEventHandlerNameCheck + extends BasicCheck +{ + + private static final String CHECK_ID = "module-attachable-event-handler-name"; //$NON-NLS-1$ + + private static final String METHOD_NAME = "SetAction"; //$NON-NLS-1$ + + private static final String METHOD_NAME_RU = "УстановитьДействие"; //$NON-NLS-1$ + + private static final String DEFAULT_PARAM_ACTION_PATTERN = "^(?U)(Подключаемый|Attachable)_.*$"; //$NON-NLS-1$ + + private static final String PARAM_ACTION_PATTERN = "actionNamePattern"; //$NON-NLS-1$ + + //@formatter:off + private static final Set SET_ACTION_TYPES = Set.of( + IEObjectTypeNames.CLIENT_APPLICATION_FORM, + IEObjectTypeNames.MANAGED_FORM, + IEObjectTypeNames.FORM_FIELD, + IEObjectTypeNames.FORM_GROUP, + IEObjectTypeNames.FORM_TABLE, + IEObjectTypeNames.FORM_DECORATION); + //@formatter:on + + private final TypesComputer typesComputer; + + /** + * Instantiates a new attachable event handler name check. + * + * @param typesComputer the types computer, cannot be {@code null}. + */ + @Inject + public AttachableEventHandlerNameCheck(TypesComputer typesComputer) + { + this.typesComputer = typesComputer; + } + + @Override + public String getCheckId() + { + return CHECK_ID; + } + + @Override + protected void configureCheck(CheckConfigurer builder) + { + builder.title(Messages.AttachableEventHandlerNameCheck_Title) + .description(Messages.AttachableEventHandlerNameCheck_Description) + .complexity(CheckComplexity.NORMAL) + .severity(IssueSeverity.MINOR) + .issueType(IssueType.CODE_STYLE) + .extension(new StandardCheckExtension(492, getCheckId(), BslPlugin.PLUGIN_ID)) + .extension(ModuleTypeFilter.excludeTypes(ModuleType.FORM_MODULE)) + .module() + .checkedObjectType(INVOCATION) + .parameter(PARAM_ACTION_PATTERN, String.class, DEFAULT_PARAM_ACTION_PATTERN, + Messages.AttachableEventHandlerNameCheck_Event_handler_name_pattern); + } + + @Override + protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters, + IProgressMonitor monitor) + { + Invocation inv = (Invocation)object; + FeatureAccess method = inv.getMethodAccess(); + String methodName = method.getName(); + String actionPattern = parameters.getString(PARAM_ACTION_PATTERN); + if (!(method instanceof DynamicFeatureAccess) || StringUtils.isEmpty(actionPattern) + || inv.getParams().size() != 2 || !(inv.getParams().get(1) instanceof StringLiteral) + || !(METHOD_NAME_RU.equalsIgnoreCase(methodName) || METHOD_NAME.equalsIgnoreCase(methodName))) + { + return; + } + + Expression parameter = inv.getParams().get(1); + String content = getStringContent(parameter); + if (content != null && !content.matches(actionPattern) + && isExpectedTypes(((DynamicFeatureAccess)method).getSource())) + { + String message = MessageFormat.format(Messages.AttachableEventHandlerNameCheck_Message, methodName); + resultAceptor.addIssue(message, parameter); + } + } + + private boolean isExpectedTypes(Expression object) + { + Environmental env = EcoreUtil2.getContainerOfType(object, Environmental.class); + List types = typesComputer.computeTypes(object, env.environments()); + return types.stream().map(McoreUtil::getTypeName).filter(Objects::nonNull).anyMatch(SET_ACTION_TYPES::contains); + } + + private String getStringContent(Expression parameter) + { + // TODO #1187 get string from content computer in future, for now hard-coded StringLiteral + StringLiteral literal = (StringLiteral)parameter; + return String.join(StringUtils.EMPTY, literal.lines(true)); + } + +} 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 1bff436d..964929fc 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 @@ -38,6 +38,14 @@ final class Messages public static String AccessibilityAtClientInObjectModuleCheck_Methods_should_be_AtClient; public static String AccessibilityAtClientInObjectModuleCheck_title; + public static String AttachableEventHandlerNameCheck_Description; + + public static String AttachableEventHandlerNameCheck_Event_handler_name_pattern; + + public static String AttachableEventHandlerNameCheck_Message; + + public static String AttachableEventHandlerNameCheck_Title; + public static String CanonicalPragmaCheck_description; public static String CanonicalPragmaCheck_Pragma_0_is_not_written_canonically_correct_spelling_is_1; public static String CanonicalPragmaCheck_title; 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 b403f75a..629aeb11 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 @@ -28,6 +28,14 @@ AccessibilityAtClientInObjectModuleCheck_description = Method or variable access AccessibilityAtClientInObjectModuleCheck_title = Method or variable accessible AtClient +AttachableEventHandlerNameCheck_Description = Programmatically added event handler name should match pattern + +AttachableEventHandlerNameCheck_Event_handler_name_pattern = Event handler name pattern + +AttachableEventHandlerNameCheck_Message = Programmatically added event handler name "{0}" should match pattern + +AttachableEventHandlerNameCheck_Title = Attachable event handler name + CanonicalPragmaCheck_Pragma_0_is_not_written_canonically_correct_spelling_is_1 = Annotation {0} is not written canonically, correct spelling is {1} CanonicalPragmaCheck_description = Check pragma is written canonically 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 658ac085..c43b3324 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 @@ -28,6 +28,14 @@ AccessibilityAtClientInObjectModuleCheck_description = Метод или пер AccessibilityAtClientInObjectModuleCheck_title = Метод или переменная доступны НаКлиенте +AttachableEventHandlerNameCheck_Description = Имя программно добавленного обработчика события должно соответствать шаблону + +AttachableEventHandlerNameCheck_Event_handler_name_pattern = Шаблон имени обработчика события + +AttachableEventHandlerNameCheck_Message = Программно добавленное имя обработчика события "{0}" должно соответствать шаблону + +AttachableEventHandlerNameCheck_Title = Имя подключаемого обработчка события + CanonicalPragmaCheck_Pragma_0_is_not_written_canonically_correct_spelling_is_1 = Аннотация {0} написана не канонически, правильное написание {1} CanonicalPragmaCheck_description = Проверяет что аннотация метода написана канонически diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/module-attachable-event-handler-name.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/module-attachable-event-handler-name.bsl new file mode 100644 index 00000000..582d17f0 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/module-attachable-event-handler-name.bsl @@ -0,0 +1,17 @@ + +// Parameters: +// Item - FormField +Procedure Incorrect(Item) + + Item.SetAction("OnChange", "CorrectOnChange"); + +EndProcedure + + +// Parameters: +// Item - FormField +Procedure Correct(Item) + + Item.SetAction("OnChange", "Attachable_CorrectOnChange"); + +EndProcedure \ No newline at end of file diff --git a/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/AttachableEventHandlerNameCheckTest.java b/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/AttachableEventHandlerNameCheckTest.java new file mode 100644 index 00000000..22a74325 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/AttachableEventHandlerNameCheckTest.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (C) 2022, 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 java.util.List; + +import org.junit.Test; + +import com._1c.g5.v8.dt.validation.marker.IExtraInfoKeys; +import com._1c.g5.v8.dt.validation.marker.Marker; +import com.e1c.v8codestyle.bsl.check.AttachableEventHandlerNameCheck; + +/** + * Tests for {@link AttachableEventHandlerNameCheck} check. + * + * @author Dmitriy Marmyshev + */ +public class AttachableEventHandlerNameCheckTest + extends AbstractSingleModuleTestBase +{ + + public AttachableEventHandlerNameCheckTest() + { + super(AttachableEventHandlerNameCheck.class); + } + + /** + * Test attachable event handler name. + * + * @throws Exception the exception + */ + @Test + public void testAttachableEventHandlerName() throws Exception + { + updateModule(FOLDER_RESOURCE + "module-attachable-event-handler-name.bsl"); + + List markers = getModuleMarkers(); + assertEquals(1, markers.size()); + Marker marker = markers.get(0); + assertEquals("6", marker.getExtraInfo().get(IExtraInfoKeys.TEXT_EXTRA_INFO_LINE_KEY)); + } +}