From c2bb25f1a72592ec15bb9e9854b976cd279f7f97 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Fri, 13 Sep 2024 16:23:52 +0200 Subject: [PATCH 1/2] feat: add recv linter --- .golangci.next.reference.yml | 10 +++++++ go.mod | 1 + go.sum | 2 ++ jsonschema/golangci.next.jsonschema.json | 17 ++++++++++++ pkg/config/linters_settings.go | 10 +++++++ pkg/golinters/recv/recv.go | 27 +++++++++++++++++++ pkg/golinters/recv/recv_integration_test.go | 11 ++++++++ pkg/golinters/recv/testdata/recv.go | 22 +++++++++++++++ .../testdata/recv_disable_type_consistency.go | 23 ++++++++++++++++ .../recv_disable_type_consistency.yml | 3 +++ .../recv/testdata/recv_max_name_length.go | 17 ++++++++++++ .../recv/testdata/recv_max_name_length.yml | 3 +++ pkg/lint/lintersdb/builder_linter.go | 7 +++++ 13 files changed, 153 insertions(+) create mode 100644 pkg/golinters/recv/recv.go create mode 100644 pkg/golinters/recv/recv_integration_test.go create mode 100644 pkg/golinters/recv/testdata/recv.go create mode 100644 pkg/golinters/recv/testdata/recv_disable_type_consistency.go create mode 100644 pkg/golinters/recv/testdata/recv_disable_type_consistency.yml create mode 100644 pkg/golinters/recv/testdata/recv_max_name_length.go create mode 100644 pkg/golinters/recv/testdata/recv_max_name_length.yml diff --git a/.golangci.next.reference.yml b/.golangci.next.reference.yml index 4d5d5c88aad3..f770defc48d3 100644 --- a/.golangci.next.reference.yml +++ b/.golangci.next.reference.yml @@ -1540,6 +1540,14 @@ linters-settings: patterns: - ".*" + recv: + # Maximum length for a receiver name. + # Default: 3 + max-name-length: 6 + # Allow to use pointer receiver and non pointer receiver on the same struct. + # Default: true + type-consistency: false + revive: # Maximum number of open files at the same time. # See https://github.com/mgechev/revive#command-line-flags @@ -2689,6 +2697,7 @@ linters: - promlinter - protogetter - reassign + - recv - revive - rowserrcheck - sloglint @@ -2804,6 +2813,7 @@ linters: - promlinter - protogetter - reassign + - recv - revive - rowserrcheck - sloglint diff --git a/go.mod b/go.mod index 051df607ecc0..db20e0cf0fba 100644 --- a/go.mod +++ b/go.mod @@ -67,6 +67,7 @@ require ( github.com/kyoh86/exportloopref v0.1.11 github.com/lasiar/canonicalheader v1.1.1 github.com/ldez/gomoddirectives v0.2.4 + github.com/ldez/recv v0.1.1 github.com/ldez/tagliatelle v0.5.0 github.com/leonklingele/grouper v1.1.2 github.com/lufeee/execinquery v1.2.1 diff --git a/go.sum b/go.sum index a8b2a42c91f2..492a89d4e4b4 100644 --- a/go.sum +++ b/go.sum @@ -343,6 +343,8 @@ github.com/lasiar/canonicalheader v1.1.1 h1:wC+dY9ZfiqiPwAexUApFush/csSPXeIi4Qqy github.com/lasiar/canonicalheader v1.1.1/go.mod h1:cXkb3Dlk6XXy+8MVQnF23CYKWlyA7kfQhSw2CcZtZb0= github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJZ3alg= github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g= +github.com/ldez/recv v0.1.1 h1:X8qarUytSxWvYKBqw0Yp4OaqvVXt/0HykDfkjF5XulY= +github.com/ldez/recv v0.1.1/go.mod h1:I/thYIKCTqjjfuVz8P/jkqeQUl1V5i88qYudsGok6FI= github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo= github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= diff --git a/jsonschema/golangci.next.jsonschema.json b/jsonschema/golangci.next.jsonschema.json index e137b14c6d39..a576eb5b1139 100644 --- a/jsonschema/golangci.next.jsonschema.json +++ b/jsonschema/golangci.next.jsonschema.json @@ -388,6 +388,7 @@ "promlinter", "protogetter", "reassign", + "recv", "revive", "rowserrcheck", "scopelint", @@ -2283,6 +2284,22 @@ } } }, + "recv": { + "type": "object", + "additionalProperties": false, + "properties": { + "max-name-length": { + "description": "Maximum length for a receiver name.", + "type": "integer", + "default": 3 + }, + "type-consistency": { + "description": "Allow to use pointer receiver and non pointer receiver on the same struct.", + "type": "boolean", + "default": true + } + } + }, "nonamedreturns": { "type": "object", "additionalProperties": false, diff --git a/pkg/config/linters_settings.go b/pkg/config/linters_settings.go index 109de42431e1..f90166e5a1a4 100644 --- a/pkg/config/linters_settings.go +++ b/pkg/config/linters_settings.go @@ -137,6 +137,10 @@ var defaultLintersSettings = LintersSettings{ Ignore: "", Qualified: false, }, + Recv: RecvSettings{ + MaxNameLength: 3, + TypeConsistency: true, + }, SlogLint: SlogLintSettings{ NoMixedArgs: true, KVOnly: false, @@ -257,6 +261,7 @@ type LintersSettings struct { Promlinter PromlinterSettings ProtoGetter ProtoGetterSettings Reassign ReassignSettings + Recv RecvSettings Revive ReviveSettings RowsErrCheck RowsErrCheckSettings SlogLint SlogLintSettings @@ -791,6 +796,11 @@ type ReassignSettings struct { Patterns []string `mapstructure:"patterns"` } +type RecvSettings struct { + MaxNameLength int `mapstructure:"max-name-length"` + TypeConsistency bool `mapstructure:"type-consistency"` +} + type ReviveSettings struct { Go string `mapstructure:"-"` MaxOpenFiles int `mapstructure:"max-open-files"` diff --git a/pkg/golinters/recv/recv.go b/pkg/golinters/recv/recv.go new file mode 100644 index 000000000000..6778b2bc671c --- /dev/null +++ b/pkg/golinters/recv/recv.go @@ -0,0 +1,27 @@ +package recv + +import ( + "github.com/ldez/recv" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/goanalysis" +) + +func New(settings *config.RecvSettings) *goanalysis.Linter { + cfg := recv.Config{} + + if settings != nil { + cfg.MaxNameLength = settings.MaxNameLength + cfg.TypeConsistency = settings.TypeConsistency + } + + a := recv.New(cfg) + + return goanalysis.NewLinter( + a.Name, + a.Doc, + []*analysis.Analyzer{a}, + nil, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/pkg/golinters/recv/recv_integration_test.go b/pkg/golinters/recv/recv_integration_test.go new file mode 100644 index 000000000000..e4ecaa8752ea --- /dev/null +++ b/pkg/golinters/recv/recv_integration_test.go @@ -0,0 +1,11 @@ +package recv + +import ( + "testing" + + "github.com/golangci/golangci-lint/test/testshared/integration" +) + +func TestFromTestdata(t *testing.T) { + integration.RunTestdata(t) +} diff --git a/pkg/golinters/recv/testdata/recv.go b/pkg/golinters/recv/testdata/recv.go new file mode 100644 index 000000000000..44c65389b308 --- /dev/null +++ b/pkg/golinters/recv/testdata/recv.go @@ -0,0 +1,22 @@ +//golangcitest:args -Erecv +package testdata + +import "fmt" + +type Foo struct { // want `the methods of "Foo" use different receiver names: f, fo.` + Name string +} + +func (f Foo) A() {} +func (fo Foo) B() {} + +type Bar struct{} // want `the methods of "Bar" use pointer receiver and non pointer receiver.` + +func (b Bar) A() {} +func (b *Bar) B() {} + +type Fuu struct{} + +func (faaa Fuu) A() { // want `the receiver name "faaa" is too long.` + fmt.Println("a") +} diff --git a/pkg/golinters/recv/testdata/recv_disable_type_consistency.go b/pkg/golinters/recv/testdata/recv_disable_type_consistency.go new file mode 100644 index 000000000000..f9300d82a859 --- /dev/null +++ b/pkg/golinters/recv/testdata/recv_disable_type_consistency.go @@ -0,0 +1,23 @@ +//golangcitest:args -Erecv +//golangcitest:config_path testdata/recv_disable_type_consistency.yml +package testdata + +import "fmt" + +type Foo struct { // want `the methods of "Foo" use different receiver names: f, fo.` + Name string +} + +func (f Foo) A() {} +func (fo Foo) B() {} + +type Bar struct{} + +func (b Bar) A() {} +func (b *Bar) B() {} + +type Fuu struct{} + +func (faaa Fuu) A() { // want `the receiver name "faaa" is too long.` + fmt.Println("a") +} diff --git a/pkg/golinters/recv/testdata/recv_disable_type_consistency.yml b/pkg/golinters/recv/testdata/recv_disable_type_consistency.yml new file mode 100644 index 000000000000..c1dff2e3b93d --- /dev/null +++ b/pkg/golinters/recv/testdata/recv_disable_type_consistency.yml @@ -0,0 +1,3 @@ +linters-settings: + recv: + type-consistency: false diff --git a/pkg/golinters/recv/testdata/recv_max_name_length.go b/pkg/golinters/recv/testdata/recv_max_name_length.go new file mode 100644 index 000000000000..114699574eb1 --- /dev/null +++ b/pkg/golinters/recv/testdata/recv_max_name_length.go @@ -0,0 +1,17 @@ +//golangcitest:args -Erecv +//golangcitest:config_path testdata/recv_max_name_length.yml +package testdata + +import "fmt" + +type Fuu struct{} + +func (faaa Fuu) A() { + fmt.Println("a") +} + +type Foo struct{} + +func (faaaaaa Foo) A() { // want `the receiver name "faaaaaa" is too long.` + fmt.Println("a") +} diff --git a/pkg/golinters/recv/testdata/recv_max_name_length.yml b/pkg/golinters/recv/testdata/recv_max_name_length.yml new file mode 100644 index 000000000000..1b112677b2b7 --- /dev/null +++ b/pkg/golinters/recv/testdata/recv_max_name_length.yml @@ -0,0 +1,3 @@ +linters-settings: + recv: + max-name-length: 6 diff --git a/pkg/lint/lintersdb/builder_linter.go b/pkg/lint/lintersdb/builder_linter.go index c06cd9a038cd..7c13f4048b25 100644 --- a/pkg/lint/lintersdb/builder_linter.go +++ b/pkg/lint/lintersdb/builder_linter.go @@ -85,6 +85,7 @@ import ( "github.com/golangci/golangci-lint/pkg/golinters/promlinter" "github.com/golangci/golangci-lint/pkg/golinters/protogetter" "github.com/golangci/golangci-lint/pkg/golinters/reassign" + "github.com/golangci/golangci-lint/pkg/golinters/recv" "github.com/golangci/golangci-lint/pkg/golinters/revive" "github.com/golangci/golangci-lint/pkg/golinters/rowserrcheck" "github.com/golangci/golangci-lint/pkg/golinters/sloglint" @@ -657,6 +658,12 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { WithLoadForGoAnalysis(). WithURL("https://github.com/curioswitch/go-reassign"), + linter.NewConfig(recv.New(&cfg.LintersSettings.Recv)). + WithSince("1.62.0"). + WithPresets(linter.PresetStyle). + WithLoadForGoAnalysis(). + WithURL("https://github.com/ldez/recv"), + linter.NewConfig(revive.New(&cfg.LintersSettings.Revive)). WithSince("v1.37.0"). WithPresets(linter.PresetStyle, linter.PresetMetaLinter). From 6329676c8de624f9adbd0e7096799ec684652b6c Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Fri, 13 Sep 2024 22:08:03 +0200 Subject: [PATCH 2/2] chore: improve messages and docs --- .golangci.next.reference.yml | 2 +- go.mod | 2 +- go.sum | 4 ++-- jsonschema/golangci.next.jsonschema.json | 2 +- pkg/golinters/recv/testdata/recv.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.golangci.next.reference.yml b/.golangci.next.reference.yml index f770defc48d3..31eff76c6f75 100644 --- a/.golangci.next.reference.yml +++ b/.golangci.next.reference.yml @@ -1544,7 +1544,7 @@ linters-settings: # Maximum length for a receiver name. # Default: 3 max-name-length: 6 - # Allow to use pointer receiver and non pointer receiver on the same struct. + # Allow using pointer receiver and non-pointer receiver on the same struct. # Default: true type-consistency: false diff --git a/go.mod b/go.mod index db20e0cf0fba..588138c20449 100644 --- a/go.mod +++ b/go.mod @@ -67,7 +67,7 @@ require ( github.com/kyoh86/exportloopref v0.1.11 github.com/lasiar/canonicalheader v1.1.1 github.com/ldez/gomoddirectives v0.2.4 - github.com/ldez/recv v0.1.1 + github.com/ldez/recv v0.1.2 github.com/ldez/tagliatelle v0.5.0 github.com/leonklingele/grouper v1.1.2 github.com/lufeee/execinquery v1.2.1 diff --git a/go.sum b/go.sum index 492a89d4e4b4..b02938797ec6 100644 --- a/go.sum +++ b/go.sum @@ -343,8 +343,8 @@ github.com/lasiar/canonicalheader v1.1.1 h1:wC+dY9ZfiqiPwAexUApFush/csSPXeIi4Qqy github.com/lasiar/canonicalheader v1.1.1/go.mod h1:cXkb3Dlk6XXy+8MVQnF23CYKWlyA7kfQhSw2CcZtZb0= github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJZ3alg= github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g= -github.com/ldez/recv v0.1.1 h1:X8qarUytSxWvYKBqw0Yp4OaqvVXt/0HykDfkjF5XulY= -github.com/ldez/recv v0.1.1/go.mod h1:I/thYIKCTqjjfuVz8P/jkqeQUl1V5i88qYudsGok6FI= +github.com/ldez/recv v0.1.2 h1:j/1nFLi4wwItCBSYX+fQCIe06IlXP6OhSLdYKJig8Cc= +github.com/ldez/recv v0.1.2/go.mod h1:I/thYIKCTqjjfuVz8P/jkqeQUl1V5i88qYudsGok6FI= github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo= github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= diff --git a/jsonschema/golangci.next.jsonschema.json b/jsonschema/golangci.next.jsonschema.json index a576eb5b1139..50d1bc39bbfb 100644 --- a/jsonschema/golangci.next.jsonschema.json +++ b/jsonschema/golangci.next.jsonschema.json @@ -2294,7 +2294,7 @@ "default": 3 }, "type-consistency": { - "description": "Allow to use pointer receiver and non pointer receiver on the same struct.", + "description": "Allow using pointer receiver and non-pointer receiver on the same struct", "type": "boolean", "default": true } diff --git a/pkg/golinters/recv/testdata/recv.go b/pkg/golinters/recv/testdata/recv.go index 44c65389b308..cbb09808727a 100644 --- a/pkg/golinters/recv/testdata/recv.go +++ b/pkg/golinters/recv/testdata/recv.go @@ -10,7 +10,7 @@ type Foo struct { // want `the methods of "Foo" use different receiver names: f, func (f Foo) A() {} func (fo Foo) B() {} -type Bar struct{} // want `the methods of "Bar" use pointer receiver and non pointer receiver.` +type Bar struct{} // want `the methods of "Bar" use pointer receiver and non-pointer receiver.` func (b Bar) A() {} func (b *Bar) B() {}