Skip to content

fix: skip Kotlin operator convention imports in unused-import detection - #740

Open
ariancovac wants to merge 1 commit into
peteromallet:mainfrom
ariancovac:fix/kotlin-operator-import-false-positives
Open

ariancovac wants to merge 1 commit into
peteromallet:mainfrom
ariancovac:fix/kotlin-operator-import-false-positives

Conversation

@ariancovac

Copy link
Copy Markdown

Problem

Kotlin invokes convention (operator) functions implicitly by the compiler. The clearest case: import androidx.compose.runtime.getValue / setValue are required for Compose State/MutableState property delegation (val x by someState, var y by mutableStateOf(...)), yet the names never appear in the file text.

Textual unused-import detection cross-references the imported name against the file body, so it flagged these live imports as unused on every scan (in one real Compose project: 26 findings across 15 files). Removing them breaks compilation — the reviewer either "fixes" a false positive into a build break, or has to dismiss the same findings after every rescan.

Fix

  • Add an optional implicit_import_names: frozenset[str] field to TreeSitterLangSpec: names a language invokes implicitly by convention, which a textual reference search cannot rule out.
  • Populate it for KOTLIN_SPEC with the Kotlin convention-function table: property delegation (getValue, setValue, provideDelegate), unary/arithmetic/ranges, augmented assignments, containment/indexing/invocation/comparison (contains, get, set, invoke, compareTo, equals), iteration (iterator, next, hasNext), and infix bitwise (and, or, xor, shl, shr, ushr).
  • detect_unused_imports skips imported names present in that set. This trades a small amount of recall (a genuinely unused operator-named import goes unreported) for eliminating a false-positive class that directly invites build-breaking fixes — consistent with the detector's conservative stance elsewhere (e.g. skipping errorful parses).
  • Other languages are unaffected (the field defaults to empty).

Test

test_unused_imports_skip_implicit_convention_names: with an implicit_import_names-carrying spec, an unreferenced getValue import yields no findings; with a plain spec it is still flagged. Suite: 29 passed in test_treesitter_analysis_direct.py + test_phase_builders.py.

Kotlin invokes convention (operator) functions implicitly: importing
androidx.compose.runtime.getValue is required for property delegation
(val x by someState) even though the name never appears in the file
text. Textual unused-import detection flagged such live imports as
unused; removing them breaks compilation.

Add an implicit_import_names set to the tree-sitter language spec and
populate it for Kotlin with the convention-function table (delegation,
unary, arithmetic, augmented assignment, containment/indexing,
invocation, comparison, iteration, infix bitwise). Imports resolving to
those names are skipped by unused-import detection.
@awdemos

awdemos commented Sep 12, 2026

Copy link
Copy Markdown

Reviewed this against #676 — both fix the same Compose getValue/setValue unused-import false positive, but with different designs, and #676 is the stronger implementation:

  • fix: skip Kotlin operator convention imports in unused-import detection #740 adds TreeSitterLangSpec.implicit_import_names and blanket-skips ~40 operator names unconditionally. A/B on real Kotlin files: a genuinely dead import …getValue with no by in the file is silenced, and dead imports named get, equals, and, or, contains, iterator can never be reported again. It also can't cover componentN destructuring (a frozenset can't express component\d+), so that false positive remains. The test suite is all FakeNode mocks.
  • fix: don't flag Kotlin delegation/destructuring imports as unused #676 adds implicit_import_uses — (name_pattern, body_pattern) pairs — so an import is only forgiven when the triggering syntax is actually present (by delegation, val (a, b) destructuring). Same false positive fixed; dead imports still found; covers componentN; end-to-end tests with the real tree-sitter grammar.

If there are operator names in #740's list you want coverage for, the right move is folding them into #676's mechanism (conditional on syntax) rather than landing the unconditional skip. Suggest closing this in favor of #676.

This branch has not been deployed

No deployments
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