Skip to content
Open
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
39 changes: 39 additions & 0 deletions docs/diagnostics/InsertionWithoutChangeAndValidate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Использование #Вставка без &ИзменениеИКонтроль (InsertionWithoutChangeAndValidate)

<!-- Блоки выше заполняются автоматически, не трогать -->
## Описание диагностики

Директива `#Вставка` / `#КонецВставки` используется в теле метода (процедуры или функции), который не помечен аннотацией `&ИзменениеИКонтроль` (`&ChangeAndValidate`). Это приводит к ошибке компиляции модуля.

Директивы `#Вставка` и `#КонецВставки` предназначены для вставки кода расширения конфигурации. Платформа разрешает их использование только в методах с аннотацией `&ИзменениеИКонтроль`, которые явно декларируют намерение изменять код расширяемого объекта.

## Примеры

### Неправильно

```bsl
Процедура ДобавитьРеквизит()

#Вставка
... // код вставки
#КонецВставки

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

### Правильно

```bsl
&ИзменениеИКонтроль
Процедура ДобавитьРеквизит()

#Вставка
... // код вставки
#КонецВставки

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

## См. также

- [Стандарт 455: Структура модуля](https://its.1c.ru/db/v8std/content/455/hdoc)
39 changes: 39 additions & 0 deletions docs/en/diagnostics/InsertionWithoutChangeAndValidate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Using #Insert without &ChangeAndValidate (InsertionWithoutChangeAndValidate)

<!-- Блоки выше заполняются автоматически, не трогать -->
## Diagnostic description

The `#Insert` / `#EndInsert` directive is used inside a method (procedure or function) that is not annotated with `&ChangeAndValidate`. This causes a module compilation error.

The `#Insert` and `#EndInsert` directives are intended for configuration extension code insertion. The platform only allows them in methods annotated with `&ChangeAndValidate`, which explicitly declare the intent to modify the code of the extended object.

## Examples

### Incorrect

```bsl
Procedure AddAttribute()

#Insert
... // insertion code
#EndInsert

EndProcedure
```

### Correct

```bsl
&ChangeAndValidate
Procedure AddAttribute()

#Insert
... // insertion code
#EndInsert

EndProcedure
```

## See also

- [Standard 455: Module structure](https://its.1c.ru/db/v8std/content/455/hdoc)
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* This file is a part of BSL Language Server.
*
* Copyright (c) 2018-2026
* Alexey Sosnoviy <labotamy@gmail.com>, Nikita Fedkin <nixel2007@gmail.com> and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* BSL Language Server is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* BSL Language Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BSL Language Server.
*/
package com.github._1c_syntax.bsl.languageserver.diagnostics;

import com.github._1c_syntax.bsl.languageserver.context.symbol.annotations.Annotation;
import com.github._1c_syntax.bsl.languageserver.context.symbol.annotations.AnnotationKind;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
import com.github._1c_syntax.bsl.parser.BSLLexer;
import org.eclipse.lsp4j.Position;

/**
* Директива {@code #Вставка} / {@code #КонецВставки} используется внутри метода
* (процедуры или функции), который не помечен аннотацией {@code &ИзменениеИКонтроль}.
* Без этой аннотации платформа не сможет скомпилировать модуль — вставка кода расширения
* разрешена только в методах, явно объявленных как изменяющие.
*
* @see <a href="https://its.1c.ru/db/v8std/content/455/hdoc">Стандарт 455</a>
*/
@DiagnosticMetadata(
type = DiagnosticType.ERROR,
severity = DiagnosticSeverity.CRITICAL,
scope = DiagnosticScope.BSL,
minutesToFix = 1,
tags = {
DiagnosticTag.ERROR
}
)
public class InsertionWithoutChangeAndValidateDiagnostic extends AbstractDiagnostic {

@Override
public void check() {
var tokens = documentContext.getTokens();

documentContext.getSymbolTree().getMethods()
.stream()
.filter(method -> method.getAnnotations().stream()
.map(Annotation::getKind)
.noneMatch(kind -> kind == AnnotationKind.CHANGEANDVALIDATE))
.filter(method -> tokens.stream()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вот тут точно не прокатит. Это n*m поиск (токены в документе, количество методов).
Кажется, дешевле будет подписаться на узлы preproc insert/end и проверить что метод не имеет нужной директивы

.filter(token -> token.getType() == BSLLexer.PREPROC_INSERT
|| token.getType() == BSLLexer.PREPROC_ENDINSERT)
.anyMatch(token -> {
var tokenPosition = new Position(token.getLine() - 1, 0);
return Ranges.containsPosition(method.getRange(), tokenPosition);
}))
.forEach(method ->
diagnosticStorage.addDiagnostic(method.getSubNameRange(),
info.getMessage(method.getName())));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
diagnosticMessage=Method "%s" uses #Insert / #EndInsert directive without &ChangeAndValidate annotation
diagnosticName=Using #Insert without &ChangeAndValidate
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
diagnosticMessage=В методе "%s" используется директива #Вставка / #КонецВставки без аннотации &ИзменениеИКонтроль
diagnosticName=Использование #Вставка без &ИзменениеИКонтроль
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* This file is a part of BSL Language Server.
*
* Copyright (c) 2018-2026
* Alexey Sosnoviy <labotamy@gmail.com>, Nikita Fedkin <nixel2007@gmail.com> and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* BSL Language Server is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* BSL Language Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BSL Language Server.
*/
package com.github._1c_syntax.bsl.languageserver.diagnostics;

import org.eclipse.lsp4j.Diagnostic;
import org.junit.jupiter.api.Test;

import java.util.List;

import static com.github._1c_syntax.bsl.languageserver.util.Assertions.assertThat;

class InsertionWithoutChangeAndValidateDiagnosticTest
extends AbstractDiagnosticTest<InsertionWithoutChangeAndValidateDiagnostic> {

InsertionWithoutChangeAndValidateDiagnosticTest() {
super(InsertionWithoutChangeAndValidateDiagnostic.class);
}

@Test
void test() {
List<Diagnostic> diagnostics = getDiagnostics();

// Должна сработать только на БезИзменения (без аннотации &ИзменениеИКонтроль)
// СИзменением и ФункцияСИзменением — пропускаются (есть аннотация)
// ПустаяПроцедура — пропускается (нет #Вставка)
assertThat(diagnostics).hasSize(1);
assertThat(diagnostics, true)
.hasRange(9, 10, 9, 22); // БезИзменения
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
&ИзменениеИКонтроль
Процедура СИзменением()

#Вставка
// какой-то код
#КонецВставки

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

Процедура БезИзменения()

#Вставка
// какой-то код
#КонецВставки

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

&ИзменениеИКонтроль
Функция ФункцияСИзменением()

#Вставка
// код
#КонецВставки

КонецФункции

Процедура ПустаяПроцедура()
// нет вставки
КонецПроцедуры
Loading