fix(types): названный в описании тип не уносит с собой посчитанные поля - #4447
Conversation
Значение метода складывается из описания и вывода по телу. По общим типам верим описанию: у «Массив из Число» из комментария состав элементов точнее собранного по телу, — и ради этого названный в описании тип вычитался из выведенного. Но вычитание убирало ссылку вместе со ВСЕМИ её декорациями, включая поля. У функции, чьё описание гласит «Возвращаемое значение: Структура», состав ключей, честно собранный из Вставить, пропадал целиком: замер на ssl_3_1 показывает 111 полей в момент сохранения и ноль при чтении. Дальше это оборачивалось ложными «У типа "Структура" нет метода или свойства …» — самой массовой жалобой диагностики на реальной конфигурации. Состав элементов по-прежнему остаётся за описанием, а поля возвращаются. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cu7S3zYn7n6GMsdYf5v1q
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthrough
ChangesReturn type inference
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 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 |
…нивое Первая версия правки ставила соединение описания с выводом на путь чтения, который зовётся при каждом разрешении вызова, и вдобавок читала поля через getLocalFields — а тот склеивает жадные поля с ленивыми, то есть форсирует их. Ленивое поле у рекурсивных и `см.`-типов ведёт обратно в getReturnTypes того же метода, и разворот шёл вглубь на каждом чтении: в прогоне по ssl_3_1 — 212 переполнений стека, проглоченных обработчиком, и катастрофическое время. Теперь соединение считается один раз и снимается записью любого из источников, а сырые карты полей читаются без склейки — ленивое перекладывается ленивым. Резолверы узла рекурсии тоже перестали форсировать: и по полям, и по элементам они читают жадный состав, разрешая ровно один уровень, ради чего узел и заведён. Прогон по ssl_3_1: переполнений стека ноль, время 60 и 71 секунда против 63 и 62 у develop, замечаний 29 220 и 29 024 против 30 235 и 30 334. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cu7S3zYn7n6GMsdYf5v1q
|
Просадку нашёл и переработал в — вы были правы, вливать первую версию было нельзя. Что я сделал не так. Соединение описания с выводом встало на путь чтения: Что изменено:
Замеры на ssl_3_1 (прогоны вперемежку, машина на сети, сканер молчит):
Переполнений стека — ноль. Разница по времени в пределах разброса этой машины; окончательное слово за бенчмарком CI. Отдельно отмечу находку, которая шире этого PR: обработчик |
|
Просадку нашёл и переработал в |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/types/index/SymbolTypeIndex.java`:
- Line 189: Fix concurrent cache publication in reindexDeclared and
putReturnTypes so an outdated reader cannot repopulate combinedReturnTypes after
source updates; use version validation against declared and inferred snapshots
or the same per-method synchronization for source publication and cache
computation. Ensure both interleavings are covered by a barrier-based
concurrency test, preserving correct return types for subsequent reads.
In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/ExpressionTypeInferencer.java`:
- Around line 829-843: Update the field and element guards in the surrounding
inferencer method to read raw maps directly from known.localFields() and
known.elementTypes(), rather than calling getLocalFields(ref) or other accessors
that force lazy values. Preserve the existing one-level LazyTypeSet creation via
withLazyField and withLazyElement, so self-referential fields and elements are
installed before any lazy evaluation occurs.
🪄 Autofix
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: 83f93d6c-85a3-43e0-b255-c0d45c505bd1
📒 Files selected for processing (2)
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/index/SymbolTypeIndex.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/ExpressionTypeInferencer.java
Снятие запомненного при записи ничего не гарантировало: читатель, взявший источники до снятия, укладывал результат уже после него, и устаревшее значение оставалось жить — новых поводов снять его не возникало. Теперь запомненное хранится вместе с источниками, из которых посчитано, и годится, только если оба совпали по ссылке. Наборы неизменяемы, запись кладёт другой объект — этого достаточно, а гонки между записью и чтением нет вовсе. В очистке документа запись снимается по-прежнему, но уже только ради памяти. Заодно перечисление в узле рекурсии перестало форсировать ленивое: имена полей берутся из сырых карт, ленивые поля перекладываются как есть, а состав элементов проверяется по жадной карте. Прежде форс мог развернуть самоссылку ещё до того, как узел будет установлен. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cu7S3zYn7n6GMsdYf5v1q
Сонар показал 69 % на новом коде: непокрытыми оставались перенос ленивых полей при соединении, перекладывание их в узле и тело его резолвера. Три теста бьют именно туда: правка тела обесценивает запомненное, ленивое поле рекурсивной функции переживает соединение с описанием и разрешается на чтении. 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>
|



Проблема
Значение метода складывается из двух источников: типа, названного в описании (
// Возвращаемое значение: …), и типов, выведенных по телу. По общим типам верим описанию — уМассив из Числоиз комментария состав элементов точнее собранного по телу. Ради этого названный в описании тип вычитался из выведенного:Вычитание убирает ссылку целиком — вместе с полями. У функции, чьё описание гласит
Возвращаемое значение: Структура, состав ключей, собранный изВставить, пропадал полностью.Замер на живом коде БСП (
ИнтеграцияПодсистемБСП.СобытияБСП, у которой два с лишним десяткаВставить): 111 полей в момент сохранения и ноль при чтении.Дальше это оборачивалось ложными «У типа "Структура" нет метода или свойства …» — самой массовой жалобой диагностики на реальной конфигурации: 9660 срабатываний из 30 587, почти треть всей выдачи.
Что сделано
Состав элементов по-прежнему остаётся за описанием — правило и тесты на
Массив из Числоне тронуты. А поля возвращаются: после вычитания к результату добавляются поля выведенного значения по тем же ссылкам.Замеры на ssl_3_1
Пакетный анализ, репортер SARIF,
mode: onlyсUnknownMember+EventHandlerInvalidSignature. Правка мерилась в составе большей ветки, где она — единственная, влияющая на состав полей: замечаний 30 401 → 28 859, то есть примерно полторы тысячи ложных срабатываний уходит.Отдельного прогона «develop против develop плюс только эта правка» я не делал: вынесу числа комментарием, если понадобится точная атрибуция.
Тесты
DeclaredStructureFieldsTest: у функции в описании назван типСтруктура, а состав ключей известен из тела; после правки ключи видны. До правки набор полей пуст.Весь пакет
types.*(1706 тестов) и*UnknownMember*— зелёные, включая тестыМассив из Число, ради которых вычитание и существовало.Связанные задачи
Часть работы по #4429.
Summary by CodeRabbit
Bug Fixes
Tests