fix(GradleTypesafeConventions): navigate and find usages for Kotlin catalog section names - #305
Merged
Merged
Conversation
… 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.
Contributor
Qodana for JVMIt 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 Contact Qodana teamContact us at qodana-support@jetbrains.com
|
|
Codecov Report❌ Patch coverage is 📢 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.
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Kotlin catalog accessors are broken for the tokens that name a catalog section (
versions,bundles,plugins), in two ways:LibrariesForLibs.java) instead ofgradle/libs.versions.toml.Library accessors (
libs.junit.jupiter) were unaffected;librarieshas no section token.Causes
These tokens select a TOML section, not an alias segment, and the Kotlin path treated them as alias selectors:
aliasSelectorStartIndex = 2for every non-librariessection, so the token never received aTypesafeConventionsKotlinCatalogReference. Inlibs.bundles.junit.bundlethe two references cover offsets 13–18 and 19–25 while the caret onbundlessits at offset 9, so the handler's range check never matched, it returnednull, and the platform fell back to reference resolution through the generated code.Groovy navigation already resolved section names through
TypesafeConventionsTomlCatalogAliasIndex.sectionOwner; the Kotlin path had no equivalent.Fix
Navigation
TypesafeConventionsKotlinCatalogAccessor.sectionExpression(nullforlibraries).libs.bundles) by relaxing the arity check.findTypesafeConventionsCatalogTomlFileplus the alias index section owner, with the same entrypoint validation as alias selectors.Find Usages
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
versionssections oflibsandcustomLibstogether reported only thelibsusages. The catalog check now runs ahead of deduplication.Tests
ReferencesSearchand the default Find Usages pipeline.pluginssection used from precompiled scriptpluginsblocks, and cross-catalog isolation.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.mdas the next planned work and predates this PR.