Skip to content

Commit d12d98f

Browse files
Merge branch 'main' of github.com:karamaru-alpha/copyloopvar into update-analyzer-doc
2 parents 510ad94 + b40a394 commit d12d98f

File tree

9 files changed

+160
-89
lines changed

9 files changed

+160
-89
lines changed

Diff for: .github/workflows/ci.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ jobs:
2222
- name: Run test
2323
run: go test -v ./...
2424
- name: Run golangci-lint
25-
uses: golangci/golangci-lint-action@v4
25+
uses: golangci/golangci-lint-action@v6
2626
with:
27-
version: v1.56
27+
version: v1.62

Diff for: copyloopvar.go

+36-8
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,8 @@ func checkRangeStmt(pass *analysis.Pass, rangeStmt *ast.RangeStmt) {
7777
continue
7878
}
7979
}
80-
pass.Report(analysis.Diagnostic{
81-
Pos: assignStmt.Pos(),
82-
Message: fmt.Sprintf(`The copy of the 'for' variable "%s" can be deleted (Go 1.22+)`, right.Name),
83-
})
80+
81+
report(pass, assignStmt, right, i)
8482
}
8583
}
8684
}
@@ -124,10 +122,40 @@ func checkForStmt(pass *analysis.Pass, forStmt *ast.ForStmt) {
124122
continue
125123
}
126124
}
127-
pass.Report(analysis.Diagnostic{
128-
Pos: assignStmt.Pos(),
129-
Message: fmt.Sprintf(`The copy of the 'for' variable "%s" can be deleted (Go 1.22+)`, right.Name),
130-
})
125+
126+
report(pass, assignStmt, right, i)
131127
}
132128
}
133129
}
130+
131+
func report(pass *analysis.Pass, assignStmt *ast.AssignStmt, right *ast.Ident, i int) {
132+
diagnostic := analysis.Diagnostic{
133+
Pos: assignStmt.Pos(),
134+
Message: fmt.Sprintf(`The copy of the 'for' variable "%s" can be deleted (Go 1.22+)`, right.Name),
135+
}
136+
137+
if i == 1 && isSimpleAssignStmt(assignStmt, right) {
138+
diagnostic.SuggestedFixes = append(diagnostic.SuggestedFixes, analysis.SuggestedFix{
139+
TextEdits: []analysis.TextEdit{{
140+
Pos: assignStmt.Pos(),
141+
End: assignStmt.End(),
142+
NewText: nil,
143+
}},
144+
})
145+
}
146+
147+
pass.Report(diagnostic)
148+
}
149+
150+
func isSimpleAssignStmt(assignStmt *ast.AssignStmt, rhs *ast.Ident) bool {
151+
if len(assignStmt.Lhs) != 1 {
152+
return false
153+
}
154+
155+
lhs, ok := assignStmt.Lhs[0].(*ast.Ident)
156+
if !ok {
157+
return false
158+
}
159+
160+
return rhs == lhs
161+
}

Diff for: copyloopvar_test.go

+30-13
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,39 @@ package copyloopvar
33
import (
44
"testing"
55

6-
"github.com/gostaticanalysis/testutil"
76
"golang.org/x/tools/go/analysis/analysistest"
87
)
98

109
func TestAnalyzer(t *testing.T) {
11-
t.Run("basic", func(t *testing.T) {
12-
testdata := testutil.WithModules(t, analysistest.TestData(), nil)
13-
analysistest.Run(t, testdata, NewAnalyzer(), "basic")
14-
})
10+
testCases := []struct {
11+
desc string
12+
dir string
13+
options map[string]string
14+
}{
15+
{
16+
desc: "basic",
17+
dir: "basic",
18+
},
19+
{
20+
desc: "check-alias",
21+
dir: "checkalias",
22+
options: map[string]string{
23+
"check-alias": "true",
24+
},
25+
},
26+
}
1527

16-
t.Run("check-alias", func(t *testing.T) {
17-
analyzer := NewAnalyzer()
18-
if err := analyzer.Flags.Set("check-alias", "true"); err != nil {
19-
t.Error(err)
20-
}
21-
testdata := testutil.WithModules(t, analysistest.TestData(), nil)
22-
analysistest.Run(t, testdata, analyzer, "checkalias")
23-
})
28+
for _, test := range testCases {
29+
t.Run(test.desc, func(t *testing.T) {
30+
analyzer := NewAnalyzer()
31+
32+
for k, v := range test.options {
33+
if err := analyzer.Flags.Set(k, v); err != nil {
34+
t.Error(err)
35+
}
36+
}
37+
38+
analysistest.RunWithSuggestedFixes(t, analysistest.TestData(), analyzer, test.dir)
39+
})
40+
}
2441
}

Diff for: go.mod

+2-12
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,6 @@ module github.com/karamaru-alpha/copyloopvar
22

33
go 1.21
44

5-
require (
6-
github.com/gostaticanalysis/testutil v0.4.0
7-
golang.org/x/tools v0.18.0
8-
)
5+
require golang.org/x/tools v0.18.0
96

10-
require (
11-
github.com/hashicorp/go-version v1.2.1 // indirect
12-
github.com/otiai10/copy v1.2.0 // indirect
13-
github.com/tenntenn/modver v1.0.1 // indirect
14-
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 // indirect
15-
golang.org/x/mod v0.15.0 // indirect
16-
golang.org/x/text v0.3.8 // indirect
17-
)
7+
require golang.org/x/mod v0.15.0 // indirect

Diff for: go.sum

-48
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,6 @@
1-
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
2-
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
3-
github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY=
4-
github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU=
5-
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
6-
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
7-
github.com/josharian/txtarfs v0.0.0-20210218200122-0702f000015a h1:8NZHLa6Gp0hW6xJ0c3F1Kse7dJw30fOcDzHuF9sLbnE=
8-
github.com/josharian/txtarfs v0.0.0-20210218200122-0702f000015a/go.mod h1:izVPOvVRsHiKkeGCT6tYBNWyDVuzj9wAaBb5R9qamfw=
9-
github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k=
10-
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
11-
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
12-
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
13-
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
14-
github.com/otiai10/mint v1.3.1 h1:BCmzIS3n71sGfHB5NMNDB3lHYPz8fWSkCAErHed//qc=
15-
github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
16-
github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA=
17-
github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0=
18-
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag=
19-
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
20-
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
21-
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
22-
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
23-
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
24-
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
25-
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
261
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
272
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
28-
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
29-
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
30-
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
31-
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
32-
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
333
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
344
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
35-
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
36-
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
37-
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
38-
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
39-
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
40-
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
41-
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
42-
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
43-
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
44-
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
45-
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
46-
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
47-
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
48-
golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
495
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
506
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
51-
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
52-
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
53-
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
54-
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

Diff for: testdata/src/basic/go.mod

-3
This file was deleted.

Diff for: testdata/src/basic/main.go.golden

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package main
2+
3+
func main() {
4+
for i, v := range []int{1, 2, 3} {
5+
// want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
6+
_i := i
7+
// want `The copy of the 'for' variable "v" can be deleted \(Go 1\.22\+\)`
8+
_v := v
9+
a, i := 1, i // want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
10+
b, _i := 1, i
11+
c, v := 1, v // want `The copy of the 'for' variable "v" can be deleted \(Go 1\.22\+\)`
12+
d, _v := 1, v
13+
e := false
14+
_, _, _, _, _, _, _, _, _ = i, _i, v, _v, a, b, c, d, e
15+
}
16+
17+
for i, j := 1, 1; i+j <= 3; i++ {
18+
// want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
19+
_i := i
20+
// want `The copy of the 'for' variable "j" can be deleted \(Go 1\.22\+\)`
21+
_j := j
22+
a, i := 1, i // want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
23+
b, _i := 1, i
24+
c, j := 1, j // want `The copy of the 'for' variable "j" can be deleted \(Go 1\.22\+\)`
25+
d, _j := 1, j
26+
e := false
27+
_, _, _, _, _, _, _, _, _ = i, _i, j, _j, a, b, c, d, e
28+
}
29+
30+
for i := range []int{1, 2, 3} {
31+
// want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
32+
_i := i
33+
a, i := 1, i // want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
34+
b, _i := 1, i
35+
c := false
36+
_, _, _, _, _ = i, _i, a, b, c
37+
}
38+
39+
var t struct {
40+
Bool bool
41+
}
42+
for _, t.Bool = range []bool{true, false} {
43+
t.Bool = t.Bool // NOTE: ignore
44+
}
45+
}

Diff for: testdata/src/checkalias/go.mod

-3
This file was deleted.

Diff for: testdata/src/checkalias/main.go.golden

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package main
2+
3+
func main() {
4+
for i, v := range []int{1, 2, 3} {
5+
// want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
6+
_i := i // want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
7+
// want `The copy of the 'for' variable "v" can be deleted \(Go 1\.22\+\)`
8+
_v := v // want `The copy of the 'for' variable "v" can be deleted \(Go 1\.22\+\)`
9+
a, i := 1, i // want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
10+
b, _i := 1, i // want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
11+
c, v := 1, v // want `The copy of the 'for' variable "v" can be deleted \(Go 1\.22\+\)`
12+
d, _v := 1, v // want `The copy of the 'for' variable "v" can be deleted \(Go 1\.22\+\)`
13+
e := false
14+
_, _, _, _, _, _, _, _, _ = i, _i, v, _v, a, b, c, d, e
15+
}
16+
17+
for i, j := 1, 1; i+j <= 3; i++ {
18+
// want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
19+
_i := i // want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
20+
// want `The copy of the 'for' variable "j" can be deleted \(Go 1\.22\+\)`
21+
_j := j // want `The copy of the 'for' variable "j" can be deleted \(Go 1\.22\+\)`
22+
a, i := 1, i // want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
23+
b, _i := 1, i // want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
24+
c, j := 1, j // want `The copy of the 'for' variable "j" can be deleted \(Go 1\.22\+\)`
25+
d, _j := 1, j // want `The copy of the 'for' variable "j" can be deleted \(Go 1\.22\+\)`
26+
e := false
27+
_, _, _, _, _, _, _, _, _ = i, _i, j, _j, a, b, c, d, e
28+
}
29+
30+
for i := range []int{1, 2, 3} {
31+
// want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
32+
_i := i // want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
33+
a, i := 1, i // want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
34+
b, _i := 1, i // want `The copy of the 'for' variable "i" can be deleted \(Go 1\.22\+\)`
35+
c := false
36+
_, _, _, _, _ = i, _i, a, b, c
37+
}
38+
39+
var t struct {
40+
Bool bool
41+
}
42+
for _, t.Bool = range []bool{true, false} {
43+
t.Bool = t.Bool // NOTE: ignore
44+
}
45+
}

0 commit comments

Comments
 (0)