Skip to content

perf(types): резолв членов по терминалу вместо повторного спуска по AST#4250

Merged
nixel2007 merged 4 commits into
developfrom
claude/perf-terminal-based-type-resolution
Jul 10, 2026
Merged

perf(types): резолв членов по терминалу вместо повторного спуска по AST#4250
nixel2007 merged 4 commits into
developfrom
claude/perf-terminal-based-type-resolution

Conversation

@nixel2007

@nixel2007 nixel2007 commented Jul 9, 2026

Copy link
Copy Markdown
Member

Описание

Резолюция «член в позиции» (TypeService.membersAt/memberAt/unknownMemberReceiverAt/isUnknownGlobalAt, DereferenceMemberMatcher, ExpressionAtPosition) принимала Position и заново спускалась от корня AST через Trees.findTerminalNodeContainsPosition(ast, position) — это O(размер дерева) на каждый вызов. Но все вызывающие (диагностики, инференсер) уже держат под рукой TerminalNode того самого идентификатора.

Что стало — добавлены overload-сигнатуры по TerminalNode:

  • TypeService: membersAt(doc, TerminalNode), memberAt(doc, TerminalNode), unknownMemberReceiverAt(doc, TerminalNode), isUnknownGlobalAt(doc, TerminalNode);
  • DereferenceMemberMatcher: matchAt(terminal, doc), receiverTypesAt(doc, terminal), findDereferenceTree(terminal) и matchWithReceiverAt (инферит ресивер один раз, отдаёт MemberMatch(members, receiverTypes));
  • ExpressionAtPosition: enclosingRule(TerminalNode, ruleIndex) / findExpressionTree(TerminalNode) — подъём вверх от известного терминала (O(глубина)) вместо спуска от корня.

Вызывающие переведены на терминал: UnknownMemberDiagnostic (methodName.IDENTIFIER() / accessProperty.IDENTIFIER()), AssignToReadOnlyPropertyDiagnostic, DeprecatedMethodCall/PlatformMemberCalls. Позиционные сигнатуры сохранены и делегируют через терминал (обратная совместимость).

Дополнительно две смежные правки в горячем пути платформенных диагностик:

  • DeprecatedMethodCallDiagnostic — дедуп: PlatformMemberCalls.collect() вызывается один раз, List<TypedMember> переиспользуется в checkPlatformMembers/checkDeletedPrefixMembers (раньше сбор шёл дважды).
  • PlatformMemberCalls — три прохода findAllRuleNodes (globalMethodCall / methodCall / accessProperty) слиты в один findAllRuleNodes(ast, RULE_globalMethodCall, RULE_methodCall, RULE_accessProperty) с диспетчером collectSite.

Зачем

findTerminalNodeContainsPosition(ast, position) — спуск от корня стоимостью в размер дерева; на большом модуле это доминирующая линейная стоимость каждого резолва члена. Терминал у вызывающего уже есть — спуск лишний.

Замеры

Нагрузка — DeprecatedMethodCall по общему модулю УправлениеДоступомСлужебный из SSL (~48k строк); чистый A/B в одной JVM:

  • DeprecatedMethodCall: 4285 мс → 363 мс = ×11.8 (эффект дедупа сбора + единого прохода + резолва по терминалу), число срабатываний неизменно.

Терминальные overload'ы — фундамент для остальных PR серии (инференс-кэш и line-индексы снимаются уже поверх них).

Связанные задачи

Closes

Чеклист

Общие

  • Ветка PR обновлена из develop (ветка создана от актуального develop)
  • Отладочные, закомментированные и прочие, не имеющие смысла участки кода удалены
  • Изменения покрыты тестами (существующие DeprecatedMethodCall/UnknownMember/AssignToReadOnlyProperty/inlay-hint тесты — парити результатов; PlatformMethodCallInlayHintCollectorUnitTest поправлен под новую сигнатуру)
  • Обязательные действия перед коммитом выполнены (gradlew precommit) — прогнаны затронутые тесты; полный precommit за мейнтейнерами

Дополнительно

Часть серии независимых перф-правок, снятых по цепочке CPU-профилей одной диагностики на большом файле. Другие PR серии: мемоизация инференса выражений, индекс объявлений символов, индекс вхождений по строке.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BSiRGLm633B4EmvG3vkk4V


Generated by Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved member resolution across diagnostics, reducing missed or inconsistent warnings when checking properties, calls, and unknown members.
    • Updated some checks to use the selected code token directly, which should make results more accurate around the cursor.
    • Streamlined platform call analysis so related diagnostics reuse the same lookup results, which may improve responsiveness.

claude added 4 commits July 9, 2026 21:31
DeprecatedMethodCall собирал платформенные члены модуля дважды за один
check() — независимо в checkPlatformMembers и checkDeletedPrefixMembers,
удваивая обход AST и резолв членов. Теперь список собирается один раз в
check() и передаётся обеим проверкам.

Дополнительно PlatformMemberCalls передаёт уже известный из обхода AST
TerminalNode в новую перегрузку TypeService.membersAt(doc, terminal,
position), минуя повторный полный спуск по дереву
(findTerminalNodeContainsPosition) ради поиска терминала по позиции.

CPU-профиль (JFR) на модуле SSL УправлениеДоступомСлужебный (~48k строк):
4285 мс → 2017 мс на check() (×2.12). Поведение не меняется —
существующие тесты диагностик и TypeService зелёные.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01BSiRGLm633B4EmvG3vkk4V
…scent

matchAt/receiverTypesAt принимали позицию и заново спускались по AST от
корня, чтобы найти терминал, который вызывающий уже держал на руках, —
до четырёх полных обходов дерева на один идентификатор (по обходу на
каждую продукцию-кандидат внутри findExpressionTree). Проводим известный
TerminalNode по цепочке matchAt -> findDereferenceTree ->
ExpressionAtPosition и поднимаемся вверх от терминала вместо спуска.

findExpressionTree(doc, position) теперь тоже резолвит терминал по позиции
один раз и переиспользует его для всех четырёх продукций — выигрыш
достаётся и hover/completion/signature help.

CPU-профиль (JFR) на модуле SSL УправлениеДоступомСлужебный (~48k строк):
спуск identifierTerminalAt 88.7% -> 0%, matchAt 83.8% -> 8.6%; суммарно с
предыдущей правкой 4285 мс -> 578 мс на check() (×7.4 к baseline, ×3.5 к
прошлому коммиту). Поведение не меняется — 1465 тестов
types/провайдеров/диагностик зелёные.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01BSiRGLm633B4EmvG3vkk4V
PlatformMemberCalls.collect делал три отдельных findAllRuleNodes
(globalMethodCall, methodCall, accessProperty) — три полных обхода AST на
модуль. Объединяем в один обход по трём rule-index с диспетчеризацией по
виду продукции (collectSite). Множество узлов и порядок резолва в пределах
сайта не меняются.

CPU-профиль (JFR) на модуле SSL УправлениеДоступомСлужебный (~48k строк):
findAllRuleNodes 57% -> 30%; суммарно с предыдущими правками
4285 мс -> 363 мс на check() (×11.8 к baseline, ×1.6 к прошлому коммиту).
Поведение не меняется — тесты диагностик и PlatformMemberCalls зелёные.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01BSiRGLm633B4EmvG3vkk4V
…r once

UnknownMember и AssignToReadOnlyProperty держат терминал-идентификатор на
руках из обхода AST, но звали позиционные точки входа TypeService
(unknownMemberReceiverAt/isUnknownGlobalAt/memberAt), которые заново
спускались по дереву от корня к позиции. Добавлены терминальные перегрузки
(позиция для остаточных позиционных API — findReference, fallback висячей
точки — берётся из терминала через Ranges.create).

Дополнительно unknownMemberReceiverAt инферил тип ресивера дважды (membersAt
матчит члены, потом receiverTypesAt инферит тот же left повторно). Введён
DereferenceMemberMatcher.matchWithReceiverAt — один инференс отдаёт и члены,
и типы ресивера.

Замер (последовательный прогон всех диагностик по SSL
УправлениеДоступомСлужебный, ~48k строк): UnknownMember 66.7 -> ~50 c
(×1.34; это правило инференс-bound и activatedByDefault=false),
AssignToReadOnlyProperty 1.61 -> ~1.3 c. Поведение не меняется — тесты
types/провайдеров/диагностик зелёные.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01BSiRGLm633B4EmvG3vkk4V
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3a7497e9-94c8-4a9a-a6af-5a9989052ff5

📥 Commits

Reviewing files that changed from the base of the PR and between 164fd7f and e1bb80c.

📒 Files selected for processing (8)
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AssignToReadOnlyPropertyDiagnostic.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/DeprecatedMethodCallDiagnostic.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnknownMemberDiagnostic.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/platform/PlatformMemberCalls.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/DereferenceMemberMatcher.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/TypeService.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/ExpressionAtPosition.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/inlayhints/PlatformMethodCallInlayHintCollectorUnitTest.java

📝 Walkthrough

Walkthrough

The change refactors member and expression resolution to use Antlr terminal nodes directly, adds terminal-based TypeService APIs, consolidates platform-call traversal, reuses collected results in deprecation checks, and updates diagnostics and Mockito stubs.

Changes

Terminal-based member resolution

Layer / File(s) Summary
Expression and dereference resolution
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/ExpressionAtPosition.java, src/main/java/com/github/_1c_syntax/bsl/languageserver/types/DereferenceMemberMatcher.java
Expression trees and dereference matching now resolve from TerminalNode values, with combined member and receiver inference.
TypeService terminal APIs
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/TypeService.java
Terminal-based overloads resolve members, unknown receivers, and unknown globals while position-based methods delegate through terminals.
Platform collection and diagnostics
src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/platform/PlatformMemberCalls.java, src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/*, src/test/java/com/github/_1c_syntax/bsl/languageserver/inlayhints/PlatformMethodCallInlayHintCollectorUnitTest.java
Platform calls use one traversal, deprecation checks reuse collected members, diagnostics pass identifiers directly, and affected Mockito matchers require Position.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Diagnostic
  participant TypeService
  participant PlatformMemberCalls
  participant DereferenceMemberMatcher
  participant ExpressionAtPosition
  Diagnostic->>PlatformMemberCalls: collect call sites
  PlatformMemberCalls->>TypeService: resolve identifier TerminalNode
  TypeService->>DereferenceMemberMatcher: match terminal
  DereferenceMemberMatcher->>ExpressionAtPosition: find expression tree
  ExpressionAtPosition-->>DereferenceMemberMatcher: expression tree
  DereferenceMemberMatcher-->>TypeService: matched members
  TypeService-->>PlatformMemberCalls: typed members
  PlatformMemberCalls-->>Diagnostic: collected platform members
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Название точно отражает основное изменение: перевод резолва членов на TerminalNode вместо повторного обхода AST.
Docstring Coverage ✅ Passed Docstring coverage is 86.67% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/perf-terminal-based-type-resolution

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

❤️ Share

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

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Test Results

 3 588 files   3 588 suites   1h 45m 10s ⏱️
 3 557 tests  3 539 ✅  18 💤 0 ❌
21 342 runs  21 230 ✅ 112 💤 0 ❌

Results for commit e1bb80c.

♻️ This comment has been updated with latest results.

@sonarqubecloud

sonarqubecloud Bot commented Jul 9, 2026

Copy link
Copy Markdown

@nixel2007
nixel2007 merged commit cd19f2b into develop Jul 10, 2026
42 checks passed
@nixel2007
nixel2007 deleted the claude/perf-terminal-based-type-resolution branch July 10, 2026 07:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants