Skip to content

feat(documentLink): кликабельные ссылки «См.» в описаниях методов#4110

Merged
nixel2007 merged 2 commits into
developfrom
claude/doclink-see-references
Jun 14, 2026
Merged

feat(documentLink): кликабельные ссылки «См.» в описаниях методов#4110
nixel2007 merged 2 commits into
developfrom
claude/doclink-see-references

Conversation

@nixel2007

@nixel2007 nixel2007 commented Jun 14, 2026

Copy link
Copy Markdown
Member

Что сделано

Добавлен SeeReferenceDocumentLinkSupplier (@Component implements DocumentLinkSupplier), который делает кликабельными перекрёстные ссылки См. (англ. See) в doc-комментариях методов. Клик по ссылке ведёт к объявлению целевого метода.

Что линкуется

  • Ссылка на метод того же модуля: // См. ДругойМетод
  • Ссылка на экспортный метод общего модуля: // См. ОбщийМодуль.Метод
  • Английское ключевое слово See поддерживается «из коробки» (общий SEE_KEYWORD лексера описаний bsl-parser).

DocumentLink формируется строго над текстом ссылки (без ключевого слова См. и без завершающей точки) — точный Range берётся из Hyperlink.range() парсера описаний.

Как разрешаются цели

Сапплаер не вводит новых индексов и переиспользует существующую инфраструктуру:

  • ссылки разбираются парсером описаний: MethodSymbol.getDescription().getLinks()Hyperlink (текст ссылки + диапазон уже в координатах документа);
  • метод того же модуля: DocumentContext.getSymbolTree().getMethodSymbol(имя);
  • метод общего модуля: Configuration.findCommonModule(имя)MdoReferenceServerContext.getDocument(mdoRef, ModuleType.CommonModule)getSymbolTree().getMethodSymbol(метод).

Цель указывается сразу (eager target) в форме URI#Lстрока,колонкаdocumentLink/resolve не требуется. Неразрешимые ссылки пропускаются, висячие (битые) ссылки не создаются.

Тесты

  • SeeReferenceDocumentLinkSupplierTest: ссылка того же модуля → линк с точным диапазоном и целью; ссылка на общий модуль → линк на метод общего модуля; несуществующий метод → ничего (без висячих ссылок).
  • DocumentLinkProviderTest: проверка агрегации — провайдер отдаёт «См.»-ссылки рядом с существующими (URL из комментариев).

*DocumentLink* тесты зелёные (15 шт.), compileJava — BUILD SUCCESSFUL.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added document link support for "See" references in documentation comments. Users can now click hyperlinks in "See" doc references to navigate directly to the declarations of referenced methods and symbols, with support for both same-module and cross-module references.

Добавлен SeeReferenceDocumentLinkSupplier: сканирует doc-комментарии
методов на ссылки вида `// См. ИмяМетода` и `// См. ОбщийМодуль.Метод`
(а также английское `See`), разрешает их в местоположение целевого
метода и формирует DocumentLink над текстом ссылки.

Ссылки на метод того же модуля разрешаются через SymbolTree, ссылки на
метод общего модуля — через Configuration.findCommonModule и
ServerContext.getDocument. Неразрешимые ссылки пропускаются (без висячих
ссылок). Цель ссылки указывается сразу (URI#Lстрока,колонка).

Co-Authored-By: Claude Fable 5 <[email protected]>
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds SeeReferenceDocumentLinkSupplier, a Spring component that scans BSL module methods and variables for doc-comment "See/См." hyperlinks and resolves them into LSP DocumentLink objects. Resolution covers same-module method references and cross-module CommonModuleName.MethodName references via server configuration lookup. Four unit tests and one provider integration test validate the new behavior.

Changes

See-Reference Document Link Feature

Layer / File(s) Summary
SeeReferenceDocumentLinkSupplier: entry point, resolution, and helpers
src/main/java/.../documentlink/SeeReferenceDocumentLinkSupplier.java
getDocumentLinks iterates module methods and variables collecting doc-comment hyperlinks; addLinkIfResolvable builds a DocumentLink from the resolved Location; resolveReference handles same-module and CommonModule.Method forms; helpers convert SourceDefinedSymbol to Location, anchor string, and precise link-text Range.
Unit and provider integration tests
src/test/java/.../documentlink/SeeReferenceDocumentLinkSupplierTest.java, src/test/java/.../providers/DocumentLinkProviderTest.java
Four tests cover same-module, common-module, variable-description, and unresolved references; a URI-fragment helper formats expected targets. DocumentLinkProviderTest adds an aggregation test asserting http://example.com and #L appear in provider output.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 A "See" in the comments, a hop through the tree,
Same module or common — the link jumps with glee!
The supplier resolves with a flick of an ear,
Anchoring targets to symbols held dear.
Four tests stand as burrows, all checked and all right —
The rabbit hops onward, the doc links shine bright! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% 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 clearly describes the main change: introducing clickable 'See' reference links in method descriptions, which aligns with the PR's core objective of making cross-reference links navigable.
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.

✏️ 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 claude/doclink-see-references

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 14, 2026

Copy link
Copy Markdown
Contributor

Test Results

 3 402 files  + 12   3 402 suites  +12   1h 41m 49s ⏱️ + 9m 26s
 3 380 tests + 23   3 362 ✅ + 23   18 💤 ±0  0 ❌ ±0 
20 280 runs  +138  20 172 ✅ +138  108 💤 ±0  0 ❌ ±0 

Results for commit b915198. ± Comparison against base commit 6e380f3.

♻️ This comment has been updated with latest results.

public List<DocumentLink> getDocumentLinks(DocumentContext documentContext) {
var documentLinks = new ArrayList<DocumentLink>();

for (MethodSymbol method : documentContext.getSymbolTree().getMethods()) {

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.

У переменных тоже есть описание, и там могут быть линки

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.

Готово — сапплаер теперь обходит описания и методов, и переменных через общий Describable.getDescription().getLinks() (метод лежит на базовом SourceDefinedSymbolDescription, общем для MethodSymbol и VariableSymbol). Добавлен тест: Перем с // См. <ref> в doc-комментарии даёт ссылку. (b915198)


var moduleName = reference.substring(0, separatorIndex);
var methodName = reference.substring(separatorIndex + 1);
return resolveCommonModuleMethod(documentContext, moduleName, methodName);

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.

Зачем??? Есть же TypeService

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.

Проверил по коду: на этой ветке (от develop, без #4111) TypeService кейс не покрывает. Все его точки входа — по Position/Reference/TypeRef/MemberDescriptor; единственный строковый метод resolve(String, FileType) отдаёт TypeRef, а не источниковый символ/Location. Ссылка «См.» — голая строка из doc-комментария: её нет ни в AST как вызова, ни в индексе ссылок. Цепочка findCommonModule → getMdoRef → getDocument → getMethodSymbol — штатная идиома репозитория (та же в ReferenceIndexFiller, MissingCommonModuleMethodDiagnostic, ScheduledJobHandlerDiagnostic), не самопал; зафиксировал причину в javadoc. Правильный инструмент — TypeService.definingSymbol, который добавляет #4111: как только он вмержится, переведу резолв на него (или ребейзну #4110 поверх). Если ты имел в виду другой метод TypeService — подскажи, переключусь.

…TypeService

Сапплаер «См.» теперь обходит описания не только методов, но и переменных:
оба символа Describable, getLinks() лежит на общем SourceDefinedSymbolDescription.

Резолв цели не переведён на TypeService: на этой ветке он умеет резолвить
только по позиции/Reference или возвращать TypeRef по имени, но не источниковый
символ/Location по строковому имени из doc-комментария. Причина зафиксирована
в javadoc resolveTarget; идиома findCommonModule → getDocument сохранена.

Co-Authored-By: Claude Fable 5 <[email protected]>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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/test/java/com/github/_1c_syntax/bsl/languageserver/providers/DocumentLinkProviderTest.java`:
- Around line 65-86: The assertion chain in
testProviderAggregatesSeeReferenceLinks() has a compilation error because
ListAssert does not support chaining after anyMatch(). Split the single
assertion into two separate assertions: one that uses anyMatch to verify at
least one extracted target contains "`#L`", and another that verifies the
documentLinks list contains "http://example.com". The anyMatch check should be
performed on the extracted list, and the contains check should be performed
separately on the original documentLinks list or on a re-extracted list.
🪄 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: 2b336772-886f-484c-b220-4170974ed0e9

📥 Commits

Reviewing files that changed from the base of the PR and between 6e380f3 and b915198.

⛔ Files ignored due to path filters (1)
  • src/test/resources/documentlink/seeReferenceDocumentLinkSupplier.bsl is excluded by !src/test/resources/**
📒 Files selected for processing (3)
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/documentlink/SeeReferenceDocumentLinkSupplier.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/documentlink/SeeReferenceDocumentLinkSupplierTest.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/DocumentLinkProviderTest.java

Comment on lines +65 to +86
@Test
void testProviderAggregatesSeeReferenceLinks() {
// given
var content = """
// См. ДругойМетод. http://example.com
Процедура Тест() Экспорт
КонецПроцедуры

Процедура ДругойМетод() Экспорт
КонецПроцедуры
""";
var documentContext = TestUtils.getDocumentContext(content);

// when
var documentLinks = documentLinkProvider.getDocumentLinks(documentContext);

// then
assertThat(documentLinks)
.extracting(DocumentLink::getTarget)
.anyMatch(target -> target.contains("#L"))
.contains("http://example.com");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix the invalid assertion chain.

Lines 82-85 contain a compilation error. AssertJ's ListAssert (returned by extracting) does not have an anyMatch method that returns the assertion for chaining. The assertion must be split into separate checks:

🐛 Proposed fix
   // then
-  assertThat(documentLinks)
-    .extracting(DocumentLink::getTarget)
-    .anyMatch(target -> target.contains("`#L`"))
-    .contains("http://example.com");
+  assertThat(documentLinks)
+    .extracting(DocumentLink::getTarget)
+    .anyMatch(target -> target.contains("`#L`"));
+  assertThat(documentLinks)
+    .extracting(DocumentLink::getTarget)
+    .contains("http://example.com");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Test
void testProviderAggregatesSeeReferenceLinks() {
// given
var content = """
// См. ДругойМетод. http://example.com
Процедура Тест() Экспорт
КонецПроцедуры
Процедура ДругойМетод() Экспорт
КонецПроцедуры
""";
var documentContext = TestUtils.getDocumentContext(content);
// when
var documentLinks = documentLinkProvider.getDocumentLinks(documentContext);
// then
assertThat(documentLinks)
.extracting(DocumentLink::getTarget)
.anyMatch(target -> target.contains("#L"))
.contains("http://example.com");
}
`@Test`
void testProviderAggregatesSeeReferenceLinks() {
// given
var content = """
// См. ДругойМетод. http://example.com
Процедура Тест() Экспорт
КонецПроцедуры
Процедура ДругойМетод() Экспорт
КонецПроцедуры
""";
var documentContext = TestUtils.getDocumentContext(content);
// when
var documentLinks = documentLinkProvider.getDocumentLinks(documentContext);
// then
assertThat(documentLinks)
.extracting(DocumentLink::getTarget)
.anySatisfy(target -> assertThat(target).contains("`#L`"));
assertThat(documentLinks)
.extracting(DocumentLink::getTarget)
.contains("http://example.com");
}
🤖 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/providers/DocumentLinkProviderTest.java`
around lines 65 - 86, The assertion chain in
testProviderAggregatesSeeReferenceLinks() has a compilation error because
ListAssert does not support chaining after anyMatch(). Split the single
assertion into two separate assertions: one that uses anyMatch to verify at
least one extracted target contains "`#L`", and another that verifies the
documentLinks list contains "http://example.com". The anyMatch check should be
performed on the extracted list, and the contains check should be performed
separately on the original documentLinks list or on a re-extracted list.

@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.

1 participant