Skip to content

feat(hover): hover по имени типа в описании метода (BSLDoc) - #4133

Open
nixel2007 wants to merge 2 commits into
developfrom
feature/hover-bsldoc-type-names
Open

feat(hover): hover по имени типа в описании метода (BSLDoc)#4133
nixel2007 wants to merge 2 commits into
developfrom
feature/hover-bsldoc-type-names

Conversation

@nixel2007

@nixel2007 nixel2007 commented Jun 16, 2026

Copy link
Copy Markdown
Member

Что сделано

Реализован hover по имени типа в описании метода (BSLDoc — секции // Параметры: и // Возвращаемое значение:). При наведении на имя типа показывается всплывающая документация этого типа.

closes #3990

Результат проверки текущего поведения

Как и предполагалось в issue — hover по имени типа в описании метода ранее не был реализован вовсе. Проверено эмпирически: ни один из ReferenceFinder не обрабатывал позиции внутри описаний; элементы описания (DescriptionElement с типом TYPE_NAME) использовались только в BslDocSemanticTokensSupplier для подсветки. Hover возвращал пустой результат и для инстанцируемых, и для неинстанцируемых типов.

Ключевой факт для реализации: позиции DescriptionElement — абсолютные координаты в файле (0-based), поэтому сопоставление с курсором идёт напрямую.

Инстанцируемые vs неинстанцируемые

Догадка из issue про «по-разному распознаются» в части резолва для BSL не подтвердилась на уровне реестра типов: и ТаблицаЗначений, и СтрокаТаблицыЗначений/КлючИЗначение присутствуют в builtin-platform-types.json и одинаково резолвятся через TypeService.resolve(...). Поэтому hover работает для обоих видов единообразно (см. тесты).

Важно: hover специально не показывает синтаксис Новый Тип(...) (это hover конструктора, ConstructorHoverBuilder) — для неинстанцируемых типов он был бы бессмысленным. Вместо этого рендерится имя типа + метка «тип» + описание типа.

Реализация

По образцу существующих finder'ов (NewExpressionReferenceFinder → symbol → builder):

  • TypeReferenceSymbol — synthetic-символ с разрешённым TypeRef;
  • DescriptionTypeReferenceFinder (@Order(300), последний) — перебирает описания методов и переменных (включая trailing-описание переменной) — тем же набором, что BslDocSemanticTokensSupplier/CommentSemanticTokensSupplier — находит TYPE_NAME-элемент под курсором и резолвит его в TypeRef. Стоит последним, поэтому на обычном коде не вмешивается;
  • TypeReferenceMarkupContentBuilder — рендерит имя типа, метку «тип»/«type» (ru/en) и описание типа; для коллекций добавляет CollectionHoverHints.

Тесты

HoverOnDescriptionTypeTest (структура given/when/then):

  • инстанцируемый тип (ТаблицаЗначений) в // Параметры:;
  • неинстанцируемый тип (СтрокаТаблицыЗначений) в // Возвращаемое значение:;
  • неизвестный тип → hover отсутствует;
  • позиция на имени параметра (не на типе) → hover отсутствует.

HoverProviderOScriptLibraryTest.hoverOnUserTypeNameInMethodDescriptionResolves — hover по имени пользовательского (OneScript) типа в описании метода резолвится тем же finder'ом.

Открытые вопросы / заметки

  1. Дизайн hover для инстанцируемых типов. Сейчас показывается документация типа (без Новый). Альтернатива — показывать ещё и сигнатуру конструктора. Выбрал «документацию типа», т.к. это соответствует формулировке issue. Готов поменять, если хочется иначе.
  2. Полнота данных по неинстанцируемым типам. Часть упомянутых в issue типов (КолонкаТаблицыЗначений, HTTPОтвет, Поток) сейчас присутствует только в builtin-oscript-platform-types.json, поэтому в .bsl-файлах они не резолвятся и hover по ним не покажется. Это отдельный пробел в данных платформенных типов BSL (не в логике hover) — стоит ли заводить отдельную задачу?
  3. Пользовательские/ссылочные типы и OneScript-библиотеки. Специальной обработки нет — резолвятся тем же typeService.resolve(name, fileType), что и платформенные: финдер перебирает те же TYPE_NAME-элементы, что подсвечивает semantic token supplier, без различения вида типа. Подтверждено тестом на OneScript USER-тип (PublicEntity). Никакой отдельной обработки не требуется. Конфигурационные СправочникСсылка.X резолвятся при загруженной конфигурации тем же путём.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added hover support for type references inside BSL symbol descriptions (including parameter and return sections).
    • Hover now shows localized type information when the cursor is over a type name, with optional type descriptions when available.
  • Tests
    • Added regression and coverage tests for type-reference hovers in descriptions, including unknown and out-of-range cursor scenarios.

При наведении на имя типа в секциях `// Параметры:` и `// Возвращаемое
значение:` описания метода теперь показывается всплывающая документация
типа. Работает одинаково для инстанцируемых (например, ТаблицаЗначений)
и неинстанцируемых (например, СтрокаТаблицыЗначений) типов — в отличие от
hover'а конструктора, синтаксис `Новый` не показывается.

Реализовано по образцу существующих finder'ов:
- TypeReferenceSymbol — synthetic-символ с разрешённым TypeRef;
- DescriptionTypeReferenceFinder — резолвит TYPE_NAME-элемент описания под
  курсором в TypeRef (позиции элементов описания — абсолютные координаты);
- TypeReferenceMarkupContentBuilder — рендерит имя типа, метку «тип» и
  описание типа.

closes #3990

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

coderabbitai Bot commented Jun 16, 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: beac7e74-dafa-48c5-ac7d-ab71b2ae9b3f

📥 Commits

Reviewing files that changed from the base of the PR and between 9fb71ea and adea93a.

📒 Files selected for processing (1)
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/HoverProviderOScriptLibraryTest.java

📝 Walkthrough

Walkthrough

Adds hover support for type names in BSLDoc method descriptions. A new TypeReferenceSymbol represents a resolved type reference. DescriptionTypeReferenceFinder scans document symbol trees for TYPE_NAME description elements and resolves them via TypeService. TypeReferenceMarkupContentBuilder renders Markdown hover content with localized labels. Integration tests cover positive and negative hover cases.

Changes

Hover for BSLDoc type names

Layer / File(s) Summary
TypeReferenceSymbol data contract
src/main/java/.../types/symbol/TypeReferenceSymbol.java
Introduces TypeReferenceSymbol implementing Symbol with typeName and typeRef fields. Returns SymbolKind.Class, implements a no-op synthetic accept() to exclude from symbol-tree traversal, and uses equality/hashcode based only on typeName.
DescriptionTypeReferenceFinder – reference resolution
src/main/java/.../references/DescriptionTypeReferenceFinder.java
Adds a @Component @Order(300) ReferenceFinder that iterates symbol-tree methods and variables, filters TYPE_NAME description elements, checks cursor containment, extracts the type name substring from document content, resolves it via TypeService, and returns a Reference wrapping TypeReferenceSymbol.
TypeReferenceMarkupContentBuilder – hover rendering and localization
src/main/java/.../hover/TypeReferenceMarkupContentBuilder.java, src/main/resources/.../hover/TypeReferenceMarkupContentBuilder_*.properties
Adds a MarkupContentBuilder that constructs Markdown hover content with a localized type name, "type" label, optional description text, and CollectionHoverHints enrichment. Includes English (type=type) and Russian (type=тип) localization resource files.
Integration tests
src/test/java/.../providers/HoverOnDescriptionTypeTest.java, src/test/java/.../providers/HoverProviderOScriptLibraryTest.java
Adds HoverOnDescriptionTypeTest with four methods covering: hover on an instantiable type in the Параметры section, hover on a non-instantiable type in Возвращаемое значение, no hover for an unknown type name, and no hover when the cursor is outside a type name. Adds a regression test in HoverProviderOScriptLibraryTest verifying hover resolution for user-defined type names in method descriptions.

Sequence Diagram

sequenceDiagram
  participant Client as LSP Client
  participant HoverProvider
  participant DescriptionTypeReferenceFinder
  participant TypeService
  participant TypeReferenceMarkupContentBuilder

  Client->>HoverProvider: hover(uri, position)
  HoverProvider->>DescriptionTypeReferenceFinder: findReference(uri, position)
  DescriptionTypeReferenceFinder->>DescriptionTypeReferenceFinder: scan TYPE_NAME elements, check cursor containment
  DescriptionTypeReferenceFinder->>TypeService: resolve(typeName)
  TypeService-->>DescriptionTypeReferenceFinder: TypeRef
  DescriptionTypeReferenceFinder-->>HoverProvider: Reference(TypeReferenceSymbol)
  HoverProvider->>TypeReferenceMarkupContentBuilder: getContent(reference)
  TypeReferenceMarkupContentBuilder-->>HoverProvider: MarkupContent(MARKDOWN)
  HoverProvider-->>Client: Hover(markupContent, range)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • 1c-syntax/bsl-language-server#3993: Introduces the reference-oriented hover pipeline (MarkupContentBuilder#getContent(Reference)) that TypeReferenceMarkupContentBuilder integrates into.

Suggested reviewers

  • sfaqer

Poem

🐇 A type in a comment, so hidden before,
Now hover reveals what the docs have in store.
ТаблицаЗначений — one cursor away,
The rabbit has wired the description today!
From finder to builder, the chain is complete —
BSLDoc types and hover now meet. 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature: hover documentation for type names in method descriptions (BSLDoc).
Linked Issues check ✅ Passed All coding requirements from issue #3990 are met: hover for type names in BSLDoc descriptions works for instantiable, non-instantiable, and user-defined types.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing hover for type names in method descriptions; no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 feature/hover-bsldoc-type-names

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 and usage tips.

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Test Results

 3 474 files  + 6   3 474 suites  +6   1h 47m 13s ⏱️ + 18m 10s
 3 483 tests + 7   3 465 ✅ + 7   18 💤 ±0  0 ❌ ±0 
20 898 runs  +42  20 786 ✅ +42  112 💤 ±0  0 ❌ ±0 

Results for commit adea93a. ± Comparison against base commit 3dd3a91.

This pull request removes 1 and adds 8 tests. Note that renamed tests count towards both.
com.github._1c_syntax.bsl.languageserver.types.model.MemberDescriptorFactoryTest ‑ withLocalizedNamesAcceptsRuAndEnAtOnce()
com.github._1c_syntax.bsl.languageserver.providers.HoverOnDescriptionTypeTest ‑ hoverOnInstantiableTypeInParametersSection()
com.github._1c_syntax.bsl.languageserver.providers.HoverOnDescriptionTypeTest ‑ hoverOnNonInstantiableTypeInReturnsSection()
com.github._1c_syntax.bsl.languageserver.providers.HoverOnDescriptionTypeTest ‑ noHoverOnDescriptionTextOutsideTypeName()
com.github._1c_syntax.bsl.languageserver.providers.HoverOnDescriptionTypeTest ‑ noHoverOnUnknownTypeNameInDescription()
com.github._1c_syntax.bsl.languageserver.providers.HoverProviderOScriptLibraryTest ‑ hoverOnUserTypeNameInMethodDescriptionResolves()
com.github._1c_syntax.bsl.languageserver.semantictokens.PlatformMemberPropertyAccessSemanticTokensSupplierTest ‑ testOwnAttributeColoredAsPlainProperty()
com.github._1c_syntax.bsl.languageserver.semantictokens.PlatformMemberPropertyAccessSemanticTokensSupplierTest ‑ testStandardAttributeColoredAsDefaultLibrary()
com.github._1c_syntax.bsl.languageserver.types.model.MemberDescriptorFactoryTest ‑ withBilingualNameAcceptsRuAndEnAtOnce()

♻️ This comment has been updated with latest results.

private final TypeService typeService;

@Override
public Optional<Reference> findReference(URI uri, Position position) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Посмотри как работает semantic token supplier на описания методов и переменных

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Посмотрел. BslDocSemanticTokensSupplierCommentSemanticTokensSupplier) перебирают ровно тот же набор описаний, что и финдер: getMethods()getDescription(), getVariables()getDescription() + getTrailingDescription(), и подсвечивают все TYPE_NAME-элементы единообразно, без различения вида типа.

Отсюда вывод, который я зря размыл в описании PR (пункт 3): пользовательские/ссылочные/OneScript-типы в описании — это такие же TYPE_NAME-элементы, и финдер резолвит их тем же typeService.resolve(name, fileType), что и платформенные. Никакой отдельной обработки нет и не нужно.

Добавил доказательство: HoverProviderOScriptLibraryTest.hoverOnUserTypeNameInMethodDescriptionResolves — hover по имени USER-класса (PublicEntity) в // Возвращаемое значение: резолвится (коммит 81-й в ветке). Формулировку пункта 3 в описании PR поправлю.

Если посыл был в другом — например, вынести общий обход описаний (методы + переменные + trailing) в шейред-хелпер, переиспользуемый обоими supplier'ами и финдером, — скажи, сделаю отдельным шагом.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Посмотрел SymbolTree.getSymbolAtPosition(Position) (единственный метод получения символа по позиции). Проверил эмпирически на примере из issue:

  • desc.getRange() = строки 0–5 (блок описания над методом);
  • method.getRange() = строки 6–8 (только объявление, без ведущего описания);
  • getSymbolAtPosition(1:20) и getSymbolAtPosition(4:10) — позиции на именах типов внутри описания — возвращают Module, а не метод;
  • getSymbolAtPosition(6:10) — внутри объявления — возвращает Method.

То есть описание лежит вне getRange() символа (у SourceDefinedSymbol есть только getRange()/getSelectionRange(), оба про объявление), и getSymbolAtPosition для позиции в комментарии-описании отдаёт модуль. Поэтому напрямую заменить обход описаний на «символ по позиции → его описание» нельзя — символ под курсором не находится.

Варианты, как это причесать:

  1. оставить обход getMethods()/getVariables(), но гейтить по description.getRange().contains(position) и сразу выходить — дёшево, минимальное изменение, поведение то же;
  2. включить ведущее описание в getRange() метода/переменной — тогда getSymbolAtPosition начнёт попадать в описание (но это меняет семантику range символа, затронет другие потребители getRange);
  3. добавить в SymbolTree метод поиска символа по позиции его описания (getSymbolByDescriptionPosition) и в финдере брать описание только найденного символа.

Я бы выбрал (1) как локальный, или (3) если хочется переиспользуемого API «символ по позиции описания» (его же могли бы использовать оба semantic token supplier'а). Что предпочитаешь? Я не угадал твой посыл — поправь, если имел в виду другое.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Согласен — финдер в текущем виде не масштабируется и это блокер.

Проблема. DescriptionTypeReferenceFinder стоит @Order(300) (последний), поэтому ReferenceResolver вызывает его на каждую позицию, которую не разрешил ни один предыдущий финдер — а это не только ховер, но и горячий путь инференсера/диагностик. Каждый вызов делает полный линейный обход getMethods() + getVariables()getVariables() — это все переменные плоско: модульные + все локальные во всех методах; на УправлениеДоступом — тысячи) с разбором описаний, плюс трогает getContentList()/getSymbolTree() под computeLock на no-lock-пути. Это O(символов) на вызов.

Что нужно. Перебор описаний — один раз на документ, с индексом по позиции; ховер = поиск по позиции, без обхода дерева.

Развилка (проверил модель ReferenceIndex): getReference(uri, pos) фильтрует SymbolOccurrence по позиции, а buildReference ресолвит лёгкий указатель (mdoRef/moduleType/symbolName/symbolKind) обратно в SourceDefinedSymbol и понимает только Variable/Module/Method. Синтетический ref на платформенный TypeRef в эту модель без расширения не ложится.

Варианты:

  • A (локально, рекомендую): добавить в DocumentContext лениво-вычисляемый и кэшируемый (Lazy, сбрасывается вместе с symbol tree в clearSecondaryData) индекс TYPE_NAME-элементов описаний (отсортированный по позиции). Финдер делает по нему поиск по позиции (бинарный/интервальный) и резолвит имя через typeService.resolve. Перебор описаний — один раз на документ; ховер — O(log n). Изменение точечное, ReferenceIndex не трогаем.
  • B (унифицировано): расширить SymbolOccurrence/buildReference поддержкой type-таргетов и наполнять type-name-ссылки в ReferenceIndexFiller.fill(). Концептуально «как все ссылки», но лезет в общую модель (затронет getReferencesTo/accessibility и пр.).

Как промежуточная дешёвая отсечка в любом случае: если getSymbolAtPosition(pos) вернул не-Module символ, курсор внутри объявления (не в комментарии-описании) — сразу выходим.

Я за A. Дай добро на направление — переделаю и прогоню тесты. Если хочешь B (единый индекс) — тоже сделаю, но это уже про общую модель ссылок.

Подтверждает, что имя USER-типа в описании метода резолвится тем же
DescriptionTypeReferenceFinder, что и платформенные типы — никакой
отдельной обработки по виду типа нет (как и в semantic token supplier'е,
который подсвечивает все TYPE_NAME-элементы единообразно).

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

Copy link
Copy Markdown

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hover по именам типов в описаниях методов (BSLDoc)

1 participant