Skip to content

fix: derive Go import identifiers from the package, not the path segment - #703

Open
dudell-bud wants to merge 1 commit into
peteromallet:mainfrom
dudell-bud:fix/go-unused-import-package-name
Open

fix: derive Go import identifiers from the package, not the path segment#703
dudell-bud wants to merge 1 commit into
peteromallet:mainfrom
dudell-bud:fix/go-unused-import-package-name

Conversation

@dudell-bud

Copy link
Copy Markdown

Problem

The unused-import detector uses the last path segment of an import path as the in-code identifier. In Go that is frequently wrong, so every affected import gets reported as unused.

Scanning a real Go repo (desloppify --lang go scan) produced 20 false positives and no true positives:

Import Reported Actually used as
_ "github.com/joho/godotenv/autoload" unused import: autoload nothing — blank import, for init() side effects
"gopkg.in/yaml.v3" unused import: v3 yaml.Unmarshal(...)
"math/rand/v2" unused import: v2 rand.N(...)
"github.com/go-playground/validator/v10" unused import: v10 validator.New()
"github.com/anthropics/anthropic-sdk-go" unused import: anthropic-sdk-go anthropic.MessageParam

Note the last row can never be right: - is not legal in a Go identifier.

There is also a general argument for treating this class conservatively: go build fails on a genuinely unused import, so a Go module that compiles cannot have one. Any finding of this class on a compiling module is therefore a false positive.

Fix

Go now gets its own identifier resolver instead of the generic path-segment heuristic:

  • Blank (_) and dot (.) imports are skipped. A blank import exists purely for its init() side effect and is never "used" by design; a dot import injects every exported name with no qualifier to search for.
  • Major-version segments are stripped/v2, /v10, and gopkg.in-style yaml.v3.
  • Unresolvable names return None, and callers treat None as "do not report". Where the package clause cannot be determined from the path alone (e.g. a hyphenated repo name), staying silent is the right call: a false negative costs far less than a false positive.

Verification

  • python -m pytest desloppify/tests/ -q5825 passed, 3 skipped
  • Added desloppify/tests/lang/common/test_go_unused_imports.py covering each case in the table above.
  • Scanned the repo that surfaced this: its 17 unused-import findings drop to 0, with no new findings elsewhere.

🤖 Generated with Claude Code

The unused-import detector took the last path segment as the in-code
identifier. In Go that is frequently wrong, so every affected import was
reported as unused.

Scanning a real Go repo produced 20 false positives and no true positives:

  _ "github.com/joho/godotenv/autoload"   -> "unused import: autoload"
  "gopkg.in/yaml.v3"                      -> "unused import: v3"
  "math/rand/v2"                          -> "unused import: v2"
  "github.com/go-playground/validator/v10"-> "unused import: v10"
  "github.com/anthropics/anthropic-sdk-go"-> "unused import: anthropic-sdk-go"

These are used as yaml., rand., validator. and anthropic. respectively; the
first is a blank import that exists only for its init() side effect. Note
that a hyphenated segment can never be a Go identifier at all.

There is also a general argument: go build fails on a genuinely unused
import, so a Go module that compiles cannot have one, and any finding of
this class on a compiling module is a false positive.

Go now gets its own resolver that skips blank and dot imports, strips
major-version segments (/v2, .v3), and returns None when the identifier
cannot be determined from the path alone — callers treat None as "do not
report", because a false negative is far cheaper than a false positive here.

Verified: full suite passes (5825 passed, 3 skipped); scanning the repo that
surfaced this drops its 17 unused-import findings to 0 with no new findings.
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