refactor(types): глобальная область видимости — члены синтетического типа ГлобальныйКонтекст#4135
Conversation
|
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
ChangesTypeRegistry Bootstrap and Global Context Type
Sequence Diagram(s)sequenceDiagram
participant Client as Caller
participant Provider as Consumer<br/>(e.g., SignatureHelp,<br/>SemanticTokens,<br/>TypeInference)
participant TypeRegistry
participant GlobalScopeProvider
participant GlobalContext as GLOBAL_CONTEXT<br/>Member Source
Client->>Provider: Query global member
Provider->>TypeRegistry: globalMember(name, fileType)
alt first access or epoch invalidated
TypeRegistry->>TypeRegistry: Build GlobalIndex
TypeRegistry->>GlobalContext: Fetch GLOBAL_CONTEXT members
GlobalContext->>GlobalScopeProvider: ensureBootstrapped() [CAS]
alt first bootstrap
GlobalScopeProvider->>TypeRegistry: ensureInitialized()
Note over TypeRegistry: `@PostConstruct` bootstrap() runs
end
GlobalContext-->>TypeRegistry: Members populated
TypeRegistry->>TypeRegistry: Cache index in AtomicReference
end
TypeRegistry-->>Provider: Optional<MemberDescriptor>
Provider->>Provider: Filter by MemberKind
Provider-->>Client: Resolved type/token/signature
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/registry/GlobalScopeProvider.java`:
- Around line 283-304: The bootstrapped flag is being set to true before the
actual initialization occurs, creating a race condition where concurrent threads
can skip the bootstrap step thinking it's already complete. In the
ensureBootstrapped method, move the compareAndSet call to after the
ensureInitialized() call completes, so the flag only gets set once
initialization actually finishes. This ensures other threads waiting to
bootstrap will not proceed until the initialization is genuinely complete.
🪄 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
Run ID: d324bf7d-9fa3-488a-8a45-e0e99c2824b6
📒 Files selected for processing (5)
src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CompareWithBooleanDiagnostic.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/TypeService.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/GlobalScopeProvider.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeRegistry.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/GlobalScopeProviderBootstrapTest.java
💤 Files with no reviewable changes (2)
- src/main/java/com/github/_1c_syntax/bsl/languageserver/types/TypeService.java
- src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CompareWithBooleanDiagnostic.java
Test Results 3 474 files + 6 3 474 suites +6 1h 43m 50s ⏱️ + 8m 14s Results for commit a199f6c. ± Comparison against base commit 6c985d8. This pull request removes 86 and adds 13 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
| * не инжектится и остаётся {@code null} — bootstrap там не нужен. | ||
| */ | ||
| @Autowired(required = false) | ||
| private @Nullable ObjectProvider<TypeRegistry> typeRegistryProvider; |
Развязка связей: кто/зачем/откуда пишет и читает, и как порвать цикл по-настоящемуСогласен, что текущий PR — это перенос «магии» из потребителей в 1. Слои храненияТри workspace-scoped бина:
2. Граф зависимостей (конструкторные рёбра)
То есть цикл целиком существует ради одной вещи: наполнение глобального скоупа — побочный эффект 3. ПисателиBootstrap-time (платформа, статично, без конфигурации) — единственная точка:
Indexing-time (конфигурация/oscript) — пишут в оба бина по событиям индексации:
Важно: писатели конфигурации/oscript опираются на состояние 4. Читатели GSP (по фичам)
Ключевой вывод: bootstrap реально нужен только читателям стора ( 5. Инсайт для развязкиНаполнение платформенного глобального скоупа — чистая функция от 6. Предложение — вариант 3 (push → pull)
Итог графа: Никакого цикла, никакого 7. Риски / на что смотреть
8. Что делать с этим PRВариант 1 здесь — безопасный интерим (зелёный, страж-тест есть). Предлагаю либо переписать эту ветку на вариант 3, либо смержить как промежуточный и сделать вариант 3 отдельным PR. Если ок — берусь за вариант 3 по плану выше. @nixel2007 куда двигаемся — переписать ветку или отдельный PR поверх? |
…gistry Наполнение GlobalScopeProvider платформенным глобальным скоупом — побочный эффект @PostConstruct bootstrap() workspace-scoped TypeRegistry. Чтение GlobalScopeProvider сам этот bootstrap не триггерило, поэтому потребители (инференсер, резолв голых имён, CompareWithBooleanDiagnostic) вынуждены были вручную дёргать typeRegistry.resolve("") ради побочного эффекта — неявная связанность, которую легко забыть в новом потребителе (тихий пустой скоуп в свежем workspace-scope, не ловится под @SpringBootTest). Вариант 1 из issue: GlobalScopeProvider.ensureBootstrapped() в начале read-методов (findGlobal, getGlobalContexts) лениво материализует TypeRegistry через ObjectProvider (разрывает конструкторный цикл). TypeRegistry — scoped proxy, поэтому его target/bootstrap создаётся только при вызове МЕТОДА: добавлен явный самодокументированный TypeRegistry.ensureInitialized() вместо загадочного resolve(""). Все три ручных resolve("") у потребителей удалены. Red-тест: чтение GlobalScopeProvider в свежем workspace-scope (без ручного bootstrap) теперь само находит платформенный класс. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2c70d42 to
5f39be3
Compare
Согласованный целевой дизайн (зафиксировано)Глобальная область перестаёт быть отдельным push-наполняемым стором. Моделируется как члены синтетического типа Сущности и куда едут:
Разрешение голого имени в глобальной области = Конфиг/oscript: общие модули и library-модули — те же свойства-члены контекста ( Направление зависимостей: namespace/scope → План (пофазно, каждая фаза = коммит с тестами-стражами)
Текущий вариант-1-коммит в этой ветке заменяется новым дизайном (rebase/переписывание ветки). |
Первый шаг развязки глобальной области (issue #3994): глобальная область моделируется как члены синтетического типа TypeRegistry.GLOBAL_CONTEXT. GlobalContextTypesProvider — composer: читает источник (bsl-context либо встроенный JSON) и собирает члены GLOBAL_CONTEXT (глобальные методы/свойства, системные перечисления как свойства-члены с valueType = сам тип). registerPack штатно регистрирует члены этого типа — реестр типов ничего не эмитит в глобальную область, а конкретный тип (КодировкаТекста) не знает о своём глобальном отражении. Старый push-путь (registerAsGlobalProperty/GlobalScopeProvider) пока живёт параллельно — снос в последующих шагах cutover'а. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…текста Composer наполняет GLOBAL_CONTEXT и в builtin-fallback: функции из builtin-globals.json → методы-члены, переменные → свойства-члены (двуязычное имя из name+alias, сигнатуры/async/metadata сохраняются). bsl-context-путь уже покрывал методы/свойства глобального контекста. Парсинг builtin-globals.json временно переиспользуется через мост GlobalScopeProvider.globalContextMembers — переедет в выделенный loader при схлопывании GSP. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
ConfigurationModuleMembersProvider регистрирует общий модуль ещё и как свойство-член GLOBAL_CONTEXT: единый динамический member-источник пересобирает члены из карты URI→DocumentContext, поэтому добавление/смена модуля отражаются после ближайшей инвалидации members-кэша (бампается на каждом изменении документа), а sourceSymbol всегда берётся из актуального SymbolTree. Старый registerAsGlobalProperty пока сохранён параллельно (снос в шаге E). Тест: общий модуль присутствует среди членов GLOBAL_CONTEXT. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…Контекста Завершает миграцию динамических писателей глобальной области (issue #3994): - ConfigurationTypesProvider: коллекции-namespace (Справочники/Документы) → свойства-члены GLOBAL_CONTEXT (карта пересоздаётся каждый проход — переживает перезагрузку конфигурации без дублей); - OScriptModuleMembersProvider: library-модули OneScript → свойства-члены GLOBAL_CONTEXT для FileType.OS, с дерегистрацией по имени в unregister. Старые registerAsGlobalProperty/registerLibraryModule пока сохранены параллельно (снос в шаге E). Теперь все глобалы (платформа + конфигурация + oscript) присутствуют как члены GLOBAL_CONTEXT — можно мигрировать читателей. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Подготовка к миграции читателей (issue #3994): - globalMember(name, fileType) — резолв безпрефиксного имени в член GLOBAL_CONTEXT через быстрый name-индекс, пересобираемый по membersEpoch; - isEnumType(ref) — классификация типа-значения (enum vs property) для раскраски, на основе сохранённого TypeDecl.isEnum; - isConstructibleTypeName(name, fileType) — ось type-name (Структура для Новый) отдельно от членов GLOBAL_CONTEXT. Направление зависимостей чистое: проекции читаются из TypeRegistry. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeRegistry.java (1)
406-450: 💤 Low valueBenign race in global index caching.
Two concurrent callers may both compute the index when the epoch changes, and one overwrites the other's result. This is functionally correct (both compute the same data for the same epoch) but wastes CPU. Consider using
compareAndSetorupdateAndGetif this hot path sees contention, though the current approach is acceptable for typical usage patterns.🤖 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 406 - 450, The globalMember method has a benign race condition where multiple concurrent threads compute the same GlobalIndex when the epoch changes and all overwrite each other's result via the unconditional globalIndexRef.set() call. Replace the set() call with compareAndSet() to ensure only the first computed GlobalIndex is stored, or alternatively use updateAndGet() to perform the epoch check and index computation atomically in a single operation, eliminating wasted CPU from redundant calculations while maintaining functional correctness.
🤖 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.
Nitpick comments:
In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeRegistry.java`:
- Around line 406-450: The globalMember method has a benign race condition where
multiple concurrent threads compute the same GlobalIndex when the epoch changes
and all overwrite each other's result via the unconditional globalIndexRef.set()
call. Replace the set() call with compareAndSet() to ensure only the first
computed GlobalIndex is stored, or alternatively use updateAndGet() to perform
the epoch check and index computation atomically in a single operation,
eliminating wasted CPU from redundant calculations while maintaining functional
correctness.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 0a8267bd-0689-4fd5-9132-e236ebb661f5
📒 Files selected for processing (8)
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/oscript/OScriptModuleMembersProvider.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/GlobalContextTypesProvider.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/GlobalScopeProvider.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/TypeRegistry.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/ConfigurationModuleMembersProviderTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/types/registry/GlobalContextMembersTest.java
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main/java/com/github/_1c_syntax/bsl/languageserver/types/registry/GlobalContextTypesProvider.java
…GLOBAL_CONTEXT Миграция читателей (issue #3994), часть 1: - ExpressionTypeInferencer: bare-идентификатор и возвращаемый тип глобальной функции — через typeRegistry.globalMember (PROPERTY → valueType, METHOD → returnTypes), вместо findGlobalEntry/findFunction; - GlobalScopeSemanticTokensSupplier: 4-сторонняя раскраска выводится из типа-значения члена — isEnumType → Enum, модульный тип (URI-индекс) → Namespace, иначе → Class+DefaultLibrary; убран SyntheticKind-switch и isCommonModuleBacked. Старый путь (GSP) ещё используется остальными читателями — мигрируются следом. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…з GLOBAL_CONTEXT Миграция читателей (issue #3994), часть 2: - PlatformGlobalMethodSemanticTokensSupplier: глоб-функция → globalMember(METHOD); - PlatformMemberPropertyAccessSemanticTokensSupplier: база цепочки → globalMember(PROPERTY); - SignatureHelpProvider: fallback глоб-функции → globalMember(METHOD); - TypeService.resolveBareName: голое имя → globalMember (METHOD/PROPERTY), убраны findFunction/findGlobalEntry и SyntheticKind/GlobalSymbolScope-импорты. Остался один читатель — CompletionProvider (list-проекции глобалов). Затем снос старого пути и схлопывание GSP. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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/semantictokens/GlobalScopeSemanticTokensSupplier.java`:
- Around line 123-131: The valueType assignment in the stream operation at the
beginning of the conditional block does not filter out UNKNOWN types before
selecting the first element. If TypeRef.UNKNOWN appears first in the stream, it
will be selected and cause misclassification of the semantic token. Add a filter
to the stream chain to exclude UNKNOWN types before calling findFirst() on
member.get().returnTypes().refs().stream() to ensure a concrete type is selected
when available.
In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/ExpressionTypeInferencer.java`:
- Around line 256-260: The current filter in the return statement of the global
property type resolution only verifies that at least one concrete ref exists,
but returns the complete TypeSet which may contain UNKNOWN values. Modify the
code to filter out UNKNOWN refs from the TypeSet after the filter that checks
for their existence, ensuring that only concrete types are returned. This
prevents UNKNOWN from being leaked into the result even when concrete
global-property types are available. The fix involves transforming the filtered
TypeSet to exclude any refs that equal TypeRef.UNKNOWN before returning it.
In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/types/TypeService.java`:
- Around line 405-409: In the map operation that creates the TypedMember for
global properties, the MemberDescriptor.property call is incorrectly setting the
owner to `ref`. According to the TypedMember contract, global properties must
have owner == null to avoid misclassification. Change the second parameter
passed to MemberDescriptor.property from `ref` to `null` to ensure the owner
field remains null for these global properties.
🪄 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
Run ID: f51c46fe-3ff0-4812-98f0-d234839da4b2
📒 Files selected for processing (6)
src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/SignatureHelpProvider.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/GlobalScopeSemanticTokensSupplier.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/PlatformGlobalMethodSemanticTokensSupplier.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/PlatformMemberPropertyAccessSemanticTokensSupplier.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/TypeService.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/ExpressionTypeInferencer.java
Завершает миграцию читателей (issue #3994): - getGlobalContexts → PROPERTY-члены GLOBAL_CONTEXT; иконка выводится из типа-значения (перечисление→Enum, library-модуль в OS→Module, иначе→Variable); - getFunctions → METHOD-члены GLOBAL_CONTEXT; - findGlobal (дедуп ru/en) → ключ по члену GLOBAL_CONTEXT либо resolve() для имён типов; - resolveCompletionItem → globalMember(METHOD). getClasses/getKeywords/getConfigurationQualifiedNames остаются собственными данными GlobalScopeProvider (грузятся в конструкторе, не push-путь). Теперь у GlobalSymbolScope-методов GSP не осталось читателей — снос в шаге E. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Последний читатель глобальной области (issue #3994): MCP-инструмент global_member_info теперь использует typeRegistry.globalMember + isEnumType вместо findFunction/findGlobalProperty/findGlobalEnum/findGlobalEntry. Канон-имя и описание берутся из члена напрямую. Все читатели глобалов мигрированы — GlobalSymbolScope-методы GSP без читателей. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Снят старый push-путь глобальной области (issue #3994): - registerPackCallables больше не эмитит классы/exposedAsGlobal в GSP; - registerAsGlobalProperty/registerAsPlatformClass удалены из TypeRegistry вместе с зависимостью на GlobalScopeProvider — ребро цикла разорвано; - config/oscript-писатели больше не зовут registerAsGlobalProperty/ registerLibraryModule/registerLibraryClass (всё через члены GLOBAL_CONTEXT); - последний читатель GSP-read API (GlobalMemberInfoTool) переведён на globalMember; - тесты, проверявшие через findGlobalContext/getGlobalContextNames, мигрированы на globalMember/getMembers(GLOBAL_CONTEXT); вариант-1 страж-тест удалён. Направление зависимостей теперь одностороннее: scope/потребители → TypeRegistry. Мёртвый код GSP (findGlobal*/register*/GlobalSymbolScope/ObjectProvider) и exposedAsGlobal на TypeDecl снимаются следующим коммитом. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…-symbol API После миграции всех читателей на GLOBAL_CONTEXT (issue #3994) у GSP-методов глобального символьного фронта не осталось вызовов. Удалены: - findGlobal/findGlobalEntry/findGlobalContext/findGlobalProperty/findGlobalEnum, getGlobalContexts/getGlobalContextNames/getGlobalPropertyNames/getGlobalEnumNames, getFunctions/findFunction; - registerGlobalProperty(×4)/registerPlatformClass/registerLibraryModule/ registerLibraryClass/unregisterLibrary*; - publishGlobals/ensureGlobalsPublished/registerFunctionSymbol/publishPlatformGlobals; - вариант-1: поле ObjectProvider<TypeRegistry> + ensureBootstrapped + флаги bootstrapped/globalsPublished, зависимость на GlobalSymbolScope (ctor-параметр). GSP остался слим-фасадом: классы для `Новый` (getClasses), keyword'ы (getKeywords/findKeyword*), URI-индекс модулей (indexModuleType/moduleTypeByUri), configuration-qualified-имена. Obsolete-тесты register*/find* удалены/обрезаны до валидных (class/keyword) кейсов. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…источника Завершает развязку (issue #3994): «видно в глобальной области» больше не поле нашего типа. exposedAsGlobal удалён из TypeDecl (record + оба конструктора); признак читается из источника там, где собирается глобальный контекст: - BuiltinTypesJsonLoader.globalContextProperties(resource) — читает JSON-флаг exposedAsGlobal и отдаёт свойства-члены GLOBAL_CONTEXT напрямую; - BslContextPlatformTypesProvider — убрана эвристика isExposedAsGlobal; - composer (GlobalContextTypesProvider) берёт exposed-свойства из лоадера. Конкретный тип (КодировкаТекста) больше не знает о своём глобальном отражении; TypeRegistry/TypeDecl чисты от namespace-концепции. Obsolete-тесты флага удалены/обрезаны. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
CI поймал регрессию: GLOBAL_CONTEXT наполнялся только для BSL
(GlobalContextTypesProvider), а OneScript-глобалы (функции/переменные/
перечисления) выпали — резолв глобалов в .os-файлах ломался (hover глоб-функции/
перечисления, global_member_info для OS).
Добавлен GlobalContextOScriptTypesProvider (FileType.OS): члены GLOBAL_CONTEXT из
builtin-oscript-globals.json (функции/переменные) + exposed-перечисления из
builtin-oscript-platform-types.json. Зеркалит BSL-composer; OneScript всегда из
ресурсов (bsl-context не применяется). globalContextDecl переиспользован.
Чинит: HoverProviderTest.hoverOnGlobal{Function,Enum}InOsFile*,
HoverProviderTypeAwareTest.hoverOn{CurrentDate,StrReplace}*, McpToolsTest.
globalMemberInfoAcceptsOscriptFileType. Добавлен страж globalMember(OS).
Refs #3994
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Платформенный глобальный контекст (bsl-context) отдаёт свойства-менеджеры коллекций (Справочники → СправочникиМенеджер, Перечисления → ПеречисленияМенеджер, Документы → ДокументыМенеджер). GlobalContextTypesProvider кладёт их членами GLOBAL_CONTEXT на bootstrap'е — раньше, чем ConfigurationTypesProvider зарегистрирует одноимённые коллекции-namespace конфигурации (с членами-MD-объектами). computeMembers резолвит член GLOBAL_CONTEXT через putIfAbsent по имени (первый источник побеждает), поэтому платформенное свойство — без MD-объектов — затеняло конфигурационную коллекцию: Справочники.<Каталог> и Перечисления.<Перечисление> не резолвились, completion членов менеджера был пуст. Видно только с платформой (HBK), поэтому CI/юнит-тесты этого не ловили. Регистрируем коллекции конфигурации как registerMemberOverride (в начало списка источников): конфигурация выигрывает, т.к. она суперсет (наследует методы менеджера через registerInheritedMembers + добавляет MD-объекты). Red-тест GlobalContextCollectionShadowingTest воспроизводит затенение без платформы (имитирует платформенное свойство, зарегистрированное раньше config). Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Регрессия: пустой completion членов менеджера коллекций/перечислений (с платформой)Нашёл и починил регрессию, которая воспроизводилась только с подключённой платформой (HBK) — поэтому CI и юнит-тесты её не ловили. Симптом
Root causeПлатформенный
Без платформы (CI/тесты/host) у bsl-context этих свойств нет → конфигурация выигрывала → зелено. Фикс
Тест
Валидация гифкамиПерезаписал Коммит: 98f785a. |
Путь membersFromContext (методы/свойства глобального контекста + системные перечисления как свойства-члены GLOBAL_CONTEXT) исполняется только при подключённой платформе (HBK), поэтому не покрывался в CI — крупнейший пробел new-code coverage PR'а и та же зона, где жила регрессия затенения коллекций. Покрываем синтетическим PlatformContextProvider по образцу BslContextPlatformTypesProviderTest (без реальной платформы): метод → метод-член, свойство → свойство-член, top-level ContextEnum → свойство-член с valueType. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
TypeRegistry — хранилище ТИПОВ; резолв глобальных функций/свойств — не его ответственность. Переносим API в GlobalScopeProvider (абстракцию доступа к контексту), TypeRegistry оставляем чистым storage (issue #3994). - GlobalScopeProvider получает globalMember/globalFunction/globalProperty (типизированные аксессоры вместо россыпи globalMember().filter(kind==…)) и эпоха-кэшированный name-индекс; делегирует в typeRegistry.getMembers(GLOBAL_CONTEXT). Направление GlobalScopeProvider → TypeRegistry (read), без цикла. - TypeRegistry.globalMember удалён; добавлен membersEpoch() как ключ инвалидации кэшей потребителей. GLOBAL_CONTEXT (идентичность типа) остаётся на TypeRegistry — он используется композерами как цель регистрации членов. - 11 потребителей (TypeService, ExpressionTypeInferencer, CompletionProvider, SignatureHelpProvider, semantic-сапплаеры, GlobalMemberInfoTool) переключены на globalScopeProvider.global*(); тесты — на GlobalScopeProvider. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
После переноса globalMember в GlobalScopeProvider у сапплаера удалён импорт
TypeRegistry (поле заменено на GlobalScopeProvider), но в javadoc класса осталась
ссылка {@link TypeRegistry#GLOBAL_CONTEXT} — кросс-пакетная, без импорта →
"reference not found", падал таск :javadoc. Сапплаер теперь резолвит глобальную
функцию через GlobalScopeProvider#globalFunction — обновляем ссылку на неё.
Refs #3994
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
ОбщегоНазначения.Знач → экспортный метод модуля (ЗначениеВМассиве). Страж пути, который задел перенос globalMember в GlobalScopeProvider (резолв ресивера-модуля через globalProperty + раскраска). На designer-фикстуре логика completion общих модулей исправна; пустой comp-07 на стенде GIF — следствие неполной индексации большого SSL-конфига, не логики. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
filterNamesByLanguage обслуживал три разные сущности (классы, составные имена конфигурации, кейворды) одним catch-all ключом globalMember?:resolve?:bareKey — причём ветка globalMember для этих вызовов мертва (голых глобал-значений в списках нет), а кейворды всё равно уходили в bareKey (не группируются). Разносим: - filterTypeNamesByLanguage(names, language) — для имён типов (классы для Новый + составные имена MD-объектов): ключ = интернированный TypeRef (resolve), ru/en одного типа группируются, остаётся написание под язык. fileType больше не нужен (resolve по имени, без языка). - кейворды — прямая итерация getKeywords: общей идентичности ru/en у них нет, фильтр был no-op; поведение сохранено, намерение явно в комментарии. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
CompletionProvider перечислял глобальные свойства и функции прямым чтением typeRegistry.getMembers(GLOBAL_CONTEXT) + фильтром по kind — обход абстракции (by-name доступ уже шёл через GlobalScopeProvider). Получалось два способа доступа к глобальной области. Добавляем перечисляющие аналоги by-name аксессоров: - GlobalScopeProvider.globalProperties(fileType) - GlobalScopeProvider.globalFunctions(fileType) Оба цикла completion идут через них. Поле typeRegistry в CompletionProvider остаётся только для resolve(name) и isEnumType(valueType) — запросы к хранилищу ТИПОВ (имя→тип, признак типа), не к глобальной области. Прямых обращений к TypeRegistry.GLOBAL_CONTEXT в потребителях больше нет. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
После переноса глобальной области в члены GLOBAL_CONTEXT синтетик-символы больше не создаются (new SyntheticSymbol отсутствует), а резолв/hover платформенных глобалов идёт через PlatformMemberSymbol (несёт MemberDescriptor) — тот же путь, что и для остальных платформенных членов. Параллельный Symbol-фронт осиротел. Удалено: - SyntheticSymbol, SyntheticKind, GlobalSymbolScope (пустой @Component-бин), SyntheticSymbolMarkupContentBuilder (никогда не диспетчеризовался); - мёртвые ветки instanceof SyntheticSymbol в TypeService.typesAt и ExpressionTypeInferencer (никогда не матчили — таких символов нет); - тесты на удалённые классы; synthetic-методы TypeServiceDelegationTest; - устаревшие javadoc-ссылки на удалённые классы (чинит сборку javadoc). Классификация property-vs-enum у потребителей — из типа-значения (TypeRegistry.isEnumType), как и было после рефактора. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Симметрия с BSL-общими модулями: GLOBAL_CONTEXT(OS)-член library-модуля теперь несёт sourceSymbol (ModuleSymbol) — для навигации/раскраски/hover, как ConfigurationModuleMembersProvider в BSL. libraryModuleGlobals ключуется по URI (а не по имени) и хранит тип + DocumentContext; member пересобирается с withSourceSymbol(doc.getSymbolTree().getModule()) лениво (rebuild-safe). unregister(URI) убирает запись по URI. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
… провайдерах Динамическое членство глобальной области (коллекции, общие/library-модули) хранилось картами прямо в трёх провайдерах (collectionGlobalMembers, commonModuleDocs, libraryModuleGlobals) — дублируя то, что уже есть в TypeRegistry (интернированный ref, а для UserType — declaration-символ), и удерживая DocumentContext сильной ссылкой (анти-паттерн, ср. 325636f). Централизуем в TypeRegistry (как enumTypes): - маркер-множество globalPropertyTypes (per FileType) + опциональный globalPropertySymbols (WeakReference) для типов без собственного declaration (конфигурационные общие модули — ConfigurationType его не несёт); - registerGlobalPropertyType(ref, ft, declaration) / unregisterGlobalPropertyType; - единый override-source на GLOBAL_CONTEXT (per язык, в bootstrap): собирает property(name/bilingual из displayName, value-type=ref, sourceSymbol из UserType.declaration либо globalPropertySymbols). Override сохраняет фикс шадоуинга (config-коллекции перекрывают платформенные свойства). Провайдеры теперь только помечают тип глобальным: - ConfigurationTypesProvider/ConfigurationModuleMembersProvider/ OScriptModuleMembersProvider — registerGlobalPropertyType(...), карты удалены. Символ захватывается eager на DocumentContextContentChangedEvent (после rebuild, как SymbolTypeIndex/WorkspaceSymbolIndex), а getMembers(GLOBAL_CONTEXT) делает лишь WeakReference.get() — без доступа к SymbolTree под чужими локами (раньше ленивый getSymbolTree() в source'е был рискованнее по локам). Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
CodeRabbit (валидные): - TypeService.resolveBareName: owner=null для глобального свойства (контракт TypedMember — глобалы без owner; глоб-функция уже была null); - GlobalScopeSemanticTokensSupplier: фильтр UNKNOWN перед классификацией токена. SonarCloud: - удалены unused-импорты/dead-code: TypeRegistry (LinkedHashSet), GlobalContextTypesProvider (EnAttachments), GlobalScopeProviderBslContextTest (8 импортов + мёртвый method()), GlobalContextTypesProviderTest (MemberDescriptor), ConfigurationTypesProviderHelpersTest (unused globalScope); - GlobalMemberInfoTool.globalValueResult → static; убрана мёртвая проверка description==null (S2589, @nonnull в @NullMarked); - BuiltinTypesJsonLoader.globalContextProperties: один guard-continue + вынос firstAlias (снижение вложенности S134/S135); - GlobalScopeProvider.globalContextMembers: вынос functionMember/variableMember (сложность S3776/S1541), константы RETURN_TYPE_FIELD/ALIASES_FIELD (дубль S1192); - тест-нитпики: lambda→MemberDescriptor::name, объединение assertThat-цепочки. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…раметра Никаких null в публичном API: вместо registerGlobalPropertyType(ref, ft, null) два перегруза — - registerGlobalPropertyType(ref, ft) — без source-символа (коллекции; library-модули OneScript несут declaration в UserType); - registerGlobalPropertyType(ref, ft, declaration) — с явным non-null символом (конфигурационные общие модули, ConfigurationType его не хранит). Вызовы коллекций и library-модулей переведены на 2-арг. Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
- registerGlobalPropertyType и соседние комментарии TypeRegistry больше не называют домены-вызывающие (коллекции, общие/library-модули, bsl-context): хранилище описывается в своих терминах (тип-глобал-свойство, source-символ, override над другими источниками GLOBAL_CONTEXT); - удалены ссылки "issue #3994"/"PR #4135" из javadoc и комментариев (трекинг — в git/PR, не в коде). Refs #3994 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Javadoc описывает «что есть», а не «как было раньше»:
- ensureInitialized: убрано «push-моделью наполняет GlobalScopeProvider»,
ссылка на удалённый ensureBootstrapped и «заменяет прежний resolve("")» —
оставлено описание текущего поведения (материализация scope + bootstrap);
- globalContextMembers: убран «временный мост на время cutover'а»;
- GlobalContextMembersTest: убрана «Фаза 1 рефактора … push-механизм»;
- registerPackCallables: убран комментарий «глобальная видимость больше не
эмитится отсюда».
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…lScopeProvider Константа GLOBAL_CONTEXT больше не public: её видимость пакетная, доступ у потребителей — только через геттеры GlobalScopeProvider (globalFunction/globalProperty/globalProperties/…). Из комментариев потребителей убрано упоминание внутреннего устройства реестра. Заодно вычищены комментарии: убран выдуманный термин «composer» (нет такого типа/интерфейса в bsl-ls) и внешнее знание (стенд GIF), не относящееся к кодовой базе. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…ль-зависимость от TypeRegistry Семь потребителей инжектили одновременно TypeService и TypeRegistry, хотя лезли в реестр лишь за мелочами, которые фасад не реэкспортировал. - В TypeService добавлены делегаты: isEnumType, isVersionedMemberName, hasAnyReadOnlyMember, supportsForEach, supportsIndexAccess, getForEachDescription, getIndexAccessDescription. - CompletionProvider, SignatureHelpProvider, ConstructorHoverBuilder, CollectionHoverHints, AssignToReadOnlyPropertyDiagnostic, PlatformMemberCalls (+ Unavailable/DeprecatedMemberCall) больше не зависят от TypeRegistry — всё через TypeService. - SignatureHelpProvider: удалено мёртвое поле typeRegistry. - PlatformMemberCalls.collect: убран параметр typeRegistry. - CompletionProvider.filterTypeNamesByLanguage резолвит ключ-идентичность через resolve(name, fileType): безфильтровый resolve(name) — внутренний примитив слоя типов и на фасаде не выставляется. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Самописная карта internedRefs (Map<TypeRef,TypeRef> + putIfAbsent) — это ровно GenericInterner<T> из utils; заменено на него. У GenericInterner нет read-API (только intern/clear), поэтому resolve(TypeKind, qualifiedName) больше не может делать чистый lookup по интернеру. Метод перенесён на хранилище types: он возвращает ссылку только для ЗАРЕГИСТРИРОВАННОГО типа (kind-точно), а не для просто интернированного полуфабриката без Type/членов. Прод-вызовов у метода нет; тест обновлён под новый контракт. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
… файла enumTypes, supportsForEach, supportsIndexAccess и их описания (forEach/indexAccessDescriptions) хранились на голом TypeRef без разреза по fileType, хотя члены и описания типа уже per-fileType. Одно и то же имя в BSL и OneScript — разные типы с разной природой, поэтому признак, выставленный источником одного языка, протекал в другой (последний регистратор побеждал). Хранение переведено на Map<FileType, …>; в isEnumType/supportsForEach/ supportsIndexAccess и геттеры описаний добавлен параметр fileType. Рябь проброшена через фасад TypeService и вызывающих (CompletionProvider, GlobalScopeSemanticTokensSupplier, GlobalMemberInfoTool, CollectionHoverHints, ConstructorHoverBuilder) — у всех fileType под рукой. Red-test: TypeRegistryCollectionTraitsPerLanguageTest — признаки, заявленные для BSL, не видны в OS. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…кет @NullMarked Пакет hover помечен @NullMarked, параметры append non-null по контракту, а единственный вызывающий передаёт non-null. Защитная проверка на null противоречила контракту (подразумевала возможность null) — удалена вместе с тестом, дёргавшим append с null (запрещённый контрактом ввод). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…не параметр TypeService прокидывался в append параметром (рудимент от прежней передачи workspace-scoped TypeRegistry). Spring отдаёт scoped-proxy, поэтому TypeService инжектится полем — как уже сделано в ConstructorHoverBuilder. append теперь принимает только (sb, ref, fileType). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…bal и двойной парс JSON-fallback глобальной области строил enum-свойства повторным парсом platform-types.json с фильтром по флагу exposedAsGlobal — это и двойной разбор того же файла, и рассинхрон с платформенным путём (там enum-глобалы выводятся структурно из ContextEnum, без флага). Теперь enum-глобалы выводятся из ENUM-типов уже загруженного пака (BuiltinTypesJsonLoader.enumGlobalProperties), load() мемоизирован по ресурсу — один парс на JVM. globalContextProperties + firstAlias удалены. Данные приведены к источнику (живой движок OneScript + OneScript.StandardLibrary + oscriptStdLib): - 7 XS-типов (ЗавершенностьСхемыXS и пр.) — это системные перечисления (EnumXSSchemaFinal), исправлен kind TYPE→ENUM; - Символы — класс (ТипЗнч=Chars), а не перечисление: kind ENUM→TYPE; его глобальность идёт из builtin-oscript-globals.json/variables; - поле exposedAsGlobal удалено из обоих platform-types.json (больше не читается). Генератор (OneScriptDocumenter/HBK-grabber) должен впредь отдавать Enumeration*/[SystemEnum]-типы как ENUM и не эмитить exposedAsGlobal. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
… Символы Глобальная переменная Символы (класс набора системных символов) не имела поля type → value-type UNKNOWN, обращение Символы.ПС не резолвилось. Задан type "Символы" — значением переменной становится класс Символы, его члены (ПС/ВК/Таб/…) подтягиваются. Red-test: GlobalContextMembersTest.oscriptGlobalVariableCharsResolvesItsMembers. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…адер чистый enumGlobalProperties жил в BuiltinTypesJsonLoader и дублировал enumAsProperty провайдера: сборка членов GLOBAL_CONTEXT — домен провайдера, а лоадер должен лишь парсить JSON в TypeDecl. Маппинг «перечисление → глобальное свойство» сведён в один общий статик GlobalContextTypesProvider.enumGlobalProperties (зовут и BSL-, и OScript-провайдер), переиспользующий enumAsProperty платформенного пути. Типы берутся из мемоизированного load() — без повторного парса. Метод удалён из лоадера. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
- 3 BUG (always-false): убраны мёртвые `if (ref == null)` в registerGlobalPropertyType/unregisterGlobalPropertyType — пакет @NullMarked, параметр non-null по контракту. - FQN: `new java.lang.ref.WeakReference<>` → `WeakReference` (импорт есть). - S1213: LOAD_CACHE перенесён в начало BuiltinTypesJsonLoader (поле до методов); заодно починена битая @link на удалённый enumGlobalProperties. - S125 (FP): переформулирован прозаический комментарий в GlobalScopeProviderBslContextTest, чтобы не выглядел закомментированным кодом. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…ямбды - CompletionProvider.filterTypeNamesByLanguage: Object-ключ (с new Object() для не-типов) заменён на TypeRef-ключ (Comparable); не-типы собираются прямо в результат. Порядок не важен — итоговую сортировку задаёт sortText. - TypeService: явный тип параметра лямбды `(TypeRef ref)`. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|



Проблема (issue #3994)
TypeRegistry(@WorkspaceScope) в@PostConstruct bootstrap()push-моделью наполнял другой бин —GlobalScopeProvider(платформенные классы дляНовый, системные перечисления, глобальные свойства/функции). Потребители читали изGlobalScopeProvider, но его чтение не материализовалоTypeRegistry→ в свежем workspace-scope первый запрос видел пустой скоуп. Костыль: потребители дёргалиtypeRegistry.resolve("")ради побочного эффекта bootstrap.Решение: глобальная область = члены синтетического типа
Глобальная область видимости моделируется как члены синтетического типа
ГлобальныйКонтекствTypeRegistry. Знание «эта сущность видна без префикса» — метаданные источника (bsl-context / встроенный JSON / конфигурация), а не флаг на конкретном типе.GLOBAL_CONTEXTштатнымTypeDecl/registerMemberSource:GlobalContextTypesProvider(BSL) иGlobalContextOScriptTypesProvider(OS) — глобальные функции (методы-члены), свойства, системные перечисления (свойства-члены сvalueType= сам тип);ConfigurationTypesProvider— коллекции-namespace (Справочники,Перечисления…);ConfigurationModuleMembersProvider/OScriptModuleMembersProvider— общие/library-модули.TypeRegistryне эмитит ничего в глобальную область — он лишь хранит тип с именемГлобальныйКонтекст. ЦиклTypeRegistry ↔ GlobalScopeProviderразорван (направление толькоGlobalScopeProvider → TypeRegistry, read).exposedAsGlobalснят сTypeDecl— признак читается из источника при сборкеGLOBAL_CONTEXT. УдаленыregisterAsGlobalProperty/registerAsPlatformClassи мёртвый global-symbol APIGlobalScopeProvider.Доступ к глобальной области — отдельная абстракция
TypeRegistry— хранилище типов; резолв глобальных функций/свойств — не его ответственность. API живёт вGlobalScopeProvider:globalMember(name, ft), типизированныеglobalFunction(...)/globalProperty(...)(вместо россыпиglobalMember().filter(kind==…)у потребителей), плюс перечислениеglobalProperties(ft)/globalFunctions(ft);typeRegistry.getMembers(GLOBAL_CONTEXT), эпоха-кэш черезTypeRegistry.membersEpoch();TypeRegistry.globalMember()удалён. КонстантаGLOBAL_CONTEXT— package-private вTypeRegistry; доступ потребителей только через геттерыGlobalScopeProvider.Сохранённые инварианты
valueTypeчлена (isEnumType), а не из отдельного флага; собственные реквизиты/методы конфигурации не красятся какdefaultLibrary.Новый(Массив,Структура) — отдельная ось (проекция «типы с конструктором»), не члены контекста.TypeRegistry.Исправленный баг шадоуинга коллекций
Платформенный глобальный контекст (bsl-context) сам отдаёт свойства-менеджеры коллекций (
Справочники → СправочникиМенеджер,Перечисления → ПеречисленияМенеджер). Они регистрировались на bootstrap'е раньше одноимённых коллекций конфигурации;computeMembersберёт первый источник (putIfAbsent), и платформенное свойство без MD-объектов затеняло конфигурационную коллекцию →Справочники.<Каталог>/Перечисления.<Перечисление>не резолвились (видно только с платформой/HBK, поэтому CI/юнит-тесты не ловили). Фикс: коллекции конфигурации регистрируются какregisterMemberOverride(в начало списка) — конфигурация выигрывает (суперсет: наследует методы менеджера + MD-объекты).Сопутствующая чистка реестра типов
TypeRegistryиTypeService, хотя лезли в реестр за мелочами. ВTypeServiceдобавлены делегаты (isEnumType,isVersionedMemberName,hasAnyReadOnlyMember,supportsForEach,supportsIndexAccess,getForEachDescription,getIndexAccessDescription); потребители (CompletionProvider,SignatureHelpProvider,ConstructorHoverBuilder,CollectionHoverHints,AssignToReadOnlyPropertyDiagnostic,PlatformMemberCalls+Unavailable/DeprecatedMemberCall) больше не зависят отTypeRegistry. Мёртвое поле вSignatureHelpProviderудалено.Map<TypeRef,TypeRef>заменена наGenericInterner<TypeRef>из utils.enumTypes,supportsForEach,supportsIndexAccessи их описания сидели на голомTypeRefбез разреза поfileType(а члены и описания типа уже per-fileType). Одно и то же имя в BSL и OneScript — разные типы с разной природой, поэтому признак одного языка протекал в другой. Хранение переведено наMap<FileType, …>, в геттеры добавлен параметрfileType. ИдентичностьTypeRefосталась языко-независимой; всё языко-зависимое наполнение типа теперь консистентно per-fileType.Тесты
GlobalContextCollectionShadowingTest— воспроизводит шадоуинг без платформы (red→green).TypeRegistryCollectionTraitsPerLanguageTest— признаки коллекций/перечислений, заявленные для BSL, не видны в OS (red→green).GlobalContextMembersTest,GlobalContextTypesProviderTest(bsl-context-путь через синтетическийPlatformContextProvider),CompletionCommonModuleMembersTest(члены общего модуля), миграция читателей наGlobalScopeProviderи фасадTypeService.Refs #3994