Skip to content

fix(GradleTypesafeConventions): navigate and find usages for Kotlin catalog section names - #305

Merged
ghostflyby merged 5 commits into
mainfrom
fix/typesafe-conventions-section-navigation
Sep 19, 2026
Merged

ghostflyby merged 5 commits into
mainfrom
fix/typesafe-conventions-section-navigation

Conversation

@ghostflyby

@ghostflyby ghostflyby commented Sep 19, 2026 •

Copy link
Copy Markdown
Owner

Problem

Kotlin catalog accessors are broken for the tokens that name a catalog section (versions, bundles, plugins), in two ways:

  1. Goto Declaration on such a token landed in the generated accessor sources (LibrariesForLibs.java) instead of gradle/libs.versions.toml.
  2. Find Usages on a section name in the catalog found nothing at all.

Library accessors (libs.junit.jupiter) were unaffected; libraries has no section token.

Causes

These tokens select a TOML section, not an alias segment, and the Kotlin path treated them as alias selectors:

  • aliasSelectorStartIndex = 2 for every non-libraries section, so the token never received a TypesafeConventionsKotlinCatalogReference. In libs.bundles.junit.bundle the two references cover offsets 13–18 and 19–25 while the caret on bundles sits at offset 9, so the handler's range check never matched, it returned null, and the platform fell back to reference resolution through the generated code.
  • Find Usages only recognized catalog alias keys. Section names are addressed through the owning table or inline table, which no search target matched, and the use-scope enlarger only handled key segments.

Groovy navigation already resolved section names through TypesafeConventionsTomlCatalogAliasIndex.sectionOwner; the Kotlin path had no equivalent.

Fix

Navigation

  • Expose the section token as TypesafeConventionsKotlinCatalogAccessor.sectionExpression (null for libraries).
  • Allow an accessor consisting of the section token alone (libs.bundles) by relaxing the arity check.
  • After reference lookup misses, resolve the token via findTypesafeConventionsCatalogTomlFile plus the alias index section owner, with the same entrypoint validation as alias selectors.

Find Usages

  • The alias index now records the key segment naming each section and the element owning it, so both the caret element (table header, inline table key, or leading segment of a top-level dotted key) and the section it stands for are available.
  • Search targets became a sealed type: alias segments keep matching through the alias index, section names match Kotlin accessors by section plus the catalog the accessor resolves to, so same-named sections of different catalogs stay isolated.
  • Reported section usages resolve to the searched section and leave the token text untouched on rename — a section name is a structural Gradle catalog key, and rewriting it would change what the expression selects.
  • The use-scope enlarger covers section names, so the default Find Usages pipeline reaches the convention sources rather than only the catalog file.

Shared search session (found in review)

Section Find Usages originally deduplicated occurrences before checking which catalog the usage belongs to. The occurrence set lives in the search session, and one session can batch requests for several catalogs over the same search word, so the first catalog to claim an occurrence suppressed the request that legitimately owned it: searching the versions sections of libs and customLibs together reported only the libs usages. The catalog check now runs ahead of deduplication.

Tests

  • Section name indexing for every TOML shape (standard table, dotted key, inline table), including that alias segments are not section names and that a library alias named like a section claims no section.
  • Section navigation and section Find Usages for default and custom catalogs across all four convention builds, through both ReferencesSearch and the default Find Usages pipeline.
  • The plugins section used from precompiled script plugins blocks, and cross-catalog isolation.
  • Several catalogs batched into one SearchRequestCollector, which reproduces the shared-session defect on the previous ordering.

Full suite: 173 tests, 0 failures on the pinned 2026.1 platform.

Not in scope

Groovy DSL Find Usages and rename remain unimplemented for contributed catalogs; that gap is tracked in the plugin's TODO.md as the next planned work and predates this PR.

… to TOML sections

Goto Declaration on the `versions` / `bundles` / `plugins` token of a Kotlin
catalog accessor produced no custom reference at all: those tokens select a TOML
section rather than an alias segment, so the accessor treated them as the
selector start index and only alias selectors received
`TypesafeConventionsKotlinCatalogReference` instances. With the caret on a
section token the handler found no reference covering the offset, returned null,
and the platform fell back to the generated accessor sources
(`LibrariesForLibs.java`). Library accessors were unaffected because `libraries`
has no such token.

Resolve section tokens in the goto handler after reference lookup misses, using
the TOML alias index section owner so standard tables, top-level dotted keys, and
inline tables all work, and let an accessor consist of the section token alone
(`libs.bundles`). Groovy navigation already resolved section names this way.

Adds `CatalogSectionCase` coverage for both default and custom catalogs across
every convention build, asserting the target is the section owner from the alias
index.
@github-actions

github-actions Bot commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Qodana for JVM

It seems all right 👌

No new problems were found according to the checks applied

💡 Qodana analysis was run in the pull request mode: only the changed files were checked
☁️ View the detailed Qodana report

Contact Qodana team

Contact us at qodana-support@jetbrains.com

@codecov-commenter

codecov-commenter commented Sep 19, 2026 •

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 65.33333% with 52 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...radle/TypesafeConventionsKotlinCatalogReference.kt 62.20% 18 Missing and 30 partials ⚠️
...s/gradle/TypesafeConventionsTomlCatalogResolver.kt 82.60% 0 Missing and 4 partials ⚠️

📢 Thoughts on this report? Let us know!

…on names

Find Usages on a `versions` / `bundles` / `plugins` section name in a version
catalog found nothing: the platform's own pipeline only recognizes catalog alias
keys, and these names select a section rather than an alias, so no Kotlin usage
was ever reachable from them.

The TOML alias index now records the key segment naming each section and the
element owning it, which gives both the caret element (a table header, an inline
table key, or the leading segment of a top-level dotted key) and the section it
stands for. Search targets became a sealed type: an alias segment keeps matching
through the alias index, while a section name matches Kotlin accessors by section
plus the catalog the accessor resolves to, so same-named sections of different
catalogs stay isolated. Reported cycle usages resolve to the searched section and
leave the token text untouched on rename: a section name is a structural Gradle
catalog key, and rewriting it would change what the expression selects. The
use-scope enlarger now covers section names too, so the default Find Usages
pipeline reaches the convention sources instead of only the catalog file.

`libraries` is excluded: it has no accessor token (`libs.foo`, not
`libs.libraries.foo`), so no Kotlin usage can name it.

Coverage adds section name indexing for every TOML shape, section Find Usages
through both `ReferencesSearch` and the default Find Usages pipeline for default
and custom catalogs, the `plugins` section used from precompiled script
`plugins` blocks, and cross-catalog isolation.
@ghostflyby ghostflyby changed the title fix(GradleTypesafeConventions): resolve Kotlin catalog section tokens to TOML sections fix(GradleTypesafeConventions): navigate and find usages for Kotlin catalog section names Sep 19, 2026
…ared search session

Section Find Usages deduplicated occurrences before checking which catalog the
usage belongs to. The occurrence set lives in the search session, and one session
can batch requests for several catalogs over the same search word, so the first
catalog to claim an occurrence suppressed the request that legitimately owned it:
searching the `versions` sections of `libs` and `customLibs` together reported
only the `libs` usages.

Move the catalog check ahead of deduplication, so an occurrence is recorded only
for the catalog it belongs to. Covers the regression by batching both catalogs
through one `SearchRequestCollector` and asserting every catalog's usages are
reported; the case fails on the previous ordering.
…atalog section

The section lookups added for section navigation and Find Usages must not claim a
library alias whose name happens to match a section name. A catalog declaring only
`[libraries] bundles = ...` has no bundles section, so the section lookups stay
empty for it while the key remains a normal library alias.
…d into a return

Replaces the `if (!set.add(...)) return true` block with the equivalent short-circuit
return, as reported by Qodana. The catalog check still runs before deduplication, so
an occurrence is only recorded for the catalog it belongs to.
@ghostflyby
ghostflyby merged commit cd13ae3 into main Sep 19, 2026
6 checks passed
@ghostflyby
ghostflyby deleted the fix/typesafe-conventions-section-navigation branch September 19, 2026 14:53
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.

3 participants