Типы форм конфигурации: реквизиты, элементы, параметры и обработчики событий - #4337
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughChangesThe 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
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
|
Перебазируй поверх девелопа, пожалуйста. |
|
И сонар грустит |
Ну, пока в работе, ага. |
fbcea56 to
a9941a2
Compare
e524326 to
d892be8
Compare
d892be8 to
31ea27b
Compare
33bb4cc to
1538835
Compare
Каждая форма получает собственный тип: реквизиты (включая колонки таблиц значений и зеркала табличных частей), элементы, параметры, команды и расширение по основному реквизиту. Обработчики событий из 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>
…артами `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>
1538835 to
77881e5
Compare
…яются В синтакс-помощнике блок «Тип» есть не у всякого свойства — по всей платформе таких под две сотни. У элементов формы из-за этого обрывалась цепочка: `Элементы.Таблица.АвтоОтметкаНезаполненного` не показывало даже того, что это Булево. Тип берётся оттуда, где его называет сама платформа: из описания свойства либо из объявления одноимённого свойства другого типа. Доопределяется только тип — описание, режим доступа и версии остаются платформенными. 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>
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
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 winRemove 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 valueRename
PATH_TO_RECORDERS.The constant points to
src/test/resources/metadata/ordinaryForms, but the name states "recorders".OrdinaryFormBasisHbkTest.javaline 56 names the same pathPATH_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 winGuard the caret computation.
Line 113 uses
content.indexOf(';', rhsStart)without checking the result. If the statement has no;,indexOfreturns-1,lastIndexOf('.', -1)also returns-1, andcaretbecomes0. 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 withassignedVar, 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 winLocate these positions from the fixture text.
Lines 76 and 83 hardcode
Position(5, 64)andPosition(3, 8). Any edit toCommonModules/Модуль1/Ext/Module.bslshifts these coordinates, and the tests then check the wrong expression. The class already resolves positions from the content intypesAtRhs. 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 valueName the
-1argument.The literal
-1inplatformMemberHoverBuilder.build(formRef, parameters, -1)does not state its meaning. Extract it to a named constant, for exampleNO_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 valueReduce 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 winAssert 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 throwNoSuchElementExceptionwith no indication of which member or type was involved. The shared root cause is a missing emptiness assertion onrefs().
src/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersHbkTest.java#L454-L459: add an assertion thatparameters.returnTypes().refs()is not empty inparametersOfbeforeiterator().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 assertsrefs()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 winFail with a message instead of returning
null.
findreturnsnullwhen 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 aNullPointerExceptionwith 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 winExtract 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 exampleobjectDataType(String formTypeName), and a second helper for theТабличнаяЧасть1lookup.🤖 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 valueRestore the removed module type after the test.
Line 105 removes the cached module type for
CATALOG_FORM_MODULEfrom the sharedGlobalScopeProvider. 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 usesCATALOG_FORM_MODULEwould then depend on execution order. Consider restoring the entry in an@AfterEachor 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 valueReuse
TestUtils.PATH_TO_METADATA.
TypeProvenanceTestand nearby registry tests use the same designer metadata fixture; importTestUtils.PATH_TO_METADATAhere and remove the local duplicate, keeping fixture paths inTestUtils.javaas 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 winRemove the unused import.
MultiLanguageStringis 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 winRemove the three unused imports.
Placeholder,MemberKind, andObjectFormare 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 valueDrop the dead null check.
formNameis a non-null parameter, soformName == nullis 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 winRemove the same-package imports.
FormKindandTableDataKindare incom.github._1c_syntax.bsl.languageserver.types.registry, the package of this class. The imports are redundant.TableDataKindalso 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 winRemove 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
FormItemTypesRegistrarandFormParametersRegistrar. 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 valueCall the static helper on the class.
attributeTypesByNameisstaticinFormItemTypesRegistrar. The call goes through the instanceformItemTypes. SonarCloud reports it. UseFormItemTypesRegistrar.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 valueConsider rejecting a self-extension.
copyMembersregisters a lazyMemberSourcethat callsgetMembers(source, fileType). If a caller passes the same ref astargetandsource, 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 forexpandedMembers. A cheap identity guard makesregisterExtensionsafe 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 valueState the repeat-registration semantics of
registerOpenStructure.
registerOpenStructureusesput, so a second call for the samerefreplaces the recorded base type. The neighboring indexes in this class useputIfAbsentand 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 winDeclare
signaturesfor the methods that take parameters.
НайтиПоИдентификатору,НайтиСтрокиandВыгрузитьare declared without asignaturesblock, 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 declaressignatures. 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 winDetached 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 toneutral(String)at line 365.src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TableDataKind.java#L141-L167: move the block that documentsattributeTypeRu/nesteddown toof(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
⛔ Files ignored due to path filters (27)
src/test/resources/metadata/designer/Documents/Документ1.xmlis excluded by!src/test/resources/**src/test/resources/metadata/designer/Documents/Документ1/Forms/ФормаДокумента/Ext/Form.xmlis excluded by!src/test/resources/**src/test/resources/metadata/designer/InformationRegisters/РегистрСведений1.xmlis excluded by!src/test/resources/**src/test/resources/metadata/designer/InformationRegisters/РегистрСведений1/Forms/ФормаЗаписи.xmlis excluded by!src/test/resources/**src/test/resources/metadata/designer/InformationRegisters/РегистрСведений1/Forms/ФормаЗаписи/Ext/Form.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/AccountingRegisters/РегистрБухгалтерии1.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/CalculationRegisters/РегистрРасчета1.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/CalculationRegisters/РегистрРасчета1/Forms/ФормаСписка.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/Catalogs/Справочник1.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/Catalogs/Справочник1/Forms/ФормаВыбора.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/Catalogs/Справочник1/Forms/ФормаСписка.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/Catalogs/Справочник1/Forms/ФормаЭлемента.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/Catalogs/Справочник2.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/Catalogs/Справочник2/Forms/ФормаСписка.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/Catalogs/Справочник2/Forms/ФормаЭлемента.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/CommonModules/Модуль1.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/CommonModules/Модуль1/Ext/Module.bslis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/Configuration.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/DocumentJournals/ЖурналДокументов1.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/DocumentJournals/ЖурналДокументов1/Forms/ФормаСписка.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/DocumentJournals/ЖурналДокументов2.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/DocumentJournals/ЖурналДокументов2/Forms/ФормаСписка.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/Documents/Документ1.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/InformationRegisters/РегистрСведений1.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/InformationRegisters/РегистрСведений1/Forms/ФормаЗаписи.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/InformationRegisters/РегистрСведений1/Forms/ФормаСписка.xmlis excluded by!src/test/resources/**src/test/resources/metadata/ordinaryForms/Languages/Русский.xmlis excluded by!src/test/resources/**
📒 Files selected for processing (34)
src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/PlatformMemberHoverBuilder.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/CLAUDE.mdsrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/index/AssignmentByReceiverIndex.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/ExpressionTypeInferencer.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/FormExpressionInference.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/BslContextPlatformTypesProvider.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ConfigurationModuleMembersProvider.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ConfigurationTypesProvider.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/EventHandlerResolver.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormAttributeTypeIndex.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormByNameResolver.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormDataKind.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormDataTypesRegistrar.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormHandlerRoleIndex.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormItemTypesRegistrar.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormKind.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersRegistrar.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersResolver.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormPlatformTypes.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypeFactory.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProvider.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/RegisterFamilies.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TableDataKind.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeRegistry.javasrc/main/resources/com/github/_1c_syntax/bsl/languageserver/types/registry/builtin-platform-types.jsonsrc/test/java/com/github/_1c_syntax/bsl/languageserver/types/FormModuleInferenceTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ConfigurationTypesProviderHelpersTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormModuleSelfTypeTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormParametersHbkTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/FormTypesProviderTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ManagerCallInferenceTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/OrdinaryFormBasisHbkTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/OrdinaryFormParametersTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeProvenanceTest.java
| // Роли считаются сразу: имена дешевле членов (в реестр не ходим), а знать, кем | ||
| // объявлен обработчик, нужно снаружи системы типов — стандартным областям модуля | ||
| // и hover'у. | ||
| formHandlerRoleIndex.register(formRef, collectHandlerRoles(data)); |
There was a problem hiding this comment.
🎯 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}')
PYRepository: 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)))
PYRepository: 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.
There was a problem hiding this comment.
Подтверждаю. EventHandlerResolver.resolveOwnerType для модуля формы резолвит moduleTypeQualifiedName, а у обычной формы это имя с суффиксом (модуль) — под именем формы роли действительно не находились. Регистрирую те же роли и под модульным типом.
There was a problem hiding this comment.
@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.
Неиспользуемые импорты, повисшие после разрезания провайдера 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>
|



Что даёт
Каждая форма конфигурации получает собственный тип — тот, что в модуле формы стоит
за
ЭтотОбъект/ЭтаФормаи за неквалифицированными именами реквизитов и элементов.Из этого следует:
Form.xml, включая колонки реквизитов-таблицзначений и зеркала табличных частей основного реквизита (
Объект.Товары);Элементы.ПолеНаименование) получают платформенный тип по своемувиду вместе с расширением (
ПолеФормы+Расширение поля формы для поля ввода);Расширение формы клиентского приложения для документаи т.п.;Параметры.Ключ) разворачиваются из синтакс-помощника — общиедля любой формы и специфичные для вида основных данных;
Команды.ЗаполнитьПоОснованию) лежат в своей коллекции, а процедураиз
<Action>считается обработчиком;Form.xmlсвязываются с процедурами модуля формы, поэтомуих параметры получают типы из контракта события платформы. Обработчики элементов
(
…ПриИзменении,…Нажатие) — тоже: контракт им ищется на типе элемента;ОткрытьФорму("Справочник.Х.Форма.ФормаЭлемента")резолвится в тип конкретнойформы — и по точному имени, и по имени основной формы объекта, на обоих языках.
Отдельно про основание: тип у этого параметра платформа не объявляет вовсе, поэтому
он берётся из
ВводитсяНаОснованиивладельца формы, а если объект ни на чём не вводится —Неопределено.Обычные формы поддержаны тоже: у них нет собственной модели содержимого, поэтому тип
берётся по роли формы у владельца, а объектный контекст инжектится в модуль.
Как устроено
FormTypesProviderFormPlatformTypesРасширение*сопоставлены, остальные — с объяснением, почему нетFormByNameResolverОткрытьФорму/ПолучитьФормуFormParametersResolverContextType.formParameters()EventHandlerResolverFormExpressionInferenceExpressionTypeInferencerAssignmentByReceiverIndexCallStatementByReceiverIndex: вид элемента, созданного в коде, задаётся присваиваниемЭлемент.Вид = …Плюс фолбэк в
builtin-platform-types.json(187 членов) — без синтакс-помощника формавсё равно знает
Элементы,Команды,Параметрыи контракты своих событий.Почему драфт
Сюда попал
Владелецподчинённого справочника (отдельный коммит) — вещьсамостоятельная, вынесу отдельным PR, если так удобнее ревьюить.
Часть возможностей ждёт 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:
develop);К системе типов эти правки не относятся, но опираются на её знание о том, кем объявлен
обработчик, поэтому идут сверху, а не отдельно.
После мержа нижних PR базы вернутся на
develop.Summary by CodeRabbit