Skip to content

Commit ff03c59

Browse files
committed
gopls/internal/analysis/modernize: append -> bytes.Clone
This CL causes appendclipped to offer bytes.Clone in place of slices.Clone where the file already imports bytes but not slices. + test Updates golang/go#70815 Change-Id: I049698c3d5b8acf46abaa42ab34d72548a012a1a Reviewed-on: https://go-review.googlesource.com/c/tools/+/653455 LUCI-TryBot-Result: Go LUCI <[email protected]> Commit-Queue: Alan Donovan <[email protected]> Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Alan Donovan <[email protected]>
1 parent 1cc80ad commit ff03c59

File tree

3 files changed

+50
-5
lines changed

3 files changed

+50
-5
lines changed

gopls/internal/analysis/modernize/slices.go

+28-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"go/ast"
1313
"go/types"
1414
"slices"
15+
"strconv"
1516

1617
"golang.org/x/tools/go/analysis"
1718
"golang.org/x/tools/go/analysis/passes/inspect"
@@ -27,6 +28,10 @@ import (
2728
// with a call to go1.21's slices.Concat(base, a, b, c), or simpler
2829
// replacements such as slices.Clone(a) in degenerate cases.
2930
//
31+
// We offer bytes.Clone in preference to slices.Clone where
32+
// appropriate, if the package already imports "bytes";
33+
// their behaviors are identical.
34+
//
3035
// The base expression must denote a clipped slice (see [isClipped]
3136
// for definition), otherwise the replacement might eliminate intended
3237
// side effects to the base slice's array.
@@ -41,7 +46,8 @@ import (
4146
// The fix does not always preserve nilness the of base slice when the
4247
// addends (a, b, c) are all empty.
4348
func appendclipped(pass *analysis.Pass) {
44-
if pass.Pkg.Path() == "slices" {
49+
switch pass.Pkg.Path() {
50+
case "slices", "bytes":
4551
return
4652
}
4753

@@ -94,15 +100,32 @@ func appendclipped(pass *analysis.Pass) {
94100
}
95101
}
96102

97-
// append(zerocap, s...) -> slices.Clone(s)
98-
_, prefix, importEdits := analysisinternal.AddImport(info, file, "slices", "slices", "Clone", call.Pos())
103+
// If the slice type is []byte, and the file imports
104+
// "bytes" but not "slices", prefer the (behaviorally
105+
// identical) bytes.Clone for local consistency.
106+
// https://go.dev/issue/70815#issuecomment-2671572984
107+
fileImports := func(path string) bool {
108+
return slices.ContainsFunc(file.Imports, func(spec *ast.ImportSpec) bool {
109+
value, _ := strconv.Unquote(spec.Path.Value)
110+
return value == path
111+
})
112+
}
113+
clonepkg := cond(
114+
types.Identical(info.TypeOf(call), byteSliceType) &&
115+
!fileImports("slices") && fileImports("bytes"),
116+
"bytes",
117+
"slices")
118+
119+
// append(zerocap, s...) -> slices.Clone(s) or bytes.Clone(s)
120+
_, prefix, importEdits := analysisinternal.AddImport(info, file, clonepkg, clonepkg, "Clone", call.Pos())
121+
message := fmt.Sprintf("Replace append with %s.Clone", clonepkg)
99122
pass.Report(analysis.Diagnostic{
100123
Pos: call.Pos(),
101124
End: call.End(),
102125
Category: "slicesclone",
103-
Message: "Replace append with slices.Clone",
126+
Message: message,
104127
SuggestedFixes: []analysis.SuggestedFix{{
105-
Message: "Replace append with slices.Clone",
128+
Message: message,
106129
TextEdits: append(importEdits, []analysis.TextEdit{{
107130
Pos: call.Pos(),
108131
End: call.End(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package appendclipped
2+
3+
import (
4+
"bytes"
5+
)
6+
7+
var _ bytes.Buffer
8+
9+
func _(b []byte) {
10+
print(append([]byte{}, b...)) // want "Replace append with bytes.Clone"
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package appendclipped
2+
3+
import (
4+
"bytes"
5+
)
6+
7+
var _ bytes.Buffer
8+
9+
func _(b []byte) {
10+
print(bytes.Clone(b)) // want "Replace append with bytes.Clone"
11+
}

0 commit comments

Comments
 (0)