-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
x/tools/gopls/internal/analysis: add "modernizer" analyzers #70815
Comments
Would it make sense for some of these to be depreciations instead? Particularly looking at x/exp/maps.Clear and the go/* upgrades. |
Even if we were to deprecate maps.Clear (which is perfectly fine function), users would still want a way to migrate their code away from it. So I see deprecation as independent. And in many cases the pattern being "modernized" is not just a simple use of one symbol that could be deprecated. |
Some of these (maybe all 😄 ) are subtler than they appear on the tin.
The core of this is just replacing
Here you have to identify the underlying "resource" that's being freed by the finalizer since that's what
There are so many patterns for splitting a string into lines right now. I'm really curious how we'd pick up on that.
In addition to creating Append methods, ideally this should also rewrite |
Change https://go.dev/cl/635777 mentions this issue: |
Change https://go.dev/cl/635680 mentions this issue: |
Change https://go.dev/cl/635681 mentions this issue: |
This change replaces the body of almost every function in the package with a call to its corresponding std function of the same name and--assumedly--semantics. If proposal golang/go#32816 is accepted, we will annotate each function with a "//go:fix inline" comment so that automated tooling such as golang.org/x/tools/internal/refactor/inline/analyzer can automatically inline the wrappers. (This CL is deemed to fix golang/go#70717 because it reduces maps.Clear to the same status as all the other maps functions.) Updates golang/go#32816 Updates golang/go#70815 Fixes golang/go#70717 Change-Id: I85246df07f903af97673b80024acdcae057b9f63 Reviewed-on: https://go-review.googlesource.com/c/exp/+/635680 Auto-Submit: Alan Donovan <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
Change https://go.dev/cl/636276 mentions this issue: |
Change https://go.dev/cl/637735 mentions this issue: |
Change https://go.dev/cl/638337 mentions this issue: |
This CL is the start of an analyzer that offers a suite of code transformations to modernize Go code, by taking advantage of newer features of the language when it would clarify the code to do so. Because it reports diagnostics on correct code, its severity is downgraded to INFO. Only one is implemented so far: the replacement of if/else conditional assignments by a call to min or max. + relnote and test Updates golang/go#70815 Change-Id: I686db57c2b95dfa399b44e5c6fdc478272cee084 Reviewed-on: https://go-review.googlesource.com/c/tools/+/635777 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]>
This CL adds a modernizer for calls to sort.Slice, where the less function is the natural order: sort.Slice(s, func(i, j int) bool { return s[i] < s[j] }) => slices.Sort(s) (Ditto SliceStable -> SortStable.) The foldingrange test was tweaked to avoid triggering this fix. Updates golang/go#70815 Change-Id: I755351c77aab8ddf7f21369c0f980e8d3334fc01 Reviewed-on: https://go-review.googlesource.com/c/tools/+/635681 Reviewed-by: Robert Findley <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Alan Donovan <[email protected]>
Also, modernize our tests in this manner. Also, remove existing "useany" analyzer, which is subsumed by this one. The fact that useany was off by default suggest that perhaps modernize may need to be as well; but perhaps severity=INFO will suffice. Updates golang/go#70815 Change-Id: Iba1662993fb8a1c50b2d843ad9425bbddafc927f Reviewed-on: https://go-review.googlesource.com/c/tools/+/636276 Auto-Submit: Alan Donovan <[email protected]> Reviewed-by: Robert Findley <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
Change https://go.dev/cl/638595 mentions this issue: |
This CL adds the first modernizer for the "slices" package. It offers to replace an append (or tower of nested appends) to a clipped slice by a call to slices.Concat or slices.Clone. Examples: append(append(append(x[:0:0], a...), b...), c...) -> slices.Concat(a, b, c) append(append(slices.Clip(a), b...) -> slices.Concat(a, b) append([]T{}, a...) -> slices.Clone(a) append([]string(nil), os.Environ()...) -> os.Environ() It takes care not to offer fixes that would eliminate potentially important side effects such as to y's array in this example: append(y[:0], x...) -> slices.Clone(x) (unsound) However, it does not attempt to preserve the nilness of base in append(base, empty...) when the second argument is empty. Updates golang/go#70815 Change-Id: I5ea13bbf8bfd0b78a9fb71aef4c14848b860cc3a Reviewed-on: https://go-review.googlesource.com/c/tools/+/637735 Reviewed-by: Robert Findley <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
This CL adds a modernizer for go1.24's testing.B.Loop. It replaces for/range loops over b.N by b.Loop() and deletes any preceding calls to b.{Start,Stop,Reset}Timer. Updates golang/go#70815 Change-Id: I504c9fed20beaec3c085c64f9ce42d3f6ad435d8 Reviewed-on: https://go-review.googlesource.com/c/tools/+/638337 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]>
Change https://go.dev/cl/638875 mentions this issue: |
Change https://go.dev/cl/638436 mentions this issue: |
Thanks for the exemplary bug report. I forgot to check the operator used by the AssignStmt--too easily done. |
Change https://go.dev/cl/642076 mentions this issue: |
A loop body of m[k] += v was spuriously matched because I forgot to check the assignment operator. + test Updates golang/go#70815 Change-Id: If74dcbb0ba920ebd475b1d0bd9191c9b44661a1a Reviewed-on: https://go-review.googlesource.com/c/tools/+/642076 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Alan Donovan <[email protected]>
Change https://go.dev/cl/642078 mentions this issue: |
Fix another bug related to not checking AssignStmt.Op. + test Updates golang/go#70815 Change-Id: I426d27b4879d30f9fecb4d0f131b3c1a0b07773b Reviewed-on: https://go-review.googlesource.com/c/tools/+/642078 Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
- Document Analyzer.Severity to describe heuristics for how severity should be determined. - Filter out hint diagnostics for closed files. VS Code already suppresses hint diagnostics from the Problems tab, but other clients do not. This change makes the visibility of Hint diagnostics more similar across clients. - Downgrade 'modernize' to Hint level severity. Updates golang/go#70815 Change-Id: If93b57d25ed3eb8dc253a3c7ef016c4148086dc9 Reviewed-on: https://go-review.googlesource.com/c/tools/+/641796 Reviewed-by: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
This CL adds a modernizer pass for slices.Contains{,Func}. Example: func assignTrueBreak(slice []int, needle int) { found := false for _, elem := range slice { // want "Loop can be simplified using strings.Contains" if elem == needle { found = true break } } print(found) } => func assignTrueBreak(slice []int, needle int) { found := slices.Contains(slice, needle) print(found) } Updates golang/go#70815 Change-Id: I72ad1c099481b6c9ae6f732e2d81674a98b79a9f Reviewed-on: https://go-review.googlesource.com/c/tools/+/640576 Auto-Submit: Alan Donovan <[email protected]> Reviewed-by: Robert Findley <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Commit-Queue: Alan Donovan <[email protected]>
Would #69820 be a good candidate for a modenizer? |
It's certainly an easy thing to implement. I'm not sure how frequent it is. The summary is: var slice []T
const k
*(*[k]T)(slice) => [k]T(slice) // when used as rvalue https://go.dev/cl/642815 contains a quick stab. |
Change https://go.dev/cl/642815 mentions this issue: |
@adonovan I encountered a bug in the slices.Contains modernizer today. Modernizing using slices.Contains here results in an error: case *ast.CallExpr:
// If cursor is an arg in a callExpr, we don't want control flow highlighting.
if i > 0 {
for _, arg := range n.Args {
if arg == path[i-1] {
return
}
}
} Error is: |
Thanks; I split this out into its own issue: #71313 |
Adds a new modernizer that suggests removing or replacing instances of "omitempty" on struct fields with "omitzero." Example (before): type Foo struct { A struct{ b int } `json:"name,omitempty" } Example (after - replace): type Foo struct { A struct{ b int } `json:"name,omitzero" } Example (after - remove): type Foo struct { A struct{ b int } `json:"name" } Updates golang/go#70815 Change-Id: I7d651880340d24929ea5cae4751557a1f60e5f8e Reviewed-on: https://go-review.googlesource.com/c/tools/+/640041 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]>
Made that a sub-issue of this one. Neat! We're living in the future. |
Adds a new modernizer that suggests replacing instances of append(s[:i], s[i+k:]...) with slices.Delete(s, i, i+k) Handles other variations like append(s[:i-1], s[i:]...) and append(s[:i+2], s[i+3:]...) Updates golang/go#70815 Change-Id: I71981d6e8d6973bca17153b95f2eb9f1f229522d Reviewed-on: https://go-review.googlesource.com/c/tools/+/641357 Reviewed-by: Alan Donovan <[email protected]> Reviewed-by: Robert Findley <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
A modernization I often do by hand is using {strings,bytes}.Cut{,Prefix,Suffix}. |
It doesn't turn up a single instance in the entire k8s codebase (~3MLoC), so the juice is not worth the squeeze. |
😅 Thank you for testing that out. |
Change https://go.dev/cl/646916 mentions this issue: |
Would |
@apocelipes see #71270 |
This CL adds a modernizer for 3-clause for loops that offers a fix to replace them with go1.22 "range n" loops. Updates golang/go#70815 Change-Id: I347179b8a308f380a9a894aa811ced66f7605df1 Reviewed-on: https://go-review.googlesource.com/c/tools/+/646916 Auto-Submit: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]>
Change https://go.dev/cl/647355 mentions this issue: |
By moving the main.go file, gopls users will be able to run $ go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix after the gopls release to apply all modernizer fixes en masse. Updates golang/go#70815 Change-Id: I25352b7b77653c177310dfea7a050741949890f9 Reviewed-on: https://go-review.googlesource.com/c/tools/+/647355 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]>
When I tried to run this, I got an error. Is this expected?
|
Yes, it is expected: gopls release tags are on a branch that doesn't have the Also: If building from head, beware that the three-way merge CL hasn't landed yet, so -fix may make a mess of things. |
Between generics, iterators, min and max, new standard packages such as
slices
,maps
, andcmp
, there are a large number of new ways to write Go code more concisely and no less clearly. We should develop "modernizer" analyzer(s) that identify such opportunities and offer suggested fixes.Many of these are already implemented in
staticcheck
(see S1000 et seq); we would just need to enable them.When the appropriate fix is to inline a call to a deprecated function whose body illustrates the recommended approach (e.g. a call to a more modern function, as in the case of the functions in the golang.org/x/exp/maps package), these will be handled by annotating the deprecated function as prescribed by proposal #32816, and letting the inliner take care of it.
Examples:
return false
andreturn true
steps in the slices package as wildcards that match "equal and opposite" actions--not just return statements--in the user code. (CL 640576)maps.Keys(m) + slices.Collect (or loop equivalent of Keys+Collect) + sort ->slices.Sorted(maps.Keys(m))
. Eliminate temporaries when used once inrange _
. Downside: de-optimizes preallocation of correct array size; perhaps best left until resolution of proposal: maps: helper to loop over the maps in predictable order #68598.append(s[:i], s[i+k:]...)
->slices.Delete(s, i, i+k)
, where k is a non-negative constantawkward logic in slice.Sort's less function →if cmp := cmp.Compare(x, y); cmp != 0 { return cmp < 0 }
sort.Slice -> slices.SortFunc, eliminating the indicesSetFinalizer → AddCleanupuse strings.Lines instead of strings.Split("\n") (but: "\r"?!) or text.scanner(strings.NewReader)/Scan/Text[]byte(fmt.Sprintf...)
→fmt.Appendf(nil, ...)
(https://go.dev/cl/638436)implementing {Text,Binary}Appender for types that currently implement {Text,Binary}Marshalerctx, cancel := context.WithCancel(context.Background()); defer cancel()
in tests withctx := t.Context()
.for i := 0; i < n; i++ {}
=>for i := range n {}
(CL 646916)They should of course all respect the effective version of Go determined by go.mod and build tags.
@aclements
The text was updated successfully, but these errors were encountered: