(This proposal is the second of a sequence of two; #73605 is the first. --adonovan)
Proposal Details
go fix
should have a type of fix called modernize
that applies modernizers.
As an example, running go fix
would change all occurrences of interface{}
to any
, provided the identifier any
is not shadowed.
For the current set of modernizers, see https://go.googlesource.com/tools/+/refs/heads/master/gopls/internal/analysis/modernize.
Comment From: adonovan
Currently the go fix
~comment~ command is completely unrelated to the //go:fix inline
annotation; it's just a grab-bag of syntax-only rewrites for very ancient features. I'm not sure whether anyone really uses it at all. At some point it might be worth rethinking it as a front-end for the go/analysis framework and the multichecker's -fix functionality.
Comment From: mvdan
(I assume you meant "go fix command" above). I have yet to encounter a recent Go user (say, who started using Go after 2015 or so) who is aware of go fix
or what it does. I suspect at this point the command could be redesigned to do whatever you feel like is most useful, as long as it can be safely run on large codebases without having to worry about any subtle breakages.
Comment From: adonovan
I agree. A good step would be to add a telemetry counter to Go 1.25 for invocations of go fix
so we can tell whether anyone is in fact still using it.
@matloob @samthanawalla @jitsu-net
Comment From: adonovan
I propose that the go fix
command-line interface should resemble go vet
as much as possible, and the two tools should be thereafter documented as a pair, where vet
is responsible for emitting diagnostics and fix
is responsible for quietly applying suggested fixes. The two tools would be implemented by the same structure both implemented by the unitchecker driver, but effectively invoked in different modes.
The suites of analyzers in the two tools would of course differ (with some overlap). Whereas vet
prizes accurate diagnosis of significant problems, fix
would aim for fixes that never hurt the quality of the code, where quality is defined across many axes:
- syntactic and semantic well-formedness (fixes don't break the build)
- behavior preservation (including in edge cases such as nilness, NaNs, aliasing, cardinality of effects)
- performance (fixes mustn't make code slower)
- style (doesn't make the code ungainly, or lose commentary)
Our goal is that users should be able to run go fix
on a large code base and merge the resulting CL with only cursory review, confident that the tools have not introduced bugs. I plan to write up a checklist for authors of fixers wanting to meet this bar.
Comment From: deefdragon
Would fix
only be limited to issues that vet detects? or could/would/should its bounds extend beyond that?
Relatedly, if the latter, would that extension be for just common things determine worth fixing by the go team, or would it be extendable by 3rd parties IE
- Tooling (lets say staticcheck/golangci-lint for common issues)
- The user (Ie. replacing a deprecated code pattern across an org with a newer pattern)
- A library developer to assist in migrating (IE. github.com/pkg/errors could extend fix
to help users migrate to modern error conventions)
I suspect the ability to extend in general is not the best idea as it may increase complexity beyond what its worth, but it still feels worth bringing up to see if its a reasonable option.