From 8215d0de5ff59c35dfa20fb91b6991cc0915863c Mon Sep 17 00:00:00 2001 From: Fata Nugraha Date: Sun, 31 Jul 2022 01:43:13 +0800 Subject: [PATCH 1/6] Add noloopclosure --- .golangci.reference.yml | 1 + go.mod | 7 +++-- go.sum | 14 +++++---- pkg/golinters/noloopclosure.go | 20 +++++++++++++ pkg/lint/lintersdb/manager.go | 6 ++++ test/testdata/noloopclosure.go | 54 ++++++++++++++++++++++++++++++++++ 6 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 pkg/golinters/noloopclosure.go create mode 100644 test/testdata/noloopclosure.go diff --git a/.golangci.reference.yml b/.golangci.reference.yml index dd1459c6b2e5..4b35f949e5c0 100644 --- a/.golangci.reference.yml +++ b/.golangci.reference.yml @@ -1903,6 +1903,7 @@ linters: - nilnil - nlreturn - noctx + - noloopclosure - nolintlint - nonamedreturns - nosnakecase diff --git a/go.mod b/go.mod index b8a76694618f..94967125e816 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( github.com/daixiang0/gci v0.4.3 github.com/denis-tingaikin/go-header v0.4.3 github.com/esimonov/ifshort v1.0.4 + github.com/fatanugraha/noloopclosure v0.1.0 github.com/fatih/color v1.13.0 github.com/firefart/nonamedreturns v1.0.4 github.com/fzipp/gocyclo v0.6.0 @@ -101,7 +102,7 @@ require ( github.com/yagipy/maintidx v1.0.0 github.com/yeya24/promlinter v0.2.0 gitlab.com/bosi/decorder v0.2.2 - golang.org/x/tools v0.1.12-0.20220628192153-7743d1d949f1 + golang.org/x/tools v0.1.12 gopkg.in/yaml.v3 v3.0.1 honnef.co/go/tools v0.3.2 mvdan.cc/gofumpt v0.3.1 @@ -171,8 +172,8 @@ require ( go.uber.org/zap v1.17.0 // indirect golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect + golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect + golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/ini.v1 v1.66.6 // indirect diff --git a/go.sum b/go.sum index 80931b84c0e2..2e14447c577b 100644 --- a/go.sum +++ b/go.sum @@ -154,6 +154,8 @@ github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStB github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw= github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= +github.com/fatanugraha/noloopclosure v0.1.0 h1:kxqwEtwWJoU5fxvgr3nGF8Ky3CZWIay9dB1hfF/3ehA= +github.com/fatanugraha/noloopclosure v0.1.0/go.mod h1:Mi9CiG5QvEgvPLtZLsTzjYwjIDnWAbo10r0BG7JpJII= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= @@ -859,7 +861,7 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -881,8 +883,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -957,8 +960,9 @@ golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1065,8 +1069,8 @@ golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da/go.mod h1:nABZi5QlRsZVlz golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= -golang.org/x/tools v0.1.12-0.20220628192153-7743d1d949f1 h1:NHLFZ56qCjD+0hYY3kE5Wl40Z7q4Gn9Ln/7YU0lsGko= -golang.org/x/tools v0.1.12-0.20220628192153-7743d1d949f1/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/golinters/noloopclosure.go b/pkg/golinters/noloopclosure.go new file mode 100644 index 000000000000..def68ebcb5ce --- /dev/null +++ b/pkg/golinters/noloopclosure.go @@ -0,0 +1,20 @@ +package golinters + +import ( + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" + + "github.com/fatanugraha/noloopclosure" +) + +func NewNoLoopClosure() *goanalysis.Linter { + analyzer := noloopclosure.Analyzer + + return goanalysis.NewLinter( + analyzer.Name, + analyzer.Doc, + []*analysis.Analyzer{analyzer}, + nil, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index 048143018dc4..7a7216494447 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -628,6 +628,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetPerformance, linter.PresetBugs). WithURL("https://github.com/sonatard/noctx"), + linter.NewConfig(golinters.NewNoLoopClosure()). + WithSince("v1.48.0"). + WithLoadForGoAnalysis(). + WithPresets(linter.PresetBugs). + WithURL("https://github.com/fatanugraha/noloopclosure"), + linter.NewConfig(golinters.NewNoNamedReturns(noNamedReturnsCfg)). WithSince("v1.46.0"). WithLoadForGoAnalysis(). diff --git a/test/testdata/noloopclosure.go b/test/testdata/noloopclosure.go new file mode 100644 index 000000000000..b504bd682197 --- /dev/null +++ b/test/testdata/noloopclosure.go @@ -0,0 +1,54 @@ +//golangcitest:args -Enoloopclosure +package testdata + +import _ "fmt" + +func noloopclosureForLoop() { + for i := 0; i < 5; i++ { + _ = i + } + + for false { + } + + for i := 0; i < 5; i++ { + _ = func() { + _ = i // ERROR "found reference to loop variable `i`. Consider to duplicate variable `i` before using it inside the function closure." + } + } + + k := 5 + for i, j := 0, 0; i < j; i++ { + _ = func() { + _ = k + } + + _ = func() { + _, _ = i, j // ERROR "found reference to loop variable `i`. Consider to duplicate variable `i` before using it inside the function closure." + } + } +} + +func noloopclosureRangeLoop() { + for k, v := range map[string]int{} { + _ = func() { + _ = k // ERROR "found reference to loop variable `k`. Consider to duplicate variable `k` before using it inside the function closure." + _ = v // ERROR "found reference to loop variable `v`. Consider to duplicate variable `v` before using it inside the function closure." + } + } + + for _, v := range map[string]int{} { + _ = func() { + _ = v // ERROR "found reference to loop variable `v`. Consider to duplicate variable `v` before using it inside the function closure." + } + } + + for k := range map[string]int{} { + _ = func() { + _ = k // ERROR "found reference to loop variable `k`. Consider to duplicate variable `k` before using it inside the function closure." + } + } + + for range map[string]int{} { + } +} From dc68a3c01c715afe6b36a46ad8d5ca25cea74fba Mon Sep 17 00:00:00 2001 From: Fata Nugraha Date: Sun, 31 Jul 2022 02:16:36 +0800 Subject: [PATCH 2/6] Fix ordering --- .golangci.reference.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.golangci.reference.yml b/.golangci.reference.yml index 4b35f949e5c0..2525d07a06d1 100644 --- a/.golangci.reference.yml +++ b/.golangci.reference.yml @@ -1903,8 +1903,8 @@ linters: - nilnil - nlreturn - noctx - - noloopclosure - nolintlint + - noloopclosure - nonamedreturns - nosnakecase - nosprintfhostport @@ -2006,6 +2006,7 @@ linters: - nlreturn - noctx - nolintlint + - noloopclosure - nonamedreturns - nosnakecase - nosprintfhostport From 52ec1f66e1ac3940dcf547f58e2edb91056e8758 Mon Sep 17 00:00:00 2001 From: Fata Nugraha Date: Tue, 30 Aug 2022 00:18:21 +0800 Subject: [PATCH 3/6] Upgrade noloopclosure version --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 94967125e816..d96b10907131 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/daixiang0/gci v0.4.3 github.com/denis-tingaikin/go-header v0.4.3 github.com/esimonov/ifshort v1.0.4 - github.com/fatanugraha/noloopclosure v0.1.0 + github.com/fatanugraha/noloopclosure v0.1.1 github.com/fatih/color v1.13.0 github.com/firefart/nonamedreturns v1.0.4 github.com/fzipp/gocyclo v0.6.0 diff --git a/go.sum b/go.sum index 2e14447c577b..c4463b59c9b1 100644 --- a/go.sum +++ b/go.sum @@ -156,6 +156,8 @@ github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw= github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= github.com/fatanugraha/noloopclosure v0.1.0 h1:kxqwEtwWJoU5fxvgr3nGF8Ky3CZWIay9dB1hfF/3ehA= github.com/fatanugraha/noloopclosure v0.1.0/go.mod h1:Mi9CiG5QvEgvPLtZLsTzjYwjIDnWAbo10r0BG7JpJII= +github.com/fatanugraha/noloopclosure v0.1.1 h1:AhepjAikNpk50qTZoipHZqeZtnyKT/C2Tk5dGn7nC+A= +github.com/fatanugraha/noloopclosure v0.1.1/go.mod h1:Mi9CiG5QvEgvPLtZLsTzjYwjIDnWAbo10r0BG7JpJII= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= From 9fc0133fe509eafd17c112235411711fd38e2c2e Mon Sep 17 00:00:00 2001 From: Fata Nugraha Date: Tue, 30 Aug 2022 03:41:08 +0800 Subject: [PATCH 4/6] Add config --- pkg/config/linters_settings.go | 8 ++++++++ pkg/golinters/noloopclosure.go | 14 ++++++++++++-- pkg/lint/lintersdb/manager.go | 2 ++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/pkg/config/linters_settings.go b/pkg/config/linters_settings.go index b0bc1ac82ffd..0320388d8a33 100644 --- a/pkg/config/linters_settings.go +++ b/pkg/config/linters_settings.go @@ -75,6 +75,9 @@ var defaultLintersSettings = LintersSettings{ Nestif: NestifSettings{ MinComplexity: 5, }, + Noloopclosure: NoloopclosureSettings{ + IncludeTestFiles: false, + }, NoLintLint: NoLintLintSettings{ RequireExplanation: false, AllowLeadingSpace: true, @@ -162,6 +165,7 @@ type LintersSettings struct { Nestif NestifSettings NilNil NilNilSettings Nlreturn NlreturnSettings + Noloopclosure NoloopclosureSettings NoLintLint NoLintLintSettings NoNamedReturns NoNamedReturnsSettings ParallelTest ParallelTestSettings @@ -486,6 +490,10 @@ type NlreturnSettings struct { BlockSize int `mapstructure:"block-size"` } +type NoloopclosureSettings struct { + IncludeTestFiles bool `mapstructure:"include-test-files"` +} + type NoLintLintSettings struct { RequireExplanation bool `mapstructure:"require-explanation"` AllowLeadingSpace bool `mapstructure:"allow-leading-space"` diff --git a/pkg/golinters/noloopclosure.go b/pkg/golinters/noloopclosure.go index def68ebcb5ce..bca7fea23c26 100644 --- a/pkg/golinters/noloopclosure.go +++ b/pkg/golinters/noloopclosure.go @@ -3,18 +3,28 @@ package golinters import ( "golang.org/x/tools/go/analysis" + "github.com/golangci/golangci-lint/pkg/config" "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" "github.com/fatanugraha/noloopclosure" ) -func NewNoLoopClosure() *goanalysis.Linter { +func NewNoLoopClosure(settings *config.NoloopclosureSettings) *goanalysis.Linter { analyzer := noloopclosure.Analyzer + var cfg map[string]map[string]interface{} + if settings != nil { + cfg = map[string]map[string]interface{}{ + analyzer.Name: { + "t": settings.IncludeTestFiles, + }, + } + } + return goanalysis.NewLinter( analyzer.Name, analyzer.Doc, []*analysis.Analyzer{analyzer}, - nil, + cfg, ).WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index 7a7216494447..a963279b255a 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -147,6 +147,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { nestifCfg *config.NestifSettings nilNilCfg *config.NilNilSettings nlreturnCfg *config.NlreturnSettings + noloopclosureCfg *config.NoloopclosureSettings noLintLintCfg *config.NoLintLintSettings noNamedReturnsCfg *config.NoNamedReturnsSettings parallelTestCfg *config.ParallelTestSettings @@ -218,6 +219,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { nestifCfg = &m.cfg.LintersSettings.Nestif nilNilCfg = &m.cfg.LintersSettings.NilNil nlreturnCfg = &m.cfg.LintersSettings.Nlreturn + noloopclosureCfg = &m.cfg.LintersSettings.Noloopclosure noLintLintCfg = &m.cfg.LintersSettings.NoLintLint noNamedReturnsCfg = &m.cfg.LintersSettings.NoNamedReturns preallocCfg = &m.cfg.LintersSettings.Prealloc From 480779d0b5e7a2852bea782bc7572ac75d18a3e1 Mon Sep 17 00:00:00 2001 From: Fata Nugraha Date: Tue, 30 Aug 2022 03:53:28 +0800 Subject: [PATCH 5/6] Update tests --- pkg/lint/lintersdb/manager.go | 2 +- test/testdata/noloopclosure.go | 116 ++++++++++++++++++++++++++++++--- 2 files changed, 108 insertions(+), 10 deletions(-) diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index a963279b255a..de0e807bc847 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -630,7 +630,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetPerformance, linter.PresetBugs). WithURL("https://github.com/sonatard/noctx"), - linter.NewConfig(golinters.NewNoLoopClosure()). + linter.NewConfig(golinters.NewNoLoopClosure(noloopclosureCfg)). WithSince("v1.48.0"). WithLoadForGoAnalysis(). WithPresets(linter.PresetBugs). diff --git a/test/testdata/noloopclosure.go b/test/testdata/noloopclosure.go index b504bd682197..1224f171449a 100644 --- a/test/testdata/noloopclosure.go +++ b/test/testdata/noloopclosure.go @@ -4,27 +4,118 @@ package testdata import _ "fmt" func noloopclosureForLoop() { + for { + + } + + for false { + // noop + } + + for i := 0; ; i++ { + _ = func() { + _ = i // ERROR "found captured reference to loop variable inside a closure" + } + } + + for i := 0; ; { + _ = i + } + for i := 0; i < 5; i++ { _ = i } - for false { + var i int + for i < 5 { + // Note: we ignore the condition clause to reduce false positive. + // Because it's hard to check which variable inside the condition that will be mutated. + _ = func() { + _ = i + } + } + + for i := 0; i < 5; i++ { + _ = func() { + _ = i // ERROR "found captured reference to loop variable inside a closure" + } } for i := 0; i < 5; i++ { + for j := 0; j < 5; j++ { + _ = func() { + _ = i // ERROR "found captured reference to loop variable inside a closure" + _ = j // ERROR "found captured reference to loop variable inside a closure" + } + } + + var j int _ = func() { - _ = i // ERROR "found reference to loop variable `i`. Consider to duplicate variable `i` before using it inside the function closure." + _ = j } } k := 5 - for i, j := 0, 0; i < j; i++ { + for i, j := 0, 0; i < j; i, k = i+1, k+1 { + _ = func() { + // Not okay since it's listed in the PostInit. + _ = k // ERROR "found captured reference to loop variable inside a closure" + } + + _ = func() { + _ = i // ERROR "found captured reference to loop variable inside a closure" + + // Not okay, even if it's not part of the PostInit, as it's very likely that dev will mutate it somehow + // inside the for loop. + _ = j // ERROR "found captured reference to loop variable inside a closure" + } + } + + // Can handle ast.SelectorExpr properly. + x := struct { + A int + B int + }{} + for x.A = 0; x.A < 5; x.A++ { + _ = func() { + _ = x.A // ERROR "found captured reference to loop variable inside a closure" + _ = x.B + } + } + + // Can handle ast.ParenExpr properly. + for (k) = 0; k < 5; k++ { + _ = func() { + _ = k // ERROR "found captured reference to loop variable inside a closure" + } + } + + // Can handle ast.StarExpr properly. + var p *int = new(int) + for *p = 0; *p < 5; (*p)++ { + _ = func() { + _ = *p // ERROR "found captured reference to loop variable inside a closure" + _ = p // ERROR "found captured reference to loop variable inside a closure" + } + } + + // Can handle ast.IndexExpr properly. + arrayOfInt := []int{1, 2, 3} + for arrayOfInt[1] = 0; arrayOfInt[1] < 5; arrayOfInt[1]++ { _ = func() { - _ = k + // Note: we will disallow any captured reference to the array, not just arrayOfInt[1] + // because we cant accurately know which index that is being mutated in compile time. + // + // Generally it's a good practice to not do this anyway hence we raise it as an issue. + _ = arrayOfInt[1] // ERROR "found captured reference to loop variable inside a closure" } + } + mapOfInt := map[int]int{1: 1} + for mapOfInt[1] = 0; mapOfInt[1] < 5; mapOfInt[1]++ { _ = func() { - _, _ = i, j // ERROR "found reference to loop variable `i`. Consider to duplicate variable `i` before using it inside the function closure." + // Note: disallow any captured reference to the map. + _ = mapOfInt[1] // ERROR "found captured reference to loop variable inside a closure" } } } @@ -32,23 +123,30 @@ func noloopclosureForLoop() { func noloopclosureRangeLoop() { for k, v := range map[string]int{} { _ = func() { - _ = k // ERROR "found reference to loop variable `k`. Consider to duplicate variable `k` before using it inside the function closure." - _ = v // ERROR "found reference to loop variable `v`. Consider to duplicate variable `v` before using it inside the function closure." + _ = k // ERROR "found captured reference to loop variable inside a closure" + _ = v // ERROR "found captured reference to loop variable inside a closure" } } for _, v := range map[string]int{} { _ = func() { - _ = v // ERROR "found reference to loop variable `v`. Consider to duplicate variable `v` before using it inside the function closure." + _ = v // ERROR "found captured reference to loop variable inside a closure" } } for k := range map[string]int{} { _ = func() { - _ = k // ERROR "found reference to loop variable `k`. Consider to duplicate variable `k` before using it inside the function closure." + _ = k // ERROR "found captured reference to loop variable inside a closure" } } for range map[string]int{} { } + + x := struct{ A string }{} + for x.A = range map[string]int{} { + _ = func() { + _ = x.A // ERROR "found captured reference to loop variable inside a closure" + } + } } From 84b75b5459713b772c9222101ea746dc2dfa2d64 Mon Sep 17 00:00:00 2001 From: Fata Nugraha Date: Tue, 30 Aug 2022 03:58:59 +0800 Subject: [PATCH 6/6] Update .golangci.reference.yml --- .golangci.reference.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.golangci.reference.yml b/.golangci.reference.yml index 2525d07a06d1..dcaf79cc7289 100644 --- a/.golangci.reference.yml +++ b/.golangci.reference.yml @@ -1148,6 +1148,11 @@ linters-settings: # Default: 1 block-size: 2 + noloopclosure: + # Enable to lint test files (files that has _test.go suffix). + # Default: false + include-test-files: true + nolintlint: # Disable to ensure that all nolint directives actually have an effect. # Default: false