Skip to content

Типы форм конфигурации: реквизиты, элементы, параметры и обработчики событий - #4337

Merged
nixel2007 merged 23 commits into
feat/catalog-owner-typingfrom
feat/form-types-support
Aug 1, 2026
Merged

Типы форм конфигурации: реквизиты, элементы, параметры и обработчики событий#4337
nixel2007 merged 23 commits into
feat/catalog-owner-typingfrom
feat/form-types-support

Conversation

@sfaqer

@sfaqer sfaqer commented Jul 31, 2026

Copy link
Copy Markdown
Member

Что даёт

Каждая форма конфигурации получает собственный тип — тот, что в модуле формы стоит
за ЭтотОбъект/ЭтаФорма и за неквалифицированными именами реквизитов и элементов.
Из этого следует:

  • реквизиты формы типизируются по Form.xml, включая колонки реквизитов-таблиц
    значений и зеркала табличных частей основного реквизита (Объект.Товары);
  • элементы формы (Элементы.ПолеНаименование) получают платформенный тип по своему
    виду вместе с расширением (ПолеФормы + Расширение поля формы для поля ввода);
  • сама форма расширяется по основному реквизиту — Расширение формы клиентского приложения для документа и т.п.;
  • параметры формы (Параметры.Ключ) разворачиваются из синтакс-помощника — общие
    для любой формы и специфичные для вида основных данных;
  • команды формы (Команды.ЗаполнитьПоОснованию) лежат в своей коллекции, а процедура
    из <Action> считается обработчиком;
  • обработчики событий из Form.xml связываются с процедурами модуля формы, поэтому
    их параметры получают типы из контракта события платформы. Обработчики элементов
    (…ПриИзменении, …Нажатие) — тоже: контракт им ищется на типе элемента;
  • ОткрытьФорму("Справочник.Х.Форма.ФормаЭлемента") резолвится в тип конкретной
    формы — и по точному имени, и по имени основной формы объекта, на обоих языках.

Отдельно про основание: тип у этого параметра платформа не объявляет вовсе, поэтому
он берётся из ВводитсяНаОсновании владельца формы, а если объект ни на чём не вводится —
Неопределено.

Обычные формы поддержаны тоже: у них нет собственной модели содержимого, поэтому тип
берётся по роли формы у владельца, а объектный контекст инжектится в модуль.

Как устроено

файл роль
FormTypesProvider регистрация типа на каждую форму; делит источники между HBK и mdclasses
FormPlatformTypes словарь «сущность формы из mdclasses → платформенный тип»; 82 из 188 типов Расширение* сопоставлены, остальные — с объяснением, почему нет
FormByNameResolver резолв формы по строковому имени из ОткрытьФорму/ПолучитьФорму
FormParametersResolver стандартные параметры формы из ContextType.formParameters()
EventHandlerResolver связка «событие → процедура модуля»
FormExpressionInference знания о конструкциях форм в инференсере — отдельным компонентом, а не правкой ExpressionTypeInferencer
AssignmentByReceiverIndex близнец CallStatementByReceiverIndex: вид элемента, созданного в коде, задаётся присваиванием Элемент.Вид = …

Плюс фолбэк в builtin-platform-types.json (187 членов) — без синтакс-помощника форма
всё равно знает Элементы, Команды, Параметры и контракты своих событий.

Почему драфт

  1. Сюда попал Владелец подчинённого справочника (отдельный коммит) — вещь
    самостоятельная, вынесу отдельным PR, если так удобнее ревьюить.

  2. Часть возможностей ждёт mdclasses:
    #670 план счетов и план видов
    расчёта (единственный оставшийся TODO mdclasses# в коде),
    #671 источник данных
    динамического списка, #673
    конфигурационные основные формы, #675
    контекстные меню, #676 расширенные
    подсказки, #677
    интерфейсы-владельцы массовых свойств.

    Всё, что закрыл mdclasses#674,
    уже задействовано: события элементов (Translate NumberOfValuesInStructureConstructor.md via GitLocalize #648), команды формы ([BUG] Кривые описания некоторых диагностик #649), явный признак
    основного реквизита (make getDiagnosticClasses static #650), параметры из самой формы (Не вешать диагностику на ноды с ошибкой разбора. #651), колонки реквизитов-таблиц
    (UsingSynchronousCalls.md #666) и ВводитсяНаОсновании для основания (Translate #652).

Проверка

Новые тесты: FormTypesProviderTest, FormModuleInferenceTest, FormModuleSelfTypeTest,
OrdinaryFormParametersTest, TypeProvenanceTest, CatalogOwnerTypeTest,
ManagerCallInferenceTest — часть на новой фикстуре
src/test/resources/metadata/ordinaryForms. Под HBK (BSL_LANGUAGE_SERVER_RUN_HBK_TESTS=true) —
FormParametersHbkTest и OrdinaryFormBasisHbkTest: параметры формы и расширения видов
элементов объявлены только в синтакс-помощнике, в JSON-фолбэке их нет.

Стек

Ветка разложена на три PR, чтобы каждый заголовок был отдельной строкой changelog:

  1. Владелец подчинённого справочника типизируется по метаданным #4346 — владелец подчинённого справочника (база develop);
  2. этот PR — система типов форм (база — ветка Владелец подчинённого справочника типизируется по метаданным #4346);
  3. Обработчики событий формы: стандартные области модуля и подсказка #4347 — стандартные области модуля формы и подсказка обработчика (база — эта ветка).
    К системе типов эти правки не относятся, но опираются на её знание о том, кем объявлен
    обработчик, поэтому идут сверху, а не отдельно.

После мержа нижних PR базы вернутся на develop.

Summary by CodeRabbit

  • New Features
    • Added comprehensive type inference for managed and ordinary forms, including attributes, parameters, commands, elements, events, table data, and form modules.
    • Improved recognition of forms opened by name or manager methods, including localized names and aliases.
    • Expanded platform type information for forms, controls, collections, data structures, and catalog/document form extensions.
    • Property hovers now show configured open-structure fields with types, descriptions, and key-parameter indicators.
  • Documentation
    • Added guidance on form type resolution and extension behavior.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 893052b2-d365-47f8-8262-fbd71ec6dba2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Changes

The PR adds managed and ordinary form type registration, form-data and form-item typing, form parameter and event metadata, form-specific expression inference, open-structure hover fields, and broad integration test coverage.

Form typing and inference

Layer / File(s) Summary
Form type foundation
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/*, src/main/resources/.../builtin-platform-types.json
Adds form platform mappings, form and table data kinds, synthetic type creation, type provenance, extensions, open structures, and expanded built-in form metadata.
Form data and item registration
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/index/*, src/main/java/.../registry/FormDataTypesRegistrar.java, FormItemTypesRegistrar.java, FormParametersRegistrar.java
Registers form attributes, table data, form elements, parameters, commands, and handler roles. Adds case-insensitive indexes and specialized collection and row types.
Form type registration and integration
src/main/java/.../registry/FormTypesProvider.java, ConfigurationTypesProvider.java, ConfigurationModuleMembersProvider.java, EventHandlerResolver.java
Registers form and form-module types, connects configuration and tabular-section metadata, resolves module self-types, and exposes form event contracts and handler roles.
Form expression inference
src/main/java/.../inferencer/*
Resolves literal and manager-based form calls, form-data conversions, literal member access, and flow-sensitive form-element kind assignments.
Hover rendering and validation
src/main/java/.../hover/PlatformMemberHoverBuilder.java, src/test/java/.../*, src/main/java/.../types/CLAUDE.md
Renders open-structure fields and key-parameter descriptions. Adds integration tests for form registration, parameters, modules, inference, hover output, and type provenance. Documents the form typing architecture.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Заголовок точно описывает основное изменение: добавление типов форм конфигурации с реквизитами, элементами, параметрами и обработчиками событий.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/form-types-support

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Test Results

 3 936 files  + 48   3 936 suites  +48   1h 11m 27s ⏱️ + 8m 27s
 4 039 tests +103   3 973 ✅ + 79   66 💤 + 24  0 ❌ ±0 
24 234 runs  +618  23 834 ✅ +474  400 💤 +144  0 ❌ ±0 

Results for commit 4f9957c. ± Comparison against base commit 6b74679.

♻️ This comment has been updated with latest results.

@nixel2007

Copy link
Copy Markdown
Member

Перебазируй поверх девелопа, пожалуйста.

@nixel2007

Copy link
Copy Markdown
Member

И сонар грустит

@sfaqer

sfaqer commented Aug 1, 2026

Copy link
Copy Markdown
Member Author

И сонар грустит

Ну, пока в работе, ага.
Я сначала функционально всё доделаю, потом остальное

sfaqer and others added 12 commits August 1, 2026 17:54
Каждая форма получает собственный тип: реквизиты (включая колонки таблиц
значений и зеркала табличных частей), элементы, параметры, команды и
расширение по основному реквизиту. Обработчики событий из Form.xml
связываются с процедурами модуля формы.

Обычные формы типизируются через роль у владельца, управляемые — по
модели содержимого mdclasses. Знание о конструкциях форм в инференсере
вынесено в отдельный компонент FormExpressionInference, как того требует
устройство инференсера-диспетчера.
Регресс на путь автодополнения: у РегистрыБухгалтерии.X.СоздатьНаборЗаписей()
получатель цепочки берётся не там, где инференс, и специализация могла не
доехать до подсказки.
Тип у параметра-основания платформа не объявляет вовсе: какие объекты допустимо
передать, известно только из метаданных владельца формы. Теперь он берётся из
`ВводитсяНаОсновании` — и у управляемой формы (`Параметры.Основание`), и у обычной
(`ПараметрОснование`). Если объект ни на чём не вводится, параметру ставится
`Неопределено`: передавать в него нечего.
Основной реквизит формы теперь берётся по явному признаку `MainAttribute`, а не
эвристикой «первый реквизит, чей тип даёт расширение» (mdclasses#650).

Реквизит-`ТаблицаЗначений` и реквизит-`ДеревоЗначений` получают свои колонки:
они объявлены в самой форме, поэтому тип заводится на реквизит конкретной формы,
а колонки ложатся свойствами строки — как у зеркала табличной части (mdclasses#666).
Три возможности, которые дала переработанная модель содержимого формы:

- параметры из блока `<Parameters>` ложатся в `Форма.Параметры` рядом со
  стандартными; при совпадении имён выигрывает объявление формы (mdclasses#651);
- команды формы получают свою коллекцию `КомандыФормы.<форма>`, а процедура из
  `<Action>` становится обработчиком: объявлена она действием, но это та же
  процедура модуля, которую зовёт платформа (mdclasses#649);
- обработчики элементов (`…ПриИзменении`, `…Нажатие`) считаются обработчиками
  формы — в её модуле они и живут, — но контракт события им ищется на типе
  элемента: `ПриИзменении` объявлено у `ПолеФормы` (mdclasses#648).
`FormHandlerRoleIndex` запоминает, что за обработчик стоит за методом модуля
формы: событие самой формы, событие элемента шапки, событие элемента таблицы
(вместе с именем таблицы) или действие команды. Системе типов эта разница не
нужна — все они EVENT-члены формы, — но она видна снаружи, и считать её надо
там, где под рукой содержимое формы.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`ТекущийОбъект` у `ПриЗаписиНаСервере` объявлен как
`ДокументОбъект.<Имя документа>`, а на форме известно, какой документ туда
придёт. Заодно события формы стали override: обработчик, названный каноническим
именем события (так делает конфигуратор), приходил ещё и по наследству от
расширения — с необработанным плейсхолдером, и выигрывал дедуп.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Синтакс-помощник описывает поведение таблицы текстом в описании расширения, а не
объявлением типов, — сами члены объявлены как `Произвольный` или union из трёх
вариантов, и цепочка от них обрывалась. Теперь эти правила применяются:

- `ТекущаяСтрока` и `ТекущийРодитель` — `ИдентификаторКомпоновкиДанных` у таблиц над
  частями компоновщика настроек, свой идентификатор у диаграммы Ганта;
- `ВыделенныеСтроки` — массив таких же идентификаторов: платформа объявляет там
  обычный `Массив`, а чем он заполнен, сказано в описании;
- `ТекущиеДанные` и метод `ДанныеСтроки` — «структура, заполненная копией данных»:
  `Структура` со свойствами-колонками своей строки. Это ни строка коллекции (её
  изменение меняло бы данные формы, а копия — нет), ни голая структура (пропали бы
  колонки). Тип заводится на конкретную таблицу: колонки у каждой свои.

Оттуда же вычитаны типы данных для семи оставшихся расширений таблицы — «применимые
для оформляемых полей компоновки данных» прямо называет `ОформляемыеПоляКомпоновкиДанных`.
Таблицы формы закрыты полностью: 20 из 20.

Заодно сопоставлено поле дендрограммы (mdclasses#665 закрыт, константа появилась),
а тест на виды элементов не даст пропустить следующий такой вид молча.
`ТипЗнч(Элементы.ТабличнаяЧасть1.ТекущиеДанные)` на платформе даёт
`ДанныеФормыЭлементКоллекции`, а не `Структура`: «структура, заполненная копией
данных» из описания расширения — про устройство значения, а не про тип. Там, где
у таблицы есть строка коллекции, `ТекущиеДанные` и `ДанныеСтроки` отдают её —
с колонками и без лишней специализации `Структура`.

Заодно типизирован идентификатор строки: описание расширения его не называет,
но называют сами данные формы — `ПолучитьИдентификатор()` объявлен как `Число`.
Поэтому `ТекущаяСтрока`, `ТекущийРодитель` и элементы `ВыделенныеСтроки` у таблиц
над табличной частью, таблицей и деревом значений больше не `Произвольный`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Проверено на платформе: у таблиц над настройками компоновки
(`КомпоновщикНастроек.Настройки` и её `Отбор`) `ТипЗнч(…ТекущиеДанные)` даёт
`ДанныеФормыСтруктура`. Вместе с прошлой проверкой это значит, что тип
`Структура` таблица формы не отдаёт нигде: либо строка своей коллекции, либо
`ДанныеФормыСтруктура`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…всем

Платформа объявляет параметры расширения одинаково для всего вида объектов, а
есть они не у всех: отбор по владельцу — только у подчинённого справочника,
отбор по регистратору — только у регистра, в который кто-то пишет движения,
текущая строка журнала — только при зарегистрированных документах. Раньше такой
параметр оставался «обобщённым»: в автодополнении выглядел рабочим, а за ним
стоял невалидный `ДокументСсылка.<Имя документа>`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Константы подняты к началу своих классов (`java:S1213` — поля до методов),
регулярка разбора многоабзацного описания вынесена в скомпилированный `Pattern`
без вложенных квантификаторов (`java:S5998`: экспоненциальный откат на длинном
тексте), список функций открытия формы стал `Set` вместо цепочки `equals`,
убраны неиспользуемая константа, дублирующийся литерал имени расширения таблицы
и магические числа в размерах списков.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sfaqer and others added 4 commits August 1, 2026 17:54
…артами

`FormPlatformTypes` держал три перечисления вложенными классами по сотне строк
каждое (`java:S2972`) — они стали самостоятельными файлами пакета: `FormKind`,
`TableDataKind`, `FormDataKind`. Два разбора по видам (расширение элемента и
расширение обычной формы) переписаны картами: `switch` на три десятка ветвей
давал цикломатическую сложность втрое выше порога (`java:S1541`), а зависит имя
расширения только от самого вида.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`FormTypesProvider` тянул на себе всё сразу — от обхода конфигурации до
преобразования реквизитов в данные формы (`java:S1448`, `java:S1200`). Первый
разрез: `FormDataTypesRegistrar` забирает то, во что превращается реквизит и
табличная часть объекта, вместе с картами уже заведённых типов. Провайдер
обращается к нему за типами реквизитов и строкой коллекции, а
`ConfigurationTypesProvider` регистрирует зеркала табличных частей напрямую.

Двуязычные имена из метаданных (`neutral`, `bilingual`) переехали в словарь
`FormPlatformTypes` — ими пользуются оба.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Второй разрез `FormTypesProvider` (`java:S1448`, `java:S1200`):
`FormItemTypesRegistrar` забрал типы видов элементов, коллекцию `Элементы`, типы
таблиц и правила их членов. Провайдер — 1524 → 1050 строк.

Общее для регистраторов вынесено по смыслу: заведение синтетического типа с
английским алиасом — в маленький `FormTypeFactory`, свойство платформенного вида
(`platformProperty`) — в словарь имён `FormPlatformTypes`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Третий, последний разрез `FormTypesProvider`: `FormParametersRegistrar` забрал
структуру параметров управляемой формы, параметры-свойства обычной (вместе с
подстановкой владельца и подавлением несуществующих) и команды. Провайдер —
1820 → 730 строк и 84 → 32 метода, то есть ниже порогов `java:S1448` и
`java:S1200`, из-за которых резали.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sfaqer
sfaqer force-pushed the feat/form-types-support branch from 1538835 to 77881e5 Compare August 1, 2026 07:54
sfaqer and others added 2 commits August 1, 2026 18:43
…яются

В синтакс-помощнике блок «Тип» есть не у всякого свойства — по всей платформе
таких под две сотни. У элементов формы из-за этого обрывалась цепочка:
`Элементы.Таблица.АвтоОтметкаНезаполненного` не показывало даже того, что это
Булево.

Тип берётся оттуда, где его называет сама платформа: из описания свойства либо
из объявления одноимённого свойства другого типа. Доопределяется только тип —
описание, режим доступа и версии остаются платформенными.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`РеквизитФормыВЗначение("Объект")` и `ДанныеФормыВЗначение(Объект, Тип("…"))`
объявлены возвращающими `Произвольный`, хотя прикладной тип известен: у второй
он всегда в обязательном параметре, у первой без параметра — это объявленный в
`Form.xml` тип реквизита (`ДокументОбъект.Заказ`), а не `ДанныеФормыСтруктура`,
которой реквизит выглядит на форме.

Объявленные типы держит `FormAttributeTypeIndex`: свойством формы такой тип не
выставишь, а обратному преобразованию нужен именно он.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sfaqer

sfaqer commented Aug 1, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@sfaqer
sfaqer marked this pull request as ready for review August 1, 2026 09:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/ExpressionTypeInferencer.java (1)

911-926: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the leftover duplicate Javadoc block.

The Javadoc that starts at Line 911 is never closed. A second /** starts at Line 914 and describes the same method, variablesOfBody. The compiler treats both as one comment, so the build passes, but the rendered Javadoc contains a duplicated, truncated description. The block at Line 911-913 looks like a leftover from an edit.

♻️ Proposed cleanup
-  /**
-   * Переменные, живущие в том же теле, что и заданная: расчёт по потоку считает их все
-   * разом, одним поиском неподвижной точки.
   /**
    * Переменные, видимые в теле: расчёт по потоку считает их все разом, одним поиском
    * неподвижной точки.

As per coding guidelines: "Javadoc классов и методов должен описывать контракт: параметры, результат, инварианты и побочные эффекты".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/ExpressionTypeInferencer.java`
around lines 911 - 926, Remove the leftover unterminated Javadoc fragment
immediately before the complete documentation for variablesOfBody, keeping only
the second Javadoc block with the method’s full description, parameters, and
return contract.

Source: Coding guidelines

🧹 Nitpick comments (20)
src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ManagerCallInferenceTest.java (3)

50-51: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Rename PATH_TO_RECORDERS.

The constant points to src/test/resources/metadata/ordinaryForms, but the name states "recorders". OrdinaryFormBasisHbkTest.java line 56 names the same path PATH_TO_ORDINARY_FORMS. Use that name here for consistency.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ManagerCallInferenceTest.java`
around lines 50 - 51, Rename the constant PATH_TO_RECORDERS to
PATH_TO_ORDINARY_FORMS in ManagerCallInferenceTest and update all references to
use the new name, preserving its existing path value.

107-120: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Guard the caret computation.

Line 113 uses content.indexOf(';', rhsStart) without checking the result. If the statement has no ;, indexOf returns -1, lastIndexOf('.', -1) also returns -1, and caret becomes 0. The test then queries position (0, 0) and fails with a confusing message. Line 110 has a related problem: indexOf(marker) matches any identifier that ends with assignedVar, so a longer variable name in the fixture selects the wrong statement.

Assert the statement terminator and the dot index before you use them.

♻️ Proposed guard
   var rhsStart = markerIdx + marker.length();
-  var caret = content.lastIndexOf('.', content.indexOf(';', rhsStart)) + 1;
+  var statementEnd = content.indexOf(';', rhsStart);
+  assertThat(statementEnd).as("не найден `;` после `%s`", marker).isGreaterThan(rhsStart);
+  var dotIdx = content.lastIndexOf('.', statementEnd);
+  assertThat(dotIdx).as("не найден `.` в правой части `%s`", marker).isGreaterThan(rhsStart);
+  var caret = dotIdx + 1;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ManagerCallInferenceTest.java`
around lines 107 - 120, Update typesAtRhs to locate the assignment using an
exact identifier boundary rather than the broad assignedVar + " = " search, and
validate that the matching statement is the intended one. Guard the semicolon
lookup and dot lookup with assertions before calculating caret, so missing
delimiters fail with clear messages instead of querying position (0, 0).

73-85: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Locate these positions from the fixture text.

Lines 76 and 83 hardcode Position(5, 64) and Position(3, 8). Any edit to CommonModules/Модуль1/Ext/Module.bsl shifts these coordinates, and the tests then check the wrong expression. The class already resolves positions from the content in typesAtRhs. Use the same approach here, for example by searching for СоздатьНаборЗаписей(). and Набор..

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ManagerCallInferenceTest.java`
around lines 73 - 85, Update receiverOfChainedCallIsTheSpecializedRecordSet and
receiverOfVariableIsTheSpecializedRecordSet to derive query positions from the
fixture content, matching the existing typesAtRhs approach. Locate the relevant
expressions by searching for “СоздатьНаборЗаписей().” and “Набор.” instead of
hardcoding Position coordinates, so edits to the fixture do not invalidate the
tests.
src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersHbkTest.java (3)

193-193: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Name the -1 argument.

The literal -1 in platformMemberHoverBuilder.build(formRef, parameters, -1) does not state its meaning. Extract it to a named constant, for example NO_ACTIVE_SIGNATURE.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersHbkTest.java`
at line 193, Replace the magic -1 argument in the FormParametersHbkTest call to
platformMemberHoverBuilder.build with a descriptive named constant such as
NO_ACTIVE_SIGNATURE, and pass that constant to make the argument’s meaning
explicit.

206-212: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reduce coupling to the syntax-helper description text.

Line 211 asserts a literal fragment of a 1C syntax-helper description, including exact trailing spaces and indentation. The stated intent is the markdown hard-break format, not the wording. A 1C platform update that rewords this description breaks the test for a reason unrelated to the code under test. Consider asserting the formatting pattern against the description text read from the member, instead of a hardcoded Russian sentence.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersHbkTest.java`
around lines 206 - 212, Update the assertion in FormParametersHbkTest to derive
the expected paragraph text from the relevant member’s syntax-helper
description, while still verifying the hard-break newline and marker-width
indentation format. Remove the hardcoded Russian wording so platform rewording
does not break the test.

454-459: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the type-ref set before you take its first element. Both test classes read the first return type with returnTypes().refs().iterator().next() without checking that the ref set is non-empty. If a member resolves but carries no type, the tests throw NoSuchElementException with no indication of which member or type was involved. The shared root cause is a missing emptiness assertion on refs().

  • src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersHbkTest.java#L454-L459: add an assertion that parameters.returnTypes().refs() is not empty in parametersOf before iterator().next(), and apply the same guard at lines 176, 226, and 296.
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProviderTest.java#L116-L124: extract one helper that asserts refs() is not empty and returns the first ref, then use it at lines 120, 566, 591, and 606.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersHbkTest.java`
around lines 454 - 459, Assert that each returnTypes().refs() collection is
non-empty before accessing its first element, preserving a clear failure at the
affected lookups. In FormParametersHbkTest.java at lines 454-459, 176, 226, and
296, add this guard before iterator().next(); in FormTypesProviderTest.java at
lines 116-124, extract a helper that performs the assertion and returns the
first ref, then use it at lines 120, 566, 591, and 606.
src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProviderTest.java (2)

638-643: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Fail with a message instead of returning null.

find returns null when no member matches. Several call sites dereference the result without a null check, for example lines 312, 315, 337, 595, and 615. A missing member then produces a NullPointerException with no indication of which member was absent. Add an assertion inside the helper, or keep the nullable contract only where a test asserts absence.

♻️ Proposed helper change
 private static MemberDescriptor find(Collection<MemberDescriptor> members, MemberKind kind, String name) {
   return members.stream()
     .filter(m -> m.kind() == kind && m.matches(name))
     .findFirst()
-    .orElse(null);
+    .orElseThrow(() -> new AssertionError("не найден член %s (%s)".formatted(name, kind)));
 }

Tests that assert absence, such as lines 380 and 557, then need a separate nullable lookup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProviderTest.java`
around lines 638 - 643, Update the `find` helper to fail with a descriptive
assertion when no matching member exists instead of returning `null`, so
dereferencing call sites identify the missing kind and name. Add a separate
nullable lookup helper for absence assertions at the relevant tests, and update
those absence-check call sites to use it while preserving their expected null
behavior.

137-230: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the repeated form-data navigation.

Five tests repeat the same three steps: read the Объект property, assert it is not null, and take the first return type ref. See lines 139-141, 160-162, 175-177, 199-206, and 223-230. Extract one helper, for example objectDataType(String formTypeName), and a second helper for the ТабличнаяЧасть1 lookup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProviderTest.java`
around lines 137 - 230, Extract the repeated “Объект” property lookup into a
shared helper such as objectDataType(String formTypeName), preserving the
existing non-null assertion and first return-type reference behavior. Add a
second helper for locating the “ТабличнаяЧасть1” member and resolving its
referenced type, then update the affected tests to use these helpers without
changing their assertions.
src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormModuleSelfTypeTest.java (1)

100-110: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Restore the removed module type after the test.

Line 105 removes the cached module type for CATALOG_FORM_MODULE from the shared GlobalScopeProvider. The context is initialized once per class, so this mutation stays for the rest of the class. No other test in this class reads that URI today, so the test passes now. A future test that uses CATALOG_FORM_MODULE would then depend on execution order. Consider restoring the entry in an @AfterEach or rebuilding the document at the end of the test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormModuleSelfTypeTest.java`
around lines 100 - 110, Restore the cached module type removed by
globalScopeProvider.removeModuleType in
selfMemberLookupWorksBeforeModuleTypeCacheIsFilled after the assertion
completes, preferably via an `@AfterEach` cleanup that rebuilds or republishes the
CATALOG_FORM_MODULE entry. Ensure shared state is reset even when the test
fails.
src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeProvenanceTest.java (1)

44-44: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse TestUtils.PATH_TO_METADATA.

TypeProvenanceTest and nearby registry tests use the same designer metadata fixture; import TestUtils.PATH_TO_METADATA here and remove the local duplicate, keeping fixture paths in TestUtils.java as the shared source.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeProvenanceTest.java`
at line 44, Update TypeProvenanceTest to import and use
TestUtils.PATH_TO_METADATA, then remove its local PATH_TO_METADATA declaration.
Preserve all existing references while making TestUtils.java the shared source
for the designer metadata fixture path.
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormDataTypesRegistrar.java (1)

34-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the unused import.

MultiLanguageString is not referenced in this file. SonarCloud flags it.

♻️ Proposed fix
-import com.github._1c_syntax.bsl.types.MultiLanguageString;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormDataTypesRegistrar.java`
at line 34, Remove the unused MultiLanguageString import from
FormDataTypesRegistrar; no other changes are needed.

Source: Linters/SAST tools

src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersRegistrar.java (1)

24-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the three unused imports.

Placeholder, MemberKind, and ObjectForm are not referenced in this file. SonarCloud flags all three.

♻️ Proposed fix
-import com.github._1c_syntax.bsl.context.api.Placeholder;
...
-import com.github._1c_syntax.bsl.languageserver.types.model.MemberKind;
...
-import com.github._1c_syntax.bsl.mdo.children.ObjectForm;

Also applies to: 29-29, 40-40

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersRegistrar.java`
at line 24, Remove the unused Placeholder, MemberKind, and ObjectForm imports
from FormParametersRegistrar, leaving all referenced imports and implementation
unchanged.

Source: Linters/SAST tools

src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormByNameResolver.java (1)

103-106: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Drop the dead null check.

formName is a non-null parameter, so formName == null is always false. SonarCloud reports it. isBlank() alone covers the guard.

♻️ Proposed fix
-    if (formName == null || formName.isBlank()) {
+    if (formName.isBlank()) {
       return Optional.empty();
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormByNameResolver.java`
around lines 103 - 106, Remove the redundant formName == null condition from
FormByNameResolver.resolve and retain the isBlank() guard so blank form names
still return Optional.empty().

Source: Linters/SAST tools

src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.java (3)

36-37: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the same-package imports.

FormKind and TableDataKind are in com.github._1c_syntax.bsl.languageserver.types.registry, the package of this class. The imports are redundant. TableDataKind also has no other use here.

♻️ Proposed fix
-import com.github._1c_syntax.bsl.languageserver.types.registry.FormKind;
-import com.github._1c_syntax.bsl.languageserver.types.registry.TableDataKind;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.java`
around lines 36 - 37, Remove the redundant same-package imports for FormKind and
TableDataKind from FormTypesProvider; also remove TableDataKind since it has no
other usage in the class.

151-154: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the leftover Javadoc blocks.

Three Javadoc comments no longer document a member: the "Свойства таблицы…" block at Line 151, the "Тип на вид элемента формы…" block at Line 169, and the "Подставляет имя объекта-владельца…" block at Line 318. Their code moved to FormItemTypesRegistrar and FormParametersRegistrar. SonarCloud reports them as dangling. Keeping them makes the class documentation describe members that do not exist.

As per coding guidelines: "Javadoc классов и методов должен описывать контракт: параметры, результат, инварианты и побочные эффекты".

Also applies to: 169-170, 318-324

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.java`
around lines 151 - 154, Remove the three dangling Javadoc blocks in
FormTypesProvider: the comments beginning “Свойства таблицы…”, “Тип на вид
элемента формы…”, and “Подставляет имя объекта-владельца…”. Do not alter the
associated fields or behavior; their documentation belongs with the moved code
in FormItemTypesRegistrar and FormParametersRegistrar.

Sources: Coding guidelines, Linters/SAST tools


387-387: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Call the static helper on the class.

attributeTypesByName is static in FormItemTypesRegistrar. The call goes through the instance formItemTypes. SonarCloud reports it. Use FormItemTypesRegistrar.attributeTypesByName(...).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.java`
at line 387, Update the call in FormTypesProvider to invoke the static
attributeTypesByName helper through FormItemTypesRegistrar instead of the
formItemTypes instance, preserving the existing data.getAttributes() argument
and assignment.

Source: Linters/SAST tools

src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeRegistry.java (2)

956-962: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Consider rejecting a self-extension.

copyMembers registers a lazy MemberSource that calls getMembers(source, fileType). If a caller passes the same ref as target and source, that source calls back into the members of the same type and the computation recurses until the stack overflows. The class already documents this self-closing hazard for expandedMembers. A cheap identity guard makes registerExtension safe for every caller.

♻️ Proposed guard
   public void registerExtension(TypeRef target, TypeRef source, FileType fileType) {
-    if (target == null || source == null) {
+    if (target == null || source == null || target.equals(source)) {
       return;
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeRegistry.java`
around lines 956 - 962, Update registerExtension to reject self-extensions by
returning when target and source refer to the same type, before mutating
extensions or calling copyMembers. Preserve the existing null-argument guard and
normal behavior for distinct TypeRef values.

1584-1610: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

State the repeat-registration semantics of registerOpenStructure.

registerOpenStructure uses put, so a second call for the same ref replaces the recorded base type. The neighboring indexes in this class use putIfAbsent and document "первая регистрация выигрывает". Record the chosen rule in the Javadoc so callers know that the last registration wins.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeRegistry.java`
around lines 1584 - 1610, Update the Javadoc for registerOpenStructure to
explicitly document that repeated registration of the same ref replaces the
previously recorded base type, so the last registration wins. Keep the existing
put-based behavior unchanged and place the rule near the method’s parameter or
behavior description.
src/main/resources/com/github/_1c_syntax/bsl/languageserver/types/registry/builtin-platform-types.json (1)

4874-4915: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Declare signatures for the methods that take parameters.

НайтиПоИдентификатору, НайтиСтроки and Выгрузить are declared without a signatures block, so the fallback pack carries no parameter metadata for them. Signature help, parameter hover and arity-based overload selection then see zero signatures for these methods. Every other method added in this file declares signatures. The same gap exists in КомандыФормы.Найти, КомандыФормы.Добавить and ДанныеФормыКоллекция.Добавить.

♻️ Example for `НайтиПоИдентификатору`
       {
         "name": "НайтиПоИдентификатору",
         "nameRu": "НайтиПоИдентификатору",
         "nameEn": "FindByID",
         "kind": "METHOD",
         "returnType": "ДанныеФормыЭлементКоллекции",
-        "description": "Возвращает строку по идентификатору."
+        "description": "Возвращает строку по идентификатору.",
+        "signatures": [
+          {
+            "parameters": [
+              {
+                "name": "Идентификатор",
+                "nameRu": "Идентификатор",
+                "nameEn": "ID",
+                "types": [
+                  "Число"
+                ],
+                "description": "Идентификатор искомой строки."
+              }
+            ]
+          }
+        ]
       },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/resources/com/github/_1c_syntax/bsl/languageserver/types/registry/builtin-platform-types.json`
around lines 4874 - 4915, Declare the appropriate signatures metadata for the
parameterized methods НайтиПоИдентификатору, НайтиСтроки, Выгрузить,
КомандыФормы.Найти, КомандыФормы.Добавить, and ДанныеФормыКоллекция.Добавить.
Match the signature structure and parameter types used by equivalent methods
elsewhere in the registry so signature help, hover, and arity-based selection
expose their parameters.
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormPlatformTypes.java (1)

339-367: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Detached Javadoc blocks in two registry files. In both files a Javadoc block stands directly before a different method than the one it documents, which leaves the intended method undocumented and produces the SonarCloud "dangling Javadoc" findings.

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormPlatformTypes.java#L339-L367: move the block that documents the same-name-in-both-locales helper down to neutral(String) at line 365.
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TableDataKind.java#L141-L167: move the block that documents attributeTypeRu/nested down to of(String, boolean) at line 167.

Based on the coding guideline "Javadoc классов и методов должен описывать контракт: параметры, результат, инварианты и побочные эффекты".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormPlatformTypes.java`
around lines 339 - 367, Move the same-name bilingual helper Javadoc in
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormPlatformTypes.java:339-367
so it directly documents neutral(String), leaving
platformProperty(BilingualString, TypeRef, BilingualString) with its own
Javadoc. In
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TableDataKind.java:141-167,
move the Javadoc describing attributeTypeRu/nested so it directly documents
of(String, boolean); do not alter the documented contracts.

Sources: Coding guidelines, Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/PlatformMemberHoverBuilder.java`:
- Around line 250-292: Refactor appendOpenStructureFields by computing
BslContextPlatformTypesProvider.KEY_PARAMETER_MARKER.forLanguage(lang) once
before the types.refs() loop. Extract each member’s filtering and rendering
logic into a private helper such as appendFieldLine, passing sb, member,
keyMarker, and lang, while preserving the existing output and filtering
behavior.

In `@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/CLAUDE.md`:
- Around line 164-166: Update the documentation text describing
ConfigurationTypesProvider.registerTabularSections so registerTabularSectionData
is attributed to FormDataTypesRegistrar, matching the formDataTypesRegistrar
call shown in the implementation; leave the surrounding navigation guidance
unchanged.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/FormExpressionInference.java`:
- Around line 227-236: Update typeArgument in FormExpressionInference to
validate typeCall.getName() is non-null before dereferencing it with getText().
Return null for a missing name, while preserving the existing type-function
validation for named calls.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ConfigurationModuleMembersProvider.java`:
- Around line 223-227: Update registerFormModule to invalidate the memoized
members with typeRegistry.invalidateMembers(ref) when the URI was already
registered with the same ref, before returning early. Preserve the existing
registration and indexing flow for new or changed registrations.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormDataTypesRegistrar.java`:
- Around line 70-83: Replace the plain maps formDataTypes, tabularSectionData,
and rowByCollection in FormDataTypesRegistrar.java:70-83 with ConcurrentHashMap
instances. Apply the same concurrent-map change to itemKindTypes and
tableDataKindTypes in FormItemTypesRegistrar.java:88-92, preserving their
existing key/value types and access behavior.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormPlatformTypes.java`:
- Around line 589-607: Update the Javadoc for extensionTypeNames to document
both parameters using their current String and FormKind meanings, and change the
`@return` description to state that the method returns a list of qualified
extension type names, using an empty list when no extension applies; do not
describe a nullable or singular result.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.java`:
- Line 255: Update the registration flow containing
FormHandlerRoleIndex.register and register the collected handler roles under the
ordinary form module type key as well as formRef, matching the unsuffixed key
used by registerModuleType. Preserve the existing managed-form registration and
ensure roleOf() can resolve handlers declared in ordinary forms.

In
`@src/main/resources/com/github/_1c_syntax/bsl/languageserver/types/registry/builtin-platform-types.json`:
- Around line 4934-4950: Add the ПолучитьЭлементы method to both
ДанныеФормыДерево and ДанныеФормыЭлементДерева in the builtin type registry,
declaring it as returning the child-row collection with item type
ДанныеФормыЭлементДерева. Preserve the existing НайтиПоИдентификатору definition
and ensure FormDataKind.TREE exposes the declared element type to consumers.

---

Outside diff comments:
In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/ExpressionTypeInferencer.java`:
- Around line 911-926: Remove the leftover unterminated Javadoc fragment
immediately before the complete documentation for variablesOfBody, keeping only
the second Javadoc block with the method’s full description, parameters, and
return contract.

---

Nitpick comments:
In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormByNameResolver.java`:
- Around line 103-106: Remove the redundant formName == null condition from
FormByNameResolver.resolve and retain the isBlank() guard so blank form names
still return Optional.empty().

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormDataTypesRegistrar.java`:
- Line 34: Remove the unused MultiLanguageString import from
FormDataTypesRegistrar; no other changes are needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersRegistrar.java`:
- Line 24: Remove the unused Placeholder, MemberKind, and ObjectForm imports
from FormParametersRegistrar, leaving all referenced imports and implementation
unchanged.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormPlatformTypes.java`:
- Around line 339-367: Move the same-name bilingual helper Javadoc in
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormPlatformTypes.java:339-367
so it directly documents neutral(String), leaving
platformProperty(BilingualString, TypeRef, BilingualString) with its own
Javadoc. In
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TableDataKind.java:141-167,
move the Javadoc describing attributeTypeRu/nested so it directly documents
of(String, boolean); do not alter the documented contracts.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.java`:
- Around line 36-37: Remove the redundant same-package imports for FormKind and
TableDataKind from FormTypesProvider; also remove TableDataKind since it has no
other usage in the class.
- Around line 151-154: Remove the three dangling Javadoc blocks in
FormTypesProvider: the comments beginning “Свойства таблицы…”, “Тип на вид
элемента формы…”, and “Подставляет имя объекта-владельца…”. Do not alter the
associated fields or behavior; their documentation belongs with the moved code
in FormItemTypesRegistrar and FormParametersRegistrar.
- Line 387: Update the call in FormTypesProvider to invoke the static
attributeTypesByName helper through FormItemTypesRegistrar instead of the
formItemTypes instance, preserving the existing data.getAttributes() argument
and assignment.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeRegistry.java`:
- Around line 956-962: Update registerExtension to reject self-extensions by
returning when target and source refer to the same type, before mutating
extensions or calling copyMembers. Preserve the existing null-argument guard and
normal behavior for distinct TypeRef values.
- Around line 1584-1610: Update the Javadoc for registerOpenStructure to
explicitly document that repeated registration of the same ref replaces the
previously recorded base type, so the last registration wins. Keep the existing
put-based behavior unchanged and place the rule near the method’s parameter or
behavior description.

In
`@src/main/resources/com/github/_1c_syntax/bsl/languageserver/types/registry/builtin-platform-types.json`:
- Around line 4874-4915: Declare the appropriate signatures metadata for the
parameterized methods НайтиПоИдентификатору, НайтиСтроки, Выгрузить,
КомандыФормы.Найти, КомандыФормы.Добавить, and ДанныеФормыКоллекция.Добавить.
Match the signature structure and parameter types used by equivalent methods
elsewhere in the registry so signature help, hover, and arity-based selection
expose their parameters.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormModuleSelfTypeTest.java`:
- Around line 100-110: Restore the cached module type removed by
globalScopeProvider.removeModuleType in
selfMemberLookupWorksBeforeModuleTypeCacheIsFilled after the assertion
completes, preferably via an `@AfterEach` cleanup that rebuilds or republishes the
CATALOG_FORM_MODULE entry. Ensure shared state is reset even when the test
fails.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersHbkTest.java`:
- Line 193: Replace the magic -1 argument in the FormParametersHbkTest call to
platformMemberHoverBuilder.build with a descriptive named constant such as
NO_ACTIVE_SIGNATURE, and pass that constant to make the argument’s meaning
explicit.
- Around line 206-212: Update the assertion in FormParametersHbkTest to derive
the expected paragraph text from the relevant member’s syntax-helper
description, while still verifying the hard-break newline and marker-width
indentation format. Remove the hardcoded Russian wording so platform rewording
does not break the test.
- Around line 454-459: Assert that each returnTypes().refs() collection is
non-empty before accessing its first element, preserving a clear failure at the
affected lookups. In FormParametersHbkTest.java at lines 454-459, 176, 226, and
296, add this guard before iterator().next(); in FormTypesProviderTest.java at
lines 116-124, extract a helper that performs the assertion and returns the
first ref, then use it at lines 120, 566, 591, and 606.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProviderTest.java`:
- Around line 638-643: Update the `find` helper to fail with a descriptive
assertion when no matching member exists instead of returning `null`, so
dereferencing call sites identify the missing kind and name. Add a separate
nullable lookup helper for absence assertions at the relevant tests, and update
those absence-check call sites to use it while preserving their expected null
behavior.
- Around line 137-230: Extract the repeated “Объект” property lookup into a
shared helper such as objectDataType(String formTypeName), preserving the
existing non-null assertion and first return-type reference behavior. Add a
second helper for locating the “ТабличнаяЧасть1” member and resolving its
referenced type, then update the affected tests to use these helpers without
changing their assertions.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ManagerCallInferenceTest.java`:
- Around line 50-51: Rename the constant PATH_TO_RECORDERS to
PATH_TO_ORDINARY_FORMS in ManagerCallInferenceTest and update all references to
use the new name, preserving its existing path value.
- Around line 107-120: Update typesAtRhs to locate the assignment using an exact
identifier boundary rather than the broad assignedVar + " = " search, and
validate that the matching statement is the intended one. Guard the semicolon
lookup and dot lookup with assertions before calculating caret, so missing
delimiters fail with clear messages instead of querying position (0, 0).
- Around line 73-85: Update receiverOfChainedCallIsTheSpecializedRecordSet and
receiverOfVariableIsTheSpecializedRecordSet to derive query positions from the
fixture content, matching the existing typesAtRhs approach. Locate the relevant
expressions by searching for “СоздатьНаборЗаписей().” and “Набор.” instead of
hardcoding Position coordinates, so edits to the fixture do not invalidate the
tests.

In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeProvenanceTest.java`:
- Line 44: Update TypeProvenanceTest to import and use
TestUtils.PATH_TO_METADATA, then remove its local PATH_TO_METADATA declaration.
Preserve all existing references while making TestUtils.java the shared source
for the designer metadata fixture path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 08526ee9-9952-4516-88b9-3d3ca06b2e3f

📥 Commits

Reviewing files that changed from the base of the PR and between 6b74679 and bd0edaf.

⛔ Files ignored due to path filters (27)
  • src/test/resources/metadata/designer/Documents/Документ1.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/designer/Documents/Документ1/Forms/ФормаДокумента/Ext/Form.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/designer/InformationRegisters/РегистрСведений1.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/designer/InformationRegisters/РегистрСведений1/Forms/ФормаЗаписи.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/designer/InformationRegisters/РегистрСведений1/Forms/ФормаЗаписи/Ext/Form.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/AccountingRegisters/РегистрБухгалтерии1.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/CalculationRegisters/РегистрРасчета1.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/CalculationRegisters/РегистрРасчета1/Forms/ФормаСписка.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/Catalogs/Справочник1.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/Catalogs/Справочник1/Forms/ФормаВыбора.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/Catalogs/Справочник1/Forms/ФормаСписка.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/Catalogs/Справочник1/Forms/ФормаЭлемента.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/Catalogs/Справочник2.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/Catalogs/Справочник2/Forms/ФормаСписка.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/Catalogs/Справочник2/Forms/ФормаЭлемента.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/CommonModules/Модуль1.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/CommonModules/Модуль1/Ext/Module.bsl is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/Configuration.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/DocumentJournals/ЖурналДокументов1.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/DocumentJournals/ЖурналДокументов1/Forms/ФормаСписка.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/DocumentJournals/ЖурналДокументов2.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/DocumentJournals/ЖурналДокументов2/Forms/ФормаСписка.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/Documents/Документ1.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/InformationRegisters/РегистрСведений1.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/InformationRegisters/РегистрСведений1/Forms/ФормаЗаписи.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/InformationRegisters/РегистрСведений1/Forms/ФормаСписка.xml is excluded by !src/test/resources/**
  • src/test/resources/metadata/ordinaryForms/Languages/Русский.xml is excluded by !src/test/resources/**
📒 Files selected for processing (34)
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/PlatformMemberHoverBuilder.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/CLAUDE.md
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/index/AssignmentByReceiverIndex.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/ExpressionTypeInferencer.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/FormExpressionInference.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/BslContextPlatformTypesProvider.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ConfigurationModuleMembersProvider.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ConfigurationTypesProvider.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/EventHandlerResolver.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormAttributeTypeIndex.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormByNameResolver.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormDataKind.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormDataTypesRegistrar.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormHandlerRoleIndex.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormItemTypesRegistrar.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormKind.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersRegistrar.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersResolver.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormPlatformTypes.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypeFactory.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/RegisterFamilies.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TableDataKind.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeRegistry.java
  • src/main/resources/com/github/_1c_syntax/bsl/languageserver/types/registry/builtin-platform-types.json
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/types/FormModuleInferenceTest.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ConfigurationTypesProviderHelpersTest.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormModuleSelfTypeTest.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersHbkTest.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProviderTest.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ManagerCallInferenceTest.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/OrdinaryFormBasisHbkTest.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/OrdinaryFormParametersTest.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeProvenanceTest.java

// Роли считаются сразу: имена дешевле членов (в реестр не ходим), а знать, кем
// объявлен обработчик, нужно снаружи системы типов — стандартным областям модуля
// и hover'у.
formHandlerRoleIndex.register(formRef, collectHandlerRoles(data));

@coderabbitai coderabbitai Bot Aug 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C5 'FormHandlerRoleIndex|roleOf\(' src/main/java src/test/java --glob '*.java'
rg -n -C3 'MODULE_SUFFIX|moduleTypeQualifiedName' src/main/java --glob '*.java'

Repository: 1c-syntax/bsl-language-server

Length of output: 25833


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant registrations/types, event owner resolution, and the ordinary form test fixture.
sed -n '240,330p' src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.java
sed -n '200,235p' src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ConfigurationModuleMembersProvider.java
rg -n -C3 'eventOwnerTypeRef|EventHandlerResolver|registerConfigurationType|byForm|FormHandlerRoleIndex' src/main/java src/test/java --glob '*.java'
fd -a '.*FormModule.*|.*Form.*Test.*' src/test/java/com/github/_1c_syntax/bsl/languageserver | sed 's#^\./##' | sort
# Locate metadata referenced by FormModuleSelfTypeTest if present
rg -n 'DOCUMENT_FORM_MODULE|PATH_TO_METADATA|ПриЗаписиНаСервере|Реквизит1ПриИзменении|ТабличнаяЧасть1Реквизит1ПриИзменении|ЗаполнитьПоОснованиюКоманда' src/test/java --glob '*.java'

Repository: 1c-syntax/bsl-language-server

Length of output: 50386


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== FormHandlerRoleIndex =="
sed -n '1,120p' src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormHandlerRoleIndex.java

echo
echo "== FormTypesProvider registration =="
sed -n '200,305p' src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.java
sed -n '305,365p' src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.java

echo
echo "== ConfigurationModuleMembersProvider ordinary form owner/module registration =="
sed -n '128,155p' src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ConfigurationModuleMembersProvider.java
sed -n '214,226p' src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ConfigurationModuleMembersProvider.java
sed -n '226,245p' src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ConfigurationModuleMembersProvider.java

echo
echo "== Event handler resolver implementation =="
fd -a 'EventHandlerResolver.java' src/main/java | sed 's#^\./##' | while read -r f; do
  echo "--- $f"
  rg -n -C3 'eventOwnerTypeRef|resolveOwnerType|MODULE_SUFFIX|FormTypesProvider|Form.*MODULE' "$f" || true
done

echo
echo "== FormModuleSelfTypeTest class outline and target area =="
wc -l src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormModuleSelfTypeTest.java
sed -n '1,175p' src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormModuleSelfTypeTest.java

echo
echo "== Ordinary form test fixtures =="
rg -n -C4 'FORM_TYPE_ORDINARY|OrdINARY|Ordinary|commonTypes|FormOrdinary|ordinary|Обычная|ПриЗаписиНаСервере|Реквизит1ПриИзменении|ТабличнаяЧасть1Реквизит1ПриИзменении|ЗаполнитьПоОснованиюКоманда' src/test/java --glob '*.java'

echo
echo "== Read-only model probe for ordinary form module role lookup path =="
python3 - <<'PY'
from pathlib import Path
import re

fp = Path('src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.java')
text = fp.read_text(encoding='utf-8')

form_self = re.search(r'public\s+static\s+String\s+selfTypeQualifiedName\s*\([^)]*\).*?\{(?P<body>.*?)\n\s*}', text, re.S)
mod_self = re.search(r'public\s+static\s+String\s+moduleTypeQualifiedName\s*\([^)]*\).*?\{(?P<body>.*?)\n\s*}', text, re.S)

checks = {
    'M MODULE_SUFFIX': '" (модуль)"' in text,
    'moduleTypeQualifiedName adds MODULE_SUFFIX for ordinary':
        'FormKind.of(form.getFormType()) == FormKind.ORDINARY ? formName + MODULE_SUFFIX : formName' in text,
    'formHandlerRoleIndex.register uses formRef':
        bool(re.search(r'formHandlerRoleIndex\.register\s*\(\s*formRef\s*,\s*collectHandlerRoles\s*\(', text)),
    'registerModuleType uses moduleTypeQualifiedName for ref':
        bool(re.search(r'var\s+moduleRef\s*=\s*typeRegistry\.registerConfigurationType\s*\(\s*moduleTypeQualifiedName\s*\(\s*form\s*\)', text, re.S)),
}

print('\n'.join(f'{k}: {v}' for k, v in checks.items()))
print(f'\nFile size: {fp.stat().st_size} bytes, lines {text.count(chr(10))+1}')
PY

Repository: 1c-syntax/bsl-language-server

Length of output: 50386


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== EventHandlerResolver ordinary module owner handling =="
sed -n '320,390p' src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/EventHandlerResolver.java

echo
echo "== FormTypesProvider module type qualified name range (no empty lines) =="
python3 - <<'PY'
from pathlib import Path
p=Path('src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.java')
lines=p.read_text().splitlines()
for i,l in enumerate(lines,1):
    if 'public static String moduleTypeQualifiedName' in l or 'MODULE_SUFFIX' in l or 'selfTypeQualifiedName' in l or 'registerForm' in l or 'registerModuleType' in l or 'formHandlerRoleIndex.register' in l:
        print(f'{i}: {l}')
PY

echo
echo "== Ordinary form form type fixture =="
fd -a 'Form.xml' src/test | sed 's#^\./##' | xargs grep -l 'FormType="ORDINARY\|ФормыКлиентскогоПриложения\| ordinary' 2>/dev/null | head -20 | while read -r f; do
  echo "--- $f"
  rg -n -C2 'FormType="ORDINARY|Ordinary|ФормыКлиентскогоПриложения|Document1|ФормаДокумента|ПриЗаписиНаСервере' "$f" || true
done

echo
echo "== Tests for ordinary form module handler roles =="
python3 - <<'PY'
from pathlib import Path
import re
src_tests = Path('src/test/java')
matches=[]
for p in src_tests.rglob('*.java'):
    txt=p.read_text()
    if 'FormHandlerRoleIndex' in txt and 'FormModule' not in str(p):
        continue
    if 'handlerRolesAreTakenFromTheFormItself' in txt or 'formHandlerRoleIndex' in txt.lower():
        matches.append(str(p))
print('\n'.join(matches))
for m in matches:
    txt=Path(m).read_text()
    print(f'--- {m}')
    print('FormModule tests:', txt.count('void ') if 'FormModule' in str(m) else 0)
    print('roleOf ordinary/module keywords:', bool(re.search(r'Ordinary|ordinary|module', txt)))
PY

Repository: 1c-syntax/bsl-language-server

Length of output: 4003


Register handler roles under the ordinary form module type as well.

FormHandlerRoleIndex.register( stores roles under formRef, but an ordinary form module resolves its owner as Module.bsl (модуль), while registerModuleType stores that module type without the suffix. roleOf() then misses every handler declared for an ordinary form; add the module type to this lookup path or register the same roles there. The role lookup test uses a managed form, so it does not cover ordinary form modules.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.java`
at line 255, Update the registration flow containing
FormHandlerRoleIndex.register and register the collected handler roles under the
ordinary form module type key as well as formRef, matching the unsuffixed key
used by registerModuleType. Preserve the existing managed-form registration and
ensure roleOf() can resolve handlers declared in ordinary forms.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Подтверждаю. EventHandlerResolver.resolveOwnerType для модуля формы резолвит moduleTypeQualifiedName, а у обычной формы это имя с суффиксом (модуль) — под именем формы роли действительно не находились. Регистрирую те же роли и под модульным типом.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@sfaqer, confirmed. Registering the same handler roles under the ordinary form module type will align FormHandlerRoleIndex.roleOf() with EventHandlerResolver.resolveOwnerType.

Please include a regression test for an ordinary form module. The test should verify that roleOf() resolves a handler registered in Form.xml through moduleTypeQualifiedName(form).

You are interacting with an AI system.

sfaqer and others added 5 commits August 1, 2026 20:07
Неиспользуемые импорты, повисшие после разрезания провайдера javadoc-блоки,
константы выше полей, явные типы у параметров лямбды, именованная константа вместо
индекса аргумента и перенос строки длиннее 140 символов.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- модуль формы сбрасывает memo членов при повторной регистрации: источник читает
  символьное дерево лениво, и после rebuild в модуле оставались экспортные методы и
  переменные предыдущей редакции;
- роли обработчиков обычной формы регистрируются и под её модульным типом — именно
  его резолвит EventHandlerResolver, под именем формы они были не видны;
- карты регистраторов стали конкурентными: заполняются на регистрации конфигурации,
  читаются позже из ленивых источников на потоках запросов;
- у дерева данных формы объявлен `ПолучитьЭлементы` вместе с типом коллекции строк —
  без него обход `Для Каждого Строка Из Дерево.ПолучитьЭлементы()` оставался без типа;
- `Тип(…)` со сломанным разбором больше не разыменовывает пустое имя вызова;
- поправлены контракт `@return` у `extensionTypeNames` и владелец
  `registerTabularSectionData` в карте подсистемы.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`build (25, ubuntu-latest)` шесть раз подряд падал `OutOfMemoryError: Java heap space`
в `ClassGraphCreator` — ArchUnit строит граф всех классов проекта, а на CI все 650+
тестовых классов идут в одном форке, и к моменту импорта куча уже занята
перезагруженными Spring-контекстами. Запас в 3 ГБ, заявленный в комментарии рядом,
кончился.

У раннера 16 ГБ и один форк, поэтому на CI ставим 4 ГБ. Локально форков до четырёх —
там остаётся 3 ГБ, иначе на машине с 16 ГБ четыре форка не влезут.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Мёртвая проверка на null у параметра @NullMarked-пакета, константы выше полей,
объявления ближе к использованию, регистрация форм объекта отдельным методом вместо
цепочки if/else-if, отступ и лог вместо проглоченного исключения.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…рана

Пакет дерева выражений помечен @NullMarked, MethodCallNode.getName() объявлен
непустым, и соседний GuardConditionNarrowing разыменовывает его без защиты. Sonar
справедливо считал добавленную проверку мёртвым кодом (java:S2583). Если контракт
неверен, помечать @nullable надо само поле MethodCallNode — правка одного места
вызова этого не решает.

Заодно разгружен collectElementRoles: разбор ролей самого элемента вынесен из цикла
обхода вложенных.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Aug 1, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants