diff --git a/.golangci.next.reference.yml b/.golangci.next.reference.yml index c4e23bb0cbd6f..cc2e6ca66ddf3 100644 --- a/.golangci.next.reference.yml +++ b/.golangci.next.reference.yml @@ -2534,6 +2534,7 @@ linters: - exportloopref - forbidigo - forcetypeassert + - foreshadow - funlen - gci - ginkgolinter @@ -2647,6 +2648,7 @@ linters: - exportloopref - forbidigo - forcetypeassert + - foreshadow - funlen - gci - ginkgolinter diff --git a/.golangci.reference.yml b/.golangci.reference.yml index c4e23bb0cbd6f..cc2e6ca66ddf3 100644 --- a/.golangci.reference.yml +++ b/.golangci.reference.yml @@ -2534,6 +2534,7 @@ linters: - exportloopref - forbidigo - forcetypeassert + - foreshadow - funlen - gci - ginkgolinter @@ -2647,6 +2648,7 @@ linters: - exportloopref - forbidigo - forcetypeassert + - foreshadow - funlen - gci - ginkgolinter diff --git a/go.mod b/go.mod index 09e91b469e67e..68f977cd19813 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/Antonboom/nilnil v0.1.7 github.com/Antonboom/testifylint v1.2.0 github.com/BurntSushi/toml v1.3.2 + github.com/Crocmagnon/foreshadow v0.1.2 github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0 github.com/OpenPeeDeeP/depguard/v2 v2.2.0 diff --git a/go.sum b/go.sum index 805c22e514d64..687f42d5db9e0 100644 --- a/go.sum +++ b/go.sum @@ -49,6 +49,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Crocmagnon/foreshadow v0.1.2 h1:N07hW4p+k7HrF2+N59nN0QnoBv6Iw/yDHtGSQDIPGU0= +github.com/Crocmagnon/foreshadow v0.1.2/go.mod h1:zJ/Zjzr27lYG8Y9GrCdgPzDnd24X9HKQAGx1yDHmTZc= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0 h1:sATXp1x6/axKxz2Gjxv8MALP0bXaNRfQinEwyfMcx8c= diff --git a/pkg/golinters/foreshadow.go b/pkg/golinters/foreshadow.go new file mode 100644 index 0000000000000..71ef83dba55cb --- /dev/null +++ b/pkg/golinters/foreshadow.go @@ -0,0 +1,17 @@ +package golinters + +import ( + "github.com/Crocmagnon/foreshadow/pkg/analyzer" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/goanalysis" +) + +func NewForeshadow() *goanalysis.Linter { + return goanalysis.NewLinter( + "foreshadow", + "Enforces context shadowing inside loops", + []*analysis.Analyzer{analyzer.Analyzer}, + nil, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/pkg/lint/lintersdb/builder_linter.go b/pkg/lint/lintersdb/builder_linter.go index 649a82fd7545d..0e645e3951b4a 100644 --- a/pkg/lint/lintersdb/builder_linter.go +++ b/pkg/lint/lintersdb/builder_linter.go @@ -181,6 +181,12 @@ func (b LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { WithPresets(linter.PresetStyle). WithURL("https://github.com/gostaticanalysis/forcetypeassert"), + linter.NewConfig(golinters.NewForeshadow()). + WithSince("1.58.0"). + WithPresets(linter.PresetPerformance). + WithLoadForGoAnalysis(). + WithURL("https://github.com/Crocmagnon/foreshadow"), + linter.NewConfig(golinters.NewFunlen(&cfg.LintersSettings.Funlen)). WithSince("v1.18.0"). WithPresets(linter.PresetComplexity). diff --git a/test/testdata/foreshadow.go b/test/testdata/foreshadow.go new file mode 100644 index 0000000000000..1c5d315193f83 --- /dev/null +++ b/test/testdata/foreshadow.go @@ -0,0 +1,33 @@ +//golangcitest:args -Eforeshadow +package testdata + +import "context" + +func example() { + ctx := context.Background() + + for i := 0; i < 10; i++ { + ctx := context.WithValue(ctx, "key", i) + ctx = context.WithValue(ctx, "other", "val") + } + + for i := 0; i < 10; i++ { + ctx = context.WithValue(ctx, "key", i) // want "context not shadowed in loop" + ctx = context.WithValue(ctx, "other", "val") + } + + for item := range []string{"one", "two", "three"} { + ctx = wrapContext(ctx) // want "context not shadowed in loop" + ctx := context.WithValue(ctx, "key", item) + ctx = wrapContext(ctx) + } + + for { + ctx = wrapContext(ctx) // want "context not shadowed in loop" + break + } +} + +func wrapContext(ctx context.Context) context.Context { + return context.WithoutCancel(ctx) +}