From dad25b744f721d2bbf15491a17eabbf90a58fcdd Mon Sep 17 00:00:00 2001 From: Dmitriy Marmyshev Date: Fri, 22 Dec 2023 13:35:42 -0800 Subject: [PATCH] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BC=D0=BE=D0=B4=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B8=20=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=B9=20=D1=81?= =?UTF-8?q?=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80=D1=8B=20=D0=B2=D0=BD?= =?UTF-8?q?=D0=B5=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8-=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B0=20#1054=20(#1393)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 + .../markdown/ru/structure-key-modification.md | 68 +++++ .../markdown/structure-key-modification.md | 69 +++++ bundles/com.e1c.v8codestyle.bsl/plugin.xml | 4 + .../bsl/strict/check/Messages.java | 8 + .../check/StructureKeyModificationCheck.java | 281 ++++++++++++++++++ .../bsl/strict/check/messages.properties | 16 + .../bsl/strict/check/messages_ru.properties | 16 + .../bsl/ExternalDependenciesModule.java | 2 + .../strict/structure-key-modification.bsl | 65 ++++ .../itests/CommonModuleStrictTypesTest.java | 28 ++ 11 files changed, 559 insertions(+) create mode 100644 bundles/com.e1c.v8codestyle.bsl/markdown/ru/structure-key-modification.md create mode 100644 bundles/com.e1c.v8codestyle.bsl/markdown/structure-key-modification.md create mode 100644 bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/StructureKeyModificationCheck.java create mode 100644 tests/com.e1c.v8codestyle.bsl.itests/resources/strict/structure-key-modification.bsl diff --git a/CHANGELOG.md b/CHANGELOG.md index c57428e6..ee895b40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ #### Код модулей - Проверка на уникальность имени поля в doc-comment-field-name #1392 +- Проверка модификации ключей структуры вне функции-конструктора #1054 + #### Запросы diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/ru/structure-key-modification.md b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/structure-key-modification.md new file mode 100644 index 00000000..7b4f6ded --- /dev/null +++ b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/structure-key-modification.md @@ -0,0 +1,68 @@ +# Модификация ключа структуры вне функции-конструктора + +Если Структура создана функцией-конструктором, то изменение состава ключей структуры методами +`Структура.Вставить("Ключ", ...); Структура.Удалить("Ключ"); Структура.Очистить();` +может приводить к ошибкам из-за неопределенности состава данных. + +## Неправильно + +Неправильно удалять все ключи структуры, удалять ключ или заменять ключ внешней структуры. + +```bsl +// @strict-types + +Процедура Неправильно1() Экспорт + + ТестоваяСтруктура = Конструктор(); + ТестоваяСтруктура.Очистить(); + ТестоваяСтруктура.Вставить("Ключ1", 10); + ТестоваяСтруктура.Удалить("Ключ2"); + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * Ключ1 - Булево - +// * Ключ2 - Число - +Функция Конструктор() Экспорт + + ТестоваяСтруктура = новый Структура("Ключ1, Ключ2", Истина, 10); + ТестоваяСтруктура.Вставить("Ключ2", 20); + + Возврат ТестоваяСтруктура; + +КонецФункции +``` + +## Правильно + +Обращаться к существующему ключу необходимо напрямую и устанавливать новое значение. +Вместо удаления ключа необходимо устанавливать значение, которое представляет пустое или начальное значение. + +```bsl +// @strict-types + +Процедура Правильно1() Экспорт + + ТестоваяСтруктура = Конструктор(); + ТестоваяСтруктура.Ключ1 = false; + ТестоваяСтруктура.Ключ2 = -1; + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * Ключ1 - Булево - +// * Ключ2 - Число - +Функция Конструктор() Экспорт + + ТестоваяСтруктура = новый Структура("Ключ1, Ключ2", Истина, 10); + ТестоваяСтруктура.Вставить("Ключ2", 20); + + Возврат ТестоваяСтруктура; + +КонецФункции +``` + +## См. + diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/structure-key-modification.md b/bundles/com.e1c.v8codestyle.bsl/markdown/structure-key-modification.md new file mode 100644 index 00000000..94825c92 --- /dev/null +++ b/bundles/com.e1c.v8codestyle.bsl/markdown/structure-key-modification.md @@ -0,0 +1,69 @@ +# Structure key modification outside constructor function + +If Structure was created by constructor function then changing the composition of the structure keys using methods +`Structure.Insert("Key", ...); Structure.Delete("Key"); Structure.Clear();` +can lead to errors due to the uncertainty of data composition. + + +## Noncompliant Code Example + +Should not clear all structure keys, delete key or replace key of external structure. + +```bsl +// @strict-types + +Procedure Incorrect1() Export + + TestStucture = Constructor(); + TestStucture.Clear(); + TestStucture.Insert("Key1", 10); + TestStucture.Delete("Key2"); + +EndProcedure + +// Returns: +// Structure: +// * Key1 - Boolean - +// * Key2 - Number - +Function Constructor() Export + + TestStucture = new Structure("Key1, Key2", true, 10); + TestStucture.Insert("Key2", 20); + + Return TestStucture; + +EndFunction +``` + +## Compliant Solution + +Access to existing key directly and set new value. +Instead of delete key should set a value that represents blank or initial value. + +```bsl +// @strict-types + +Procedure Correct1() Export + + TestStucture = Constructor(); + TestStucture.Key1 = false; + TestStucture.Key2 = -1; + +EndProcedure + +// Returns: +// Structure: +// * Key1 - Boolean - +// * Key2 - Number - +Function Constructor() Export + + TestStucture = new Structure("Key1, Key2", true, 10); + TestStucture.Insert("Key2", 10); + + Return TestStucture; + +EndFunction +``` + +## See + diff --git a/bundles/com.e1c.v8codestyle.bsl/plugin.xml b/bundles/com.e1c.v8codestyle.bsl/plugin.xml index 906eddad..84f46c15 100644 --- a/bundles/com.e1c.v8codestyle.bsl/plugin.xml +++ b/bundles/com.e1c.v8codestyle.bsl/plugin.xml @@ -132,6 +132,10 @@ category="com.e1c.v8codestyle.bsl.strict" class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.strict.check.TypedValueAddingToUntypedCollectionCheck"> + + diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/Messages.java b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/Messages.java index a1649e0e..87e0f79c 100644 --- a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/Messages.java +++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/Messages.java @@ -58,6 +58,14 @@ final class Messages public static String StructureCtorValueTypeCheck_Structure_key__N__K__has_no_default_value_initializer; public static String StructureCtorValueTypeCheck_Structure_key__N__K__value_initialized_with_empty_types; public static String StructureCtorValueTypeCheck_title; + public static String StructureKeyModificationCheck_Check_Clear_method; + public static String StructureKeyModificationCheck_Check_Delete_method; + public static String StructureKeyModificationCheck_Check_Insert_method; + public static String StructureKeyModificationCheck_description; + public static String StructureKeyModificationCheck_error_message_Clear; + public static String StructureKeyModificationCheck_error_message_Delete; + public static String StructureKeyModificationCheck_error_message_Insert; + public static String StructureKeyModificationCheck_title; public static String TypedValueAddingToUntypedCollectionCheck_description; public static String TypedValueAddingToUntypedCollectionCheck_title; public static String VariableTypeCheck_description; diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/StructureKeyModificationCheck.java b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/StructureKeyModificationCheck.java new file mode 100644 index 00000000..83df7a8c --- /dev/null +++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/StructureKeyModificationCheck.java @@ -0,0 +1,281 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +package com.e1c.v8codestyle.bsl.strict.check; + +import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.DYNAMIC_FEATURE_ACCESS; +import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.FEATURE_ACCESS__NAME; + +import java.text.MessageFormat; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.naming.IQualifiedNameConverter; +import org.eclipse.xtext.nodemodel.ICompositeNode; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; +import org.eclipse.xtext.util.Pair; + +import com._1c.g5.v8.bm.core.IBmTransaction; +import com._1c.g5.v8.dt.bsl.common.IBslPreferences; +import com._1c.g5.v8.dt.bsl.common.IStaticExpressionValueComputer; +import com._1c.g5.v8.dt.bsl.common.IStringLiteralTextProvider; +import com._1c.g5.v8.dt.bsl.model.BslDerivedPropertySource; +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.Invocation; +import com._1c.g5.v8.dt.bsl.model.Method; +import com._1c.g5.v8.dt.bsl.model.util.BslUtil; +import com._1c.g5.v8.dt.common.StringUtils; +import com._1c.g5.v8.dt.core.platform.IBmModelManager; +import com._1c.g5.v8.dt.core.platform.IResourceLookup; +import com._1c.g5.v8.dt.mcore.DerivedProperty; +import com._1c.g5.v8.dt.mcore.Property; +import com._1c.g5.v8.dt.mcore.TypeItem; +import com._1c.g5.v8.dt.mcore.util.Environments; +import com._1c.g5.v8.dt.mcore.util.McoreUtil; +import com._1c.g5.v8.dt.platform.IEObjectTypeNames; +import com.e1c.g5.dt.core.api.naming.INamingService; +import com.e1c.g5.v8.dt.check.CheckComplexity; +import com.e1c.g5.v8.dt.check.ICheckParameters; +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.google.inject.Inject; + +/** + * The check of structure key modification using methods Clear(), Delete() and Insert() + * for structure created with external constructor function. + * + * @author Dmitriy Marmyshev + */ +public class StructureKeyModificationCheck + extends AbstractTypeCheck +{ + private static final String CHECK_ID = "structure-key-modification"; //$NON-NLS-1$ + + private static final String PARAM_CHECK_INSERT = "checkInsert"; //$NON-NLS-1$ + private static final String PARAM_CHECK_DELETE = "checkDelete"; //$NON-NLS-1$ + private static final String PARAM_CHECK_CLEAR = "checkClear"; //$NON-NLS-1$ + + private static final String INSERT_RU = "Вставить"; //$NON-NLS-1$ + private static final String INSERT = "Insert"; //$NON-NLS-1$ + + private static final String CLEAR_RU = "Очистить"; //$NON-NLS-1$ + private static final String CLEAR = "Clear"; //$NON-NLS-1$ + + private static final String DELETE_RU = "Удалить"; //$NON-NLS-1$ + private static final String DELETE = "Delete"; //$NON-NLS-1$ + + private static final String MODULE_URI_FRAGMENT = "/0"; //$NON-NLS-1$ + + private final IStaticExpressionValueComputer staticExpressionValueComputer; + + @Inject + public StructureKeyModificationCheck(IResourceLookup resourceLookup, IBslPreferences bslPreferences, + IQualifiedNameConverter qualifiedNameConverter, INamingService namingService, IBmModelManager bmModelManager, + IStaticExpressionValueComputer staticExpressionValueComputer) + { + super(resourceLookup, bslPreferences, qualifiedNameConverter, namingService, bmModelManager); + this.staticExpressionValueComputer = staticExpressionValueComputer; + } + + @Override + public String getCheckId() + { + return CHECK_ID; + } + + @Override + protected void configureCheck(CheckConfigurer builder) + { + builder.title(Messages.StructureKeyModificationCheck_title) + .description(Messages.StructureKeyModificationCheck_description) + .complexity(CheckComplexity.NORMAL) + .severity(IssueSeverity.MAJOR) + .issueType(IssueType.CODE_STYLE) + .extension(new ModuleTopObjectNameFilterExtension()) + .extension(new StrictTypeAnnotationCheckExtension()) + .module() + .checkedObjectType(DYNAMIC_FEATURE_ACCESS) + .parameter(PARAM_CHECK_INSERT, Boolean.class, Boolean.TRUE.toString(), + Messages.StructureKeyModificationCheck_Check_Insert_method) + .parameter(PARAM_CHECK_DELETE, Boolean.class, Boolean.TRUE.toString(), + Messages.StructureKeyModificationCheck_Check_Delete_method) + .parameter(PARAM_CHECK_CLEAR, Boolean.class, Boolean.TRUE.toString(), + Messages.StructureKeyModificationCheck_Check_Clear_method); + + } + + @Override + protected void check(Object object, ResultAcceptor resultAcceptor, ICheckParameters parameters, + IBmTransaction bmTransaction, IProgressMonitor monitor) + { + DynamicFeatureAccess fa = (DynamicFeatureAccess)object; + String methodName = fa.getName(); + if (StringUtils.isBlank(methodName)) + { + return; + } + + Invocation inv = BslUtil.getInvocation(fa); + if (inv == null) + { + return; + } + + Expression source = fa.getSource(); + + boolean isInsert = isInsert(methodName); + if (parameters.getBoolean(PARAM_CHECK_INSERT) && isInsert + || parameters.getBoolean(PARAM_CHECK_DELETE) && isDelete(methodName)) + { + if (inv.getParams().isEmpty()) + { + return; + } + + Environments actualEnvs = getActualEnvironments(fa); + if (actualEnvs.isEmpty()) + { + return; + } + List sourceTypes = computeTypes(source, actualEnvs).stream() + .filter(t -> IEObjectTypeNames.STRUCTURE.equals(McoreUtil.getTypeName(t))) + .collect(Collectors.toList()); + if (sourceTypes.isEmpty()) + { + return; + } + IStringLiteralTextProvider structureKey = + staticExpressionValueComputer.getStringContent(inv.getParams().get(0)); + if (structureKey != null && StringUtils.isNotBlank(structureKey.getText())) + { + String keyName = structureKey.getText(); + + if (isExternalStructureKey(sourceTypes, source, keyName, monitor)) + { + String message = isInsert ? Messages.StructureKeyModificationCheck_error_message_Insert + : Messages.StructureKeyModificationCheck_error_message_Delete; + message = MessageFormat.format(message, keyName); + resultAcceptor.addIssue(message, FEATURE_ACCESS__NAME); + } + } + + } + else if (parameters.getBoolean(PARAM_CHECK_CLEAR) && inv.getParams().isEmpty() && isClear(methodName)) + { + Environments actualEnvs = getActualEnvironments(fa); + if (actualEnvs.isEmpty()) + { + return; + } + List sourceTypes = computeTypes(source, actualEnvs).stream() + .filter(t -> IEObjectTypeNames.STRUCTURE.equals(McoreUtil.getTypeName(t))) + .collect(Collectors.toList()); + if (sourceTypes.isEmpty()) + { + return; + } + + Optional firstProperty = getFirstExternalKey(sourceTypes, fa); + if (!monitor.isCanceled() && firstProperty.isPresent()) + { + String message = Messages.StructureKeyModificationCheck_error_message_Clear; + resultAcceptor.addIssue(message, FEATURE_ACCESS__NAME); + } + } + } + + private Optional getFirstExternalKey(List sourceTypes, Expression context) + { + return dynamicFeatureAccessComputer.getAllProperties(sourceTypes, context.eResource()) + .stream() + .flatMap(e -> e.getFirst().stream()) + .filter(e -> e instanceof DerivedProperty + && ((DerivedProperty)e).getSource() instanceof BslDerivedPropertySource + && isExternalStructureKey((DerivedProperty)e, context)) + .map(DerivedProperty.class::cast) + .findAny(); + } + + private boolean isExternalStructureKey(Collection structureTypes, Expression currentMethodObject, + String keyName, IProgressMonitor monitor) + { + Collection, TypeItem>> allProperties = + dynamicFeatureAccessComputer.getAllProperties(structureTypes, currentMethodObject.eResource()); + for (Pair, TypeItem> pair : allProperties) + { + for (Property property : pair.getFirst()) + { + if (monitor.isCanceled()) + { + return false; + } + + if (property instanceof DerivedProperty && keyName.equalsIgnoreCase(property.getName()) + && ((DerivedProperty)property).getSource() instanceof BslDerivedPropertySource) + { + return isExternalStructureKey((DerivedProperty)property, currentMethodObject); + } + } + } + + return false; + } + + private boolean isExternalStructureKey(DerivedProperty property, Expression currentMethodObject) + { + BslDerivedPropertySource source = (BslDerivedPropertySource)property.getSource(); + + URI uri = EcoreUtil.getURI(currentMethodObject).trimFragment().appendFragment(MODULE_URI_FRAGMENT); + if (source.getModuleUri() != null && !source.getModuleUri().equals(uri.toString())) + { + return true; + } + + Method method = EcoreUtil2.getContainerOfType(currentMethodObject, Method.class); + + String currentMethodName = method == null ? StringUtils.EMPTY : method.getName(); + if (!currentMethodName.equalsIgnoreCase(source.getMethodName())) + { + return true; + } + else if (source.getLocalOffset() > 0 && method != null) + { + ICompositeNode node = NodeModelUtils.findActualNodeFor(method); + return source.getLocalOffset() < node.getOffset() - node.getTotalOffset(); + } + return false; + } + + private boolean isDelete(String methodName) + { + return DELETE_RU.equalsIgnoreCase(methodName) || DELETE.equalsIgnoreCase(methodName); + } + + private boolean isInsert(String methodName) + { + return INSERT_RU.equalsIgnoreCase(methodName) || INSERT.equalsIgnoreCase(methodName); + } + + private boolean isClear(String methodName) + { + return CLEAR_RU.equalsIgnoreCase(methodName) || CLEAR.equalsIgnoreCase(methodName); + } + +} diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/messages.properties b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/messages.properties index de92f3ca..02d0214e 100644 --- a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/messages.properties +++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/messages.properties @@ -84,6 +84,22 @@ StructureCtorValueTypeCheck_description = Checks Structure constructor string li StructureCtorValueTypeCheck_title = Structure constructor value types +StructureKeyModificationCheck_Check_Clear_method = Check Clear() method + +StructureKeyModificationCheck_Check_Delete_method = Check Delete() method + +StructureKeyModificationCheck_Check_Insert_method = Check Insert() method + +StructureKeyModificationCheck_description = Structure key modification outside constructor function + +StructureKeyModificationCheck_error_message_Clear = Should not clear external structure keys + +StructureKeyModificationCheck_error_message_Delete = Should not delete external structure key "{0}" + +StructureKeyModificationCheck_error_message_Insert = Should not replace external structure key "{0}" with new value type + +StructureKeyModificationCheck_title = Structure key modification outside constructor function + TypedValueAddingToUntypedCollectionCheck_description = Typed value is added to untyped collection TypedValueAddingToUntypedCollectionCheck_title = Typed value is added to untyped collection diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/messages_ru.properties b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/messages_ru.properties index c0ac4d89..734a6370 100644 --- a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/messages_ru.properties +++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/strict/check/messages_ru.properties @@ -84,6 +84,22 @@ StructureCtorValueTypeCheck_description = Проверяет строковый StructureCtorValueTypeCheck_title = Типизация значений в конструкторе структуры +StructureKeyModificationCheck_Check_Clear_method = Проверять метод Очистить() + +StructureKeyModificationCheck_Check_Delete_method = Проверять метод Удалить() + +StructureKeyModificationCheck_Check_Insert_method = Проверять метод Вставить() + +StructureKeyModificationCheck_description = Модификация ключа структуры вне функции-конструктора + +StructureKeyModificationCheck_error_message_Clear = Нельзя очищать ключи внешней структуры + +StructureKeyModificationCheck_error_message_Delete = Нельзя удалять ключ "{0}" внешней структуры + +StructureKeyModificationCheck_error_message_Insert = Нельзя заменять ключ "{0}" внешней структуры новым типом значения + +StructureKeyModificationCheck_title = Модификация ключа структуры вне функции-конструктора + TypedValueAddingToUntypedCollectionCheck_description = Добавление типизированного значения в нетипизированную коллекцию TypedValueAddingToUntypedCollectionCheck_title = Добавление типизированного значения в нетипизированную коллекцию diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/internal/bsl/ExternalDependenciesModule.java b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/internal/bsl/ExternalDependenciesModule.java index 44554fa6..6db7a920 100644 --- a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/internal/bsl/ExternalDependenciesModule.java +++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/internal/bsl/ExternalDependenciesModule.java @@ -27,6 +27,7 @@ import org.eclipse.xtext.scoping.IScopeProvider; import com._1c.g5.v8.dt.bm.xtext.BmAwareResourceSetProvider; import com._1c.g5.v8.dt.bsl.common.IBslPreferences; +import com._1c.g5.v8.dt.bsl.common.IStaticExpressionValueComputer; import com._1c.g5.v8.dt.bsl.contextdef.IBslModuleContextDefService; import com._1c.g5.v8.dt.bsl.documentation.comment.BslMultiLineCommentDocumentationProvider; import com._1c.g5.v8.dt.bsl.model.resource.owner.IBslOwnerComputerService; @@ -100,5 +101,6 @@ class ExternalDependenciesModule bind(IConfigurationProvider.class).toService(); bind(BslGrammarAccess.class).toProvider(() -> rsp.get(BslGrammarAccess.class)); bind(BmAwareResourceSetProvider.class).toProvider(() -> rsp.get(BmAwareResourceSetProvider.class)); + bind(IStaticExpressionValueComputer.class).toProvider(() -> rsp.get(IStaticExpressionValueComputer.class)); } } diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/strict/structure-key-modification.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/strict/structure-key-modification.bsl new file mode 100644 index 00000000..b2940b52 --- /dev/null +++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/strict/structure-key-modification.bsl @@ -0,0 +1,65 @@ +// @strict-types + + +Procedure Incorrect1() Export + + TestStucture = Correct2(); + TestStucture.Clear(); + TestStucture.Delete("Key2"); + TestStucture.Insert("Key1", Undefined); + TestStucture.Clear(); + TestStucture.Insert("Key1", 10); + TestStucture.Key1 = ""; + +EndProcedure + +Procedure Correct1() Export + + TestStucture = new Structure(); + TestStucture.Clear(); + TestStucture.Delete("Key2"); + TestStucture.Insert("Key1"); + TestStucture.Clear(); + TestStucture.Insert("Key1", 10); + TestStucture.Clear(); + TestStucture.Key1 = ""; + +EndProcedure + + +// Parameters: +// TestStucture - Structure: +// * Key1 - Boolean - +// * Key2 - Number - +Procedure Incorrect2(TestStucture) Export + + TestStucture.Insert("Key1", 10); + TestStucture.Insert("Key3", 10); + TestStucture.Clear(); + TestStucture.Delete("Key2"); + +EndProcedure + +// Parameters: +// TestStucture - See Correct2 +Procedure Incorrect3(TestStucture) Export + + TestStucture.Insert("Key1", 10); + TestStucture.Insert("Key3", 10); + TestStucture.Clear(); + TestStucture.Delete("Key2"); + +EndProcedure + +// Returns: +// Structure: +// * Key1 - Boolean - +// * Key2 - Number - +Function Correct2() Export + + TestStucture = new Structure("Key1, Key2", true, 10); + TestStucture.Insert("Key1", 10); + + Return TestStucture; + +EndFunction diff --git a/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/strict/check/itests/CommonModuleStrictTypesTest.java b/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/strict/check/itests/CommonModuleStrictTypesTest.java index abe265ae..a8ae4b39 100644 --- a/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/strict/check/itests/CommonModuleStrictTypesTest.java +++ b/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/strict/check/itests/CommonModuleStrictTypesTest.java @@ -55,6 +55,7 @@ import com.e1c.v8codestyle.bsl.strict.check.InvocationParamIntersectionCheck; import com.e1c.v8codestyle.bsl.strict.check.MethodParamTypeCheck; import com.e1c.v8codestyle.bsl.strict.check.SimpleStatementTypeCheck; import com.e1c.v8codestyle.bsl.strict.check.StructureCtorValueTypeCheck; +import com.e1c.v8codestyle.bsl.strict.check.StructureKeyModificationCheck; import com.e1c.v8codestyle.bsl.strict.check.TypedValueAddingToUntypedCollectionCheck; import com.e1c.v8codestyle.bsl.strict.check.VariableTypeCheck; @@ -643,6 +644,33 @@ public class CommonModuleStrictTypesTest assertEquals(Set.of("18", "19"), lines); } + /** + * Test of {@link StructureKeyModificationCheck} that check replace existing key of external structure key, + * delete key or clear structure with existing keys. + * + * @throws Exception the exception + */ + @Test + public void testStructureKeyModification() throws Exception + { + + String checkId = "structure-key-modification"; + String resouceName = "structure-key-modification"; + + Module module = updateAndGetModule(resouceName); + + List markers = getMarters(checkId, module); + + assertEquals(10, markers.size()); + + Set lines = new HashSet<>(); + for (Marker marker : markers) + { + lines.add(marker.getExtraInfo().get(IExtraInfoKeys.TEXT_EXTRA_INFO_LINE_KEY)); + } + assertEquals(Set.of("7", "8", "9", "10", "36", "38", "39", "47", "49", "50"), lines); + } + private IDtProject getProject() { return dtProject;