Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bundles/com.e1c.v8codestyle.bsl/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
4 changes: 4 additions & 0 deletions bundles/com.e1c.v8codestyle.bsl/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,10 @@
category="com.e1c.v8codestyle.bsl"
class="com.e1c.v8codestyle.bsl.check.OptionalFormParameterAccessCheck">
</check>
<check
category="com.e1c.v8codestyle.bsl"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.check.StringLiteralTypeAnnotationCheck">
</check>
</extension>
<extension
point="org.eclipse.core.runtime.preferences">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Void>
{
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<Set<String>> 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<StringLiteral> moduleStringLiterals = new ArrayList<>();
List<INode> 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<INode> invalidAnnotations = getInvalidAnnotations(monitor, moduleStringLiterals, moduleAnnotations);

addIssues(resultAceptor, module, invalidAnnotations, monitor);
}

private void addIssues(ResultAcceptor resultAceptor, Module module, List<INode> 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<INode> getInvalidAnnotations(IProgressMonitor monitor, List<StringLiteral> moduleStringLiterals,
List<INode> moduleAnnotations)
{
List<INode> invalidAnnotations = new ArrayList<>();

Set<INode> correctAnnotations = new HashSet<>();
for (StringLiteral literal : moduleStringLiterals)
{
if (monitor.isCanceled())
return invalidAnnotations;

EObject literalParent = findLiteralParent(literal);

if (literalParent != null)
{
List<INode> 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<Triple<String, Integer, String>> commentAnnotations = TypeUtil.parseHeaderAnnotations(text);
for (Triple<String, Integer, String> commentAnnotation : commentAnnotations)
{
if (getAllowAnnotations().contains(commentAnnotation.getFirst().toLowerCase()))
return true;
}
return false;
}

private Set<String> getAllowAnnotations()
{
Set<String> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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=Неправильное размещение аннотации типов строковых литералов
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand Down
Original file line number Diff line number Diff line change
@@ -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[ИмяСвойства]);
КонецЕсли;

КонецПроцедуры
Loading
Loading