Summary
sprintfint (pkg/linters/sprintfint/sprintfint.go) rewrites fmt.Sprintf("%d", n) → strconv.Itoa(n). The emitted SuggestedFix (buildItoaFix, lines 94-109) contains only the call-replacement TextEdit — it never adds a "strconv" import, and it does nothing about the now-possibly-orphaned "fmt" import. For the common case of a file whose only strconv/fmt use is the flagged call, applying the fix produces code that fails to compile in two ways:
undefined: strconv — strconv.Itoa is emitted but strconv is not imported.
"fmt" imported and not used — the flagged call was the last fmt reference.
This is the same self-containment defect that #44653 filed against writebytestring (missing io import) — which has since been retrofitted with an in-fix import edit (writebytestring.go:213 addIOImportEdit), and the 44th linter bytescomparestring was written to add its bytes import in-fix (bytescomparestring.go:113 addBytesImportEdit). sprintfint is now the only import-introducing SuggestedFix linter that does not self-add its import, and it additionally has an orphaned-import problem the other two do not (they add a package; sprintfint both adds strconv and removes the last fmt use).
Evidence
pkg/linters/sprintfint/sprintfint.go:94-109 // buildItoaFix: single TextEdit, no import management
pkg/linters/sprintfint/sprintfint.go:22 // Doc: "suggested fixes may require goimports to add/remove imports"
The analyzer Doc string explicitly acknowledges the goimports dependency, but the autofix is applied verbatim by any non-gopls driver (e.g. go vet -vettool=... -fix, singlechecker -fix, multichecker -fix), none of which run goimports. Only editor-integrated gopls rescues it via format-on-save.
The RWSF golden hides the bug
sprintfint_test.go:16 uses analysistest.RunWithSuggestedFixes, but the fixture is hand-constructed so the import transition is never exercised:
pkg/linters/sprintfint/testdata/src/sprintfint/sprintfint.go(.golden)
import ( "fmt"; "strconv" ) // strconv PRE-imported -> no "undefined: strconv"
func goodInt64(n int64) ... // keeps other fmt.Sprintf uses alive -> fmt never orphaned
Because the fixture pre-imports strconv and preserves other fmt uses, the golden compiles and the test passes — giving false confidence that the autofix is compile-safe. analysistest does not compile the golden, so a single-use fixture would expose it.
Concrete failing input
package foo
import "fmt"
func label(n int) string { return fmt.Sprintf("%d", n) }
After -fix:
package foo
import "fmt" // "fmt" imported and not used
func label(n int) string { return strconv.Itoa(n) } // undefined: strconv
Impact
- Any bulk/CI application of the suggested fix (without a trailing goimports pass) yields non-compiling code for single-use files — the majority case for a targeted fmt/strconv call.
- Inconsistent with the suite's now-established convention (writebytestring retrofit + bytescomparestring) that import-introducing fixes are self-contained.
Recommendation
Adopt the same in-fix import handling used by bytescomparestring/writebytestring:
- Add a
"strconv" import TextEdit (reuse the grouped/single/standalone insertion logic + per-file dedup already implemented in those two linters — factor it into pkg/linters/internal/astutil to avoid a third copy).
- When the flagged call is the file's last
fmt reference, also remove the now-unused "fmt" import (or, if that analysis is too costly, keep the Doc caveat but at minimum add the strconv import so the result is at worst an unused-import warning, not an undefined error).
- Add a testdata fixture whose file imports only
fmt and uses fmt.Sprintf("%d", n) exactly once, so the RWSF golden exercises both the strconv-add and the fmt-removal.
Validation checklist
Effort: Small–Medium (mostly reuse of the existing import-edit helper; the fmt-removal is the only genuinely new logic). NOT CI-enforced today, so this is latent quality, not an active break.
Generated by 🤖 Sergo - Serena Go Expert · 333.5 AIC · ⌖ 11.7 AIC · ⊞ 5.8K · ◷
Summary
sprintfint(pkg/linters/sprintfint/sprintfint.go) rewritesfmt.Sprintf("%d", n)→strconv.Itoa(n). The emittedSuggestedFix(buildItoaFix, lines 94-109) contains only the call-replacementTextEdit— it never adds a"strconv"import, and it does nothing about the now-possibly-orphaned"fmt"import. For the common case of a file whose onlystrconv/fmtuse is the flagged call, applying the fix produces code that fails to compile in two ways:undefined: strconv—strconv.Itoais emitted butstrconvis not imported."fmt" imported and not used— the flagged call was the lastfmtreference.This is the same self-containment defect that #44653 filed against
writebytestring(missingioimport) — which has since been retrofitted with an in-fix import edit (writebytestring.go:213addIOImportEdit), and the 44th linterbytescomparestringwas written to add itsbytesimport in-fix (bytescomparestring.go:113addBytesImportEdit).sprintfintis now the only import-introducing SuggestedFix linter that does not self-add its import, and it additionally has an orphaned-import problem the other two do not (they add a package;sprintfintboth addsstrconvand removes the lastfmtuse).Evidence
The analyzer Doc string explicitly acknowledges the goimports dependency, but the autofix is applied verbatim by any non-gopls driver (e.g.
go vet -vettool=... -fix,singlechecker -fix,multichecker -fix), none of which run goimports. Only editor-integrated gopls rescues it via format-on-save.The RWSF golden hides the bug
sprintfint_test.go:16usesanalysistest.RunWithSuggestedFixes, but the fixture is hand-constructed so the import transition is never exercised:Because the fixture pre-imports
strconvand preserves otherfmtuses, the golden compiles and the test passes — giving false confidence that the autofix is compile-safe.analysistestdoes not compile the golden, so a single-use fixture would expose it.Concrete failing input
After
-fix:Impact
Recommendation
Adopt the same in-fix import handling used by
bytescomparestring/writebytestring:"strconv"importTextEdit(reuse the grouped/single/standalone insertion logic + per-file dedup already implemented in those two linters — factor it intopkg/linters/internal/astutilto avoid a third copy).fmtreference, also remove the now-unused"fmt"import (or, if that analysis is too costly, keep the Doc caveat but at minimum add thestrconvimport so the result is at worst an unused-import warning, not anundefinederror).fmtand usesfmt.Sprintf("%d", n)exactly once, so the RWSF golden exercises both the strconv-add and the fmt-removal.Validation checklist
fmtimport, one flagged call) — golden showsstrconvimported andfmtremoved, and the golden compiles.go build ./...on a scratch module after applying the fix to a single-use file.Effort: Small–Medium (mostly reuse of the existing import-edit helper; the fmt-removal is the only genuinely new logic). NOT CI-enforced today, so this is latent quality, not an active break.