diff --git a/bundles/com.e1c.v8codestyle.bsl/META-INF/MANIFEST.MF b/bundles/com.e1c.v8codestyle.bsl/META-INF/MANIFEST.MF
index ee3388a5..14c9914e 100644
--- a/bundles/com.e1c.v8codestyle.bsl/META-INF/MANIFEST.MF
+++ b/bundles/com.e1c.v8codestyle.bsl/META-INF/MANIFEST.MF
@@ -29,6 +29,7 @@ Import-Package: com._1c.g5.v8.bm.core;version="[9.0.0,10.0.0)",
com._1c.g5.v8.dt.bsl.model.util;version="[4.0.0,5.0.0)",
com._1c.g5.v8.dt.bsl.resource;version="[15.0.0,16.0.0)",
com._1c.g5.v8.dt.bsl.services;version="[7.0.0,8.0.0)",
+ com._1c.g5.v8.dt.bsl.stringliteral.contenttypes;version="[1.2.0,2.0.0)",
com._1c.g5.v8.dt.bsl.typesystem;version="[10.0.0,11.0.0)",
com._1c.g5.v8.dt.bsl.typesystem.util;version="[11.0.0,12.0.0)",
com._1c.g5.v8.dt.bsl.util;version="[8.0.0,9.0.0)",
diff --git a/bundles/com.e1c.v8codestyle.bsl/plugin.xml b/bundles/com.e1c.v8codestyle.bsl/plugin.xml
index 84f46c15..20d13a22 100644
--- a/bundles/com.e1c.v8codestyle.bsl/plugin.xml
+++ b/bundles/com.e1c.v8codestyle.bsl/plugin.xml
@@ -391,6 +391,10 @@
category="com.e1c.v8codestyle.bsl"
class="com.e1c.v8codestyle.bsl.check.OptionalFormParameterAccessCheck">
+
+
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 f5d3b1d2..73d961c5 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
@@ -453,7 +453,7 @@ final class Messages
public static String IsInRoleMethodRoleExistCheck_Role_named_not_exists_in_configuration;
public static String IsInRoleMethodRoleExistCheck_title;
-
+
public static String ModuleUndefinedVariableCheck_Title;
public static String ModuleUndefinedVariableCheck_Description;
public static String ModuleUndefinedVariable_msg;
@@ -484,6 +484,9 @@ final class Messages
public static String VariableNameInvalidCheck_variable_name_must_start_with_a_capital_letter;
public static String VariableNameInvalidCheck_variable_name_starts_with_an_underline;
+ public static String StringLiteralTypeAnnotationCheck_Title;
+ public static String StringLiteralTypeAnnotationCheck_Incorrect_annotation_location;
+
static
{
// initialize resource bundle
diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/StringLiteralTypeAnnotationCheck.java b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/StringLiteralTypeAnnotationCheck.java
new file mode 100644
index 00000000..451fe904
--- /dev/null
+++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/StringLiteralTypeAnnotationCheck.java
@@ -0,0 +1,242 @@
+/**
+ * Copyright (C) 2025, 1C
+ */
+package com.e1c.v8codestyle.bsl.check;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.nodemodel.ICompositeNode;
+import org.eclipse.xtext.nodemodel.ILeafNode;
+import org.eclipse.xtext.nodemodel.INode;
+import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
+import org.eclipse.xtext.util.Triple;
+
+import com._1c.g5.v8.dt.bsl.documentation.comment.BslCommentUtils;
+import com._1c.g5.v8.dt.bsl.model.Conditional;
+import com._1c.g5.v8.dt.bsl.model.IfStatement;
+import com._1c.g5.v8.dt.bsl.model.LoopStatement;
+import com._1c.g5.v8.dt.bsl.model.Module;
+import com._1c.g5.v8.dt.bsl.model.PreprocessorItem;
+import com._1c.g5.v8.dt.bsl.model.RegionPreprocessor;
+import com._1c.g5.v8.dt.bsl.model.StringLiteral;
+import com._1c.g5.v8.dt.bsl.model.TryExceptStatement;
+import com._1c.g5.v8.dt.bsl.stringliteral.contenttypes.BslBuiltInLanguagePreferences;
+import com._1c.g5.v8.dt.bsl.stringliteral.contenttypes.IStringLiteralTypeComputer;
+import com._1c.g5.v8.dt.bsl.stringliteral.contenttypes.LiteralType;
+import com._1c.g5.v8.dt.bsl.stringliteral.contenttypes.TypeUtil;
+import com._1c.g5.v8.dt.common.StringUtils;
+import com._1c.g5.v8.dt.core.platform.IV8Project;
+import com._1c.g5.v8.dt.core.platform.IV8ProjectManager;
+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.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.CommonSenseCheckExtension;
+import com.e1c.v8codestyle.internal.bsl.BslPlugin;
+import com.google.inject.Inject;
+
+/**
+ * Checks the correct placement of annotations for typing string literals.
+ *
+ * @author Babin Nikolay
+ *
+ */
+public class StringLiteralTypeAnnotationCheck
+ extends BasicCheck
+{
+ private static final String CHECK_ID = "string-literal-type-annotation-invalid-place"; //$NON-NLS-1$
+
+ @Inject
+ private IV8ProjectManager projectManager;
+
+ @Inject
+ private IStringLiteralTypeComputer typeComputer;
+
+ private final AtomicReference> annotations = new AtomicReference<>();
+
+ @Override
+ public String getCheckId()
+ {
+ return CHECK_ID;
+ }
+
+ @Override
+ protected void configureCheck(CheckConfigurer builder)
+ {
+ builder.title(Messages.StringLiteralTypeAnnotationCheck_Title)
+ .complexity(CheckComplexity.NORMAL)
+ .severity(IssueSeverity.MAJOR)
+ .issueType(IssueType.WARNING)
+ .extension(new CommonSenseCheckExtension(getCheckId(), BslPlugin.PLUGIN_ID))
+ .module();
+ }
+
+ @Override
+ protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
+ IProgressMonitor monitor)
+ {
+ if (!(object instanceof Module))
+ return;
+
+ Module module = (Module)object;
+
+ if (!isApplyTagsToEntireExpression(module))
+ return;
+
+ ICompositeNode moduleNode = NodeModelUtils.findActualNodeFor(module);
+ List moduleStringLiterals = new ArrayList<>();
+ List moduleAnnotations = new ArrayList<>();
+ if (moduleNode != null)
+ {
+ for (ILeafNode child : moduleNode.getLeafNodes())
+ {
+ if (monitor.isCanceled())
+ return;
+
+ EObject semantic = NodeModelUtils.findActualSemanticObjectFor(child);
+ if (semantic instanceof StringLiteral literal)
+ {
+ moduleStringLiterals.add(literal);
+ }
+ if (child.isHidden() && BslCommentUtils.isCommentNode(child) && isAllowAnnotation(child.getText()))
+ {
+ moduleAnnotations.add(child);
+ }
+ }
+ }
+
+ List invalidAnnotations = getInvalidAnnotations(monitor, moduleStringLiterals, moduleAnnotations);
+
+ addIssues(resultAceptor, module, invalidAnnotations, monitor);
+ }
+
+ private void addIssues(ResultAcceptor resultAceptor, Module module, List invalidAnnotations,
+ IProgressMonitor monitor)
+ {
+ for (INode annotation : invalidAnnotations)
+ {
+ if (monitor.isCanceled())
+ return;
+
+ int index = annotation.getText().indexOf("@"); //$NON-NLS-1$
+ int offset = annotation.getTotalOffset() + index;
+
+ int length = annotation.getText()
+ .trim()
+ .replaceFirst(BslCommentUtils.START_COMMENT_TAG_BSL, StringUtils.EMPTY)
+ .trim()
+ .toLowerCase()
+ .length();
+
+ DirectLocation directLocation = new DirectLocation(offset, length, annotation.getStartLine(), module);
+ BslDirectLocationIssue directLocationIssue =
+ new BslDirectLocationIssue(
+ Messages.StringLiteralTypeAnnotationCheck_Incorrect_annotation_location, directLocation,
+ StringUtils.EMPTY);
+
+ resultAceptor.addIssue(directLocationIssue);
+ }
+ }
+
+ private List getInvalidAnnotations(IProgressMonitor monitor, List moduleStringLiterals,
+ List moduleAnnotations)
+ {
+ List invalidAnnotations = new ArrayList<>();
+
+ Set correctAnnotations = new HashSet<>();
+ for (StringLiteral literal : moduleStringLiterals)
+ {
+ if (monitor.isCanceled())
+ return invalidAnnotations;
+
+ EObject literalParent = findLiteralParent(literal);
+
+ if (literalParent != null)
+ {
+ List rightLines = TypeUtil.getCommentLinesFromRight(literalParent)
+ .stream()
+ .filter(node -> isAllowAnnotation(node.getText()))
+ .toList();
+ correctAnnotations.addAll(rightLines);
+ }
+ }
+
+ for (INode node : moduleAnnotations)
+ {
+ if (monitor.isCanceled())
+ return invalidAnnotations;
+
+ if (!correctAnnotations.contains(node))
+ {
+ invalidAnnotations.add(node);
+ }
+ }
+ return invalidAnnotations;
+ }
+
+ private boolean isApplyTagsToEntireExpression(EObject object)
+ {
+ IV8Project project = projectManager.getProject(object);
+
+ return project != null && project.getProject() != null
+ && BslBuiltInLanguagePreferences.isApplyTagsToEntireExpression(project.getProject());
+ }
+
+ private EObject findLiteralParent(StringLiteral literal)
+ {
+ for (EObject e = literal; e != null; e = e.eContainer())
+ {
+ EObject container = e.eContainer();
+ //@formatter:off
+ if (container instanceof com._1c.g5.v8.dt.bsl.model.Method
+ || container instanceof RegionPreprocessor
+ || container instanceof PreprocessorItem
+ || container instanceof Conditional
+ || container instanceof IfStatement
+ || container instanceof TryExceptStatement
+ || container instanceof LoopStatement)
+ {
+ //@formatter:on
+ return e;
+ }
+ }
+ return null;
+ }
+
+ private boolean isAllowAnnotation(String text)
+ {
+ List> commentAnnotations = TypeUtil.parseHeaderAnnotations(text);
+ for (Triple commentAnnotation : commentAnnotations)
+ {
+ if (getAllowAnnotations().contains(commentAnnotation.getFirst().toLowerCase()))
+ return true;
+ }
+ return false;
+ }
+
+ private Set getAllowAnnotations()
+ {
+ Set allowAnnotations = annotations.get();
+ if (allowAnnotations == null)
+ {
+ allowAnnotations = typeComputer.allTypes()
+ .stream()
+ .filter(LiteralType::allowAnnotation)
+ .map(type -> type.getName().toLowerCase())
+ .collect(Collectors.toSet());
+ if (!annotations.compareAndSet(null, allowAnnotations))
+ allowAnnotations = annotations.get();
+ }
+ return allowAnnotations;
+ }
+}
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 2b2d397b..4f742843 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
@@ -513,3 +513,7 @@ VariableNameInvalidCheck_variable_name_is_invalid = Variable name {0} is invalid
VariableNameInvalidCheck_variable_name_must_start_with_a_capital_letter = variable name must start with a capital letter
VariableNameInvalidCheck_variable_name_starts_with_an_underline = variable name starts with an underline
+
+StringLiteralTypeAnnotationCheck_Title=The annotation is placed in the wrong location
+
+StringLiteralTypeAnnotationCheck_Incorrect_annotation_location=Incorrect location for placing the annotation
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 9eadbaf3..7710b449 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
@@ -513,3 +513,7 @@ VariableNameInvalidCheck_variable_name_is_invalid = Имя переменной
VariableNameInvalidCheck_variable_name_must_start_with_a_capital_letter = имя переменной должно начинаться с заглавной буквы
VariableNameInvalidCheck_variable_name_starts_with_an_underline = имя переменной начинается с символа подчеркивания
+
+StringLiteralTypeAnnotationCheck_Title = Неправильное размещение аннотации строковых литералов
+
+StringLiteralTypeAnnotationCheck_Incorrect_annotation_location=Неправильное размещение аннотации типов строковых литералов
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 6db7a920..30ce2ff1 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
@@ -36,6 +36,7 @@
import com._1c.g5.v8.dt.bsl.resource.ExportMethodProvider;
import com._1c.g5.v8.dt.bsl.resource.TypesComputer;
import com._1c.g5.v8.dt.bsl.services.BslGrammarAccess;
+import com._1c.g5.v8.dt.bsl.stringliteral.contenttypes.IStringLiteralTypeComputer;
import com._1c.g5.v8.dt.bsl.typesystem.ExportMethodTypeProvider;
import com._1c.g5.v8.dt.core.naming.ITopObjectFqnGenerator;
import com._1c.g5.v8.dt.core.platform.IBmModelManager;
@@ -82,6 +83,7 @@ protected void doConfigure()
URI uri = URI.createURI("*.bsl"); //$NON-NLS-1$
final IResourceServiceProvider rsp = IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(uri);
+ bind(IStringLiteralTypeComputer.class).toProvider(() -> rsp.get(IStringLiteralTypeComputer.class));
bind(IResourceDescription.Manager.class).toProvider(() -> rsp.get(IResourceDescription.Manager.class));
bind(BslEventsService.class).toProvider(() -> rsp.get(BslEventsService.class));
bind(TypesComputer.class).toProvider(() -> rsp.get(TypesComputer.class));
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/resources/string-literal-annotations-invalid-locations.bsl b/tests/com.e1c.v8codestyle.bsl.itests/resources/string-literal-annotations-invalid-locations.bsl
new file mode 100644
index 00000000..5f8521a7
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/resources/string-literal-annotations-invalid-locations.bsl
@@ -0,0 +1,36 @@
+
+// Новая процедура.
+//
+// Параметры:
+// ЯвляетсяЗаявкойНаОплату Является заявкой на оплату
+// ИмяСвойства Имя свойства
+// ЗначенияСвойства Значения свойства
+// ОбъектXDTO Объект XDTO
+Процедура НоваяПроцедура(ЯвляетсяЗаявкойНаОплату, ИмяСвойства, ЗначенияСвойства, ОбъектXDTO)
+
+ Значение = ""; // Дата1, Число какое то число
+ // yj dsq
+
+ Сообщить(Значение);
+
+ Если ЯвляетсяЗаявкойНаОплату И ИмяСвойства = "recipient" //@non-nls
+ Тогда // @fqn
+
+ ЗначенияСвойства.Добавить(ОбъектXDTO, "Получатель"); // @nOn-nls
+ ИначеЕсли ТипЗнч(ОбъектXDTO[ИмяСвойства]) = Тип("СписокXDTO")
+
+ Тогда // @noN-nls-1
+ Для //@form
+ Каждого ЭлементСпискаXDTO
+ //@non-nls
+ Из ОбъектXDTO[ИмяСвойства] Цикл
+
+ ЗначенияСвойства.Добавить("ыва"); //@non-Nls
+ ЗначенияСвойства.Добавить("Литерал"); //@non-nLs
+
+ КонецЦикла;
+ Иначе
+ ЗначенияСвойства.Добавить(ОбъектXDTO[ИмяСвойства]);
+ КонецЕсли;
+
+КонецПроцедуры
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/StringLiteralTypeAnnotationCheckTest.java b/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/StringLiteralTypeAnnotationCheckTest.java
new file mode 100644
index 00000000..ce3c6c84
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/StringLiteralTypeAnnotationCheckTest.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2025, 1C
+ */
+package com.e1c.v8codestyle.bsl.check.itests;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.junit.Test;
+
+import com._1c.g5.v8.dt.bsl.stringliteral.contenttypes.BslBuiltInLanguagePreferences;
+import com._1c.g5.v8.dt.core.platform.IDtProject;
+import com._1c.g5.v8.dt.validation.marker.Marker;
+import com._1c.g5.v8.dt.validation.marker.StandardExtraInfo;
+import com.e1c.v8codestyle.bsl.check.StringLiteralTypeAnnotationCheck;
+
+/**
+ * A class for testing {@link StringLiteralTypeAnnotationCheck}
+ *
+ * @author Babin Nikolay
+ *
+ */
+public class StringLiteralTypeAnnotationCheckTest
+ extends AbstractSingleModuleTestBase
+{
+
+ private static final String PROJECT_NAME = "CommonModule";
+
+ private static final String MODULE_FILE_NAME = "/src/CommonModules/CommonModule/Module.bsl";
+
+ public StringLiteralTypeAnnotationCheckTest()
+ {
+ super(StringLiteralTypeAnnotationCheck.class);
+ }
+
+ /**
+ * Checks invalid annotations locations.
+ *
+ * @throws Exception the exception
+ */
+ @Test
+ public void testInvalidAnnotationsLocationsMarkers() throws Exception
+ {
+ IDtProject project = getProject();
+
+ IEclipsePreferences preferences = BslBuiltInLanguagePreferences.getPreferences(project.getWorkspaceProject());
+ preferences.putBoolean(BslBuiltInLanguagePreferences.APPLY_TAGS_TO_ENTIRE_EXPRESSION, true);
+ preferences.flush();
+
+ updateModule(FOLDER_RESOURCE + "string-literal-annotations-invalid-locations.bsl");
+
+ List markers = getModuleMarkers();
+ assertEquals(2, markers.size());
+
+ assertEquals(Integer.valueOf(22), markers.get(0).getExtraInfo().get(StandardExtraInfo.TEXT_LINE));
+ assertEquals(Integer.valueOf(25), markers.get(1).getExtraInfo().get(StandardExtraInfo.TEXT_LINE));
+ }
+
+ @Override
+ protected String getTestConfigurationName()
+ {
+ return PROJECT_NAME;
+ }
+
+ @Override
+ protected String getModuleFileName()
+ {
+ return MODULE_FILE_NAME;
+ }
+}