From fbc22e1df0586ae79f15d2b4ad0fe57cd1ca85e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 15:28:32 +0000 Subject: [PATCH 1/4] build(deps): bump github.com/jgautheron/goconst from 1.7.1 to 1.8.1 Bumps [github.com/jgautheron/goconst](https://github.com/jgautheron/goconst) from 1.7.1 to 1.8.1. - [Release notes](https://github.com/jgautheron/goconst/releases) - [Commits](https://github.com/jgautheron/goconst/compare/v1.7.1...v1.8.1) --- updated-dependencies: - dependency-name: github.com/jgautheron/goconst dependency-version: 1.8.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 142079fc123d..9557cdc3dcb5 100644 --- a/go.mod +++ b/go.mod @@ -57,7 +57,7 @@ require ( github.com/gostaticanalysis/forcetypeassert v0.2.0 github.com/gostaticanalysis/nilerr v0.1.1 github.com/hashicorp/go-version v1.7.0 - github.com/jgautheron/goconst v1.7.1 + github.com/jgautheron/goconst v1.8.1 github.com/jingyugao/rowserrcheck v1.1.1 github.com/jjti/go-spancheck v0.6.4 github.com/julz/importas v0.2.0 diff --git a/go.sum b/go.sum index 5cfb4c9ad89d..7d65bcaa5c89 100644 --- a/go.sum +++ b/go.sum @@ -331,8 +331,8 @@ github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSo github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= -github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jgautheron/goconst v1.8.1 h1:PPqCYp3K/xlOj5JmIe6O1Mj6r1DbkdbLtR3AJuZo414= +github.com/jgautheron/goconst v1.8.1/go.mod h1:A0oxgBCHy55NQn6sYpO7UdnA9p+h7cPtoOZUmvNIako= github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= github.com/jjti/go-spancheck v0.6.4 h1:Tl7gQpYf4/TMU7AT84MN83/6PutY21Nb9fuQjFTpRRc= From 6aea1df1a78e0d8fe0dde7eaaff8cade868bc3e5 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 9 Apr 2025 04:55:20 +0200 Subject: [PATCH 2/4] chore: update implementation --- .golangci.next.reference.yml | 9 +++- jsonschema/golangci.next.jsonschema.json | 17 ++++++- pkg/config/linters_settings.go | 21 +++++--- pkg/config/loader.go | 11 +++- pkg/golinters/goconst/goconst.go | 51 ++++++++++++------- .../goconst_eval_and_find_duplicates.go | 25 +++++++++ .../goconst_eval_and_find_duplicates.yml | 8 +++ .../goconst_eval_const_expressions.go | 29 +++++++++++ .../goconst_eval_const_expressions.yml | 6 +++ .../testdata/goconst_find_duplicates.go | 29 +++++++++++ .../testdata/goconst_find_duplicates.yml | 6 +++ pkg/lint/lintersdb/builder_linter.go | 1 + 12 files changed, 183 insertions(+), 30 deletions(-) create mode 100644 pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.go create mode 100644 pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.yml create mode 100644 pkg/golinters/goconst/testdata/goconst_eval_const_expressions.go create mode 100644 pkg/golinters/goconst/testdata/goconst_eval_const_expressions.yml create mode 100644 pkg/golinters/goconst/testdata/goconst_find_duplicates.go create mode 100644 pkg/golinters/goconst/testdata/goconst_find_duplicates.yml diff --git a/.golangci.next.reference.yml b/.golangci.next.reference.yml index 6245b6245ba0..13c0b5cf1344 100644 --- a/.golangci.next.reference.yml +++ b/.golangci.next.reference.yml @@ -631,7 +631,14 @@ linters: ignore-calls: false # Exclude strings matching the given regular expression. # Default: "" - ignore-strings: 'foo.+' + ignore-string-values: + - 'foo.+' + # Detects constants with identical values. + # Default: false + find-duplicates: true + # Evaluates of constant expressions like Prefix + "suffix". + # Default: false + eval-const-expressions: true gocritic: # Disable all checks. diff --git a/jsonschema/golangci.next.jsonschema.json b/jsonschema/golangci.next.jsonschema.json index 814c7cfe9c8e..8149984411dd 100644 --- a/jsonschema/golangci.next.jsonschema.json +++ b/jsonschema/golangci.next.jsonschema.json @@ -1487,9 +1487,12 @@ "type": "boolean", "default": true }, - "ignore-strings": { + "ignore-string-values": { "description": "Exclude strings matching the given regular expression", - "type": "string" + "type": "array", + "items": { + "type": "string" + } }, "numbers": { "description": "Search also for duplicated numbers.", @@ -1505,6 +1508,16 @@ "description": "Maximum value, only works with `numbers`", "type": "integer", "default": 3 + }, + "find-duplicates": { + "description": "Detects constants with identical values", + "type": "boolean", + "default": false + }, + "eval-const-expressions": { + "description": "Evaluates of constant expressions like Prefix + \"suffix\"", + "type": "boolean", + "default": false } } }, diff --git a/pkg/config/linters_settings.go b/pkg/config/linters_settings.go index 046645e40f98..16269033c7e9 100644 --- a/pkg/config/linters_settings.go +++ b/pkg/config/linters_settings.go @@ -451,14 +451,19 @@ type GocognitSettings struct { } type GoConstSettings struct { - IgnoreStrings string `mapstructure:"ignore-strings"` - MatchWithConstants bool `mapstructure:"match-constant"` - MinStringLen int `mapstructure:"min-len"` - MinOccurrencesCount int `mapstructure:"min-occurrences"` - ParseNumbers bool `mapstructure:"numbers"` - NumberMin int `mapstructure:"min"` - NumberMax int `mapstructure:"max"` - IgnoreCalls bool `mapstructure:"ignore-calls"` + IgnoreStringValues []string `mapstructure:"ignore-string-values"` + MatchWithConstants bool `mapstructure:"match-constant"` + MinStringLen int `mapstructure:"min-len"` + MinOccurrencesCount int `mapstructure:"min-occurrences"` + ParseNumbers bool `mapstructure:"numbers"` + NumberMin int `mapstructure:"min"` + NumberMax int `mapstructure:"max"` + IgnoreCalls bool `mapstructure:"ignore-calls"` + FindDuplicates bool `mapstructure:"find-duplicates"` + EvalConstExpressions bool `mapstructure:"eval-const-expressions"` + + // Deprecated: use IgnoreStringValues instead. + IgnoreStrings string `mapstructure:"ignore-strings"` } type GoCriticSettings struct { diff --git a/pkg/config/loader.go b/pkg/config/loader.go index ffa02d6bcdb5..19a17e7d71db 100644 --- a/pkg/config/loader.go +++ b/pkg/config/loader.go @@ -190,8 +190,15 @@ func (l *Loader) handleDeprecation() error { return nil } -func (*Loader) handleLinterOptionDeprecations() { - // The function is empty but deprecations will happen in the future. +func (l *Loader) handleLinterOptionDeprecations() { + // Deprecated since v2.1.0. + if l.cfg.Linters.Settings.Goconst.IgnoreStrings != "" { + l.log.Warnf("The configuration option `linters.settings.goconst.ignore-strings` is deprecated, " + + "please use `linters.settings.goconst.ignore-string-values`.") + + l.cfg.Linters.Settings.Goconst.IgnoreStringValues = append(l.cfg.Linters.Settings.Goconst.IgnoreStringValues, + l.cfg.Linters.Settings.Goconst.IgnoreStrings) + } } func (l *Loader) handleEnableOnlyOption() error { diff --git a/pkg/golinters/goconst/goconst.go b/pkg/golinters/goconst/goconst.go index 26196f6929d6..f3af64625243 100644 --- a/pkg/golinters/goconst/goconst.go +++ b/pkg/golinters/goconst/goconst.go @@ -48,19 +48,21 @@ func New(settings *config.GoConstSettings) *goanalysis.Linter { nil, ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) + }).WithLoadMode(goanalysis.LoadModeTypesInfo) } func runGoconst(pass *analysis.Pass, settings *config.GoConstSettings) ([]goanalysis.Issue, error) { cfg := goconstAPI.Config{ - IgnoreStrings: settings.IgnoreStrings, - MatchWithConstants: settings.MatchWithConstants, - MinStringLength: settings.MinStringLen, - MinOccurrences: settings.MinOccurrencesCount, - ParseNumbers: settings.ParseNumbers, - NumberMin: settings.NumberMin, - NumberMax: settings.NumberMax, - ExcludeTypes: map[goconstAPI.Type]bool{}, + IgnoreStrings: settings.IgnoreStringValues, + MatchWithConstants: settings.MatchWithConstants, + MinStringLength: settings.MinStringLen, + MinOccurrences: settings.MinOccurrencesCount, + ParseNumbers: settings.ParseNumbers, + NumberMin: settings.NumberMin, + NumberMax: settings.NumberMax, + ExcludeTypes: map[goconstAPI.Type]bool{}, + FindDuplicates: settings.FindDuplicates, + EvalConstExpressions: settings.EvalConstExpressions, // Should be managed with `linters.exclusions.rules`. IgnoreTests: false, @@ -70,7 +72,7 @@ func runGoconst(pass *analysis.Pass, settings *config.GoConstSettings) ([]goanal cfg.ExcludeTypes[goconstAPI.Call] = true } - lintIssues, err := goconstAPI.Run(pass.Files, pass.Fset, &cfg) + lintIssues, err := goconstAPI.Run(pass.Files, pass.Fset, pass.TypesInfo, &cfg) if err != nil { return nil, err } @@ -80,17 +82,32 @@ func runGoconst(pass *analysis.Pass, settings *config.GoConstSettings) ([]goanal } res := make([]goanalysis.Issue, 0, len(lintIssues)) - for _, i := range lintIssues { - text := fmt.Sprintf("string %s has %d occurrences", internal.FormatCode(i.Str, nil), i.OccurrencesCount) + for i := range lintIssues { + issue := &lintIssues[i] - if i.MatchingConst == "" { - text += ", make it a constant" - } else { - text += fmt.Sprintf(", but such constant %s already exists", internal.FormatCode(i.MatchingConst, nil)) + var text string + + switch { + case issue.OccurrencesCount > 0: + text = fmt.Sprintf("string %s has %d occurrences", internal.FormatCode(issue.Str, nil), issue.OccurrencesCount) + + if issue.MatchingConst == "" { + text += ", make it a constant" + } else { + text += fmt.Sprintf(", but such constant %s already exists", internal.FormatCode(issue.MatchingConst, nil)) + } + + case issue.DuplicateConst != "": + text = fmt.Sprintf("This constant is a duplicate of %s at %s", + internal.FormatCode(issue.DuplicateConst, nil), + issue.DuplicatePos.String()) + + default: + continue } res = append(res, goanalysis.NewIssue(&result.Issue{ - Pos: i.Pos, + Pos: issue.Pos, Text: text, FromLinter: linterName, }, pass)) diff --git a/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.go b/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.go new file mode 100644 index 000000000000..24d43af14df6 --- /dev/null +++ b/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.go @@ -0,0 +1,25 @@ +//golangcitest:args -Egoconst +//golangcitest:config_path testdata/goconst_eval_and_find_duplicates.yml +package testdata + +import "fmt" + +const ( + envPrefix = "FOO_" + EnvUser = envPrefix + "USER" + EnvPassword = envPrefix + "PASSWORD" +) + +const EnvUserFull = "FOO_USER" // want "This constant is a duplicate of `EnvUser` at goconst_eval_and_find_duplicates.go:9:16" + +const KiB = 1 << 10 + +func _() { + fmt.Println(envPrefix, EnvUser, EnvPassword, EnvUserFull) + + const kilobytes = 1024 // want "This constant is a duplicate of `KiB` at goconst_eval_and_find_duplicates.go:15:13" + fmt.Println(kilobytes) + + kib := 1024 + fmt.Println(kib) +} diff --git a/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.yml b/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.yml new file mode 100644 index 000000000000..445d6b77263d --- /dev/null +++ b/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.yml @@ -0,0 +1,8 @@ +version: "2" + +linters: + settings: + goconst: + find-duplicates: true + eval-const-expressions: true + numbers: true diff --git a/pkg/golinters/goconst/testdata/goconst_eval_const_expressions.go b/pkg/golinters/goconst/testdata/goconst_eval_const_expressions.go new file mode 100644 index 000000000000..4cc272945b43 --- /dev/null +++ b/pkg/golinters/goconst/testdata/goconst_eval_const_expressions.go @@ -0,0 +1,29 @@ +//golangcitest:args -Egoconst +//golangcitest:config_path testdata/goconst_eval_const_expressions.yml +package testdata + +const ( + prefix = "example.com/" + API = prefix + "api" + Web = prefix + "web" +) + +const Full = "example.com/api" + +func _() { + a0 := "example.com/api" // want "string `example.com/api` has 3 occurrences, but such constant `API` already exists" + a1 := "example.com/api" + a2 := "example.com/api" + + _ = a0 + _ = a1 + _ = a2 + + b0 := "example.com/web" // want "string `example.com/web` has 3 occurrences, but such constant `Web` already exists" + b1 := "example.com/web" + b2 := "example.com/web" + + _ = b0 + _ = b1 + _ = b2 +} diff --git a/pkg/golinters/goconst/testdata/goconst_eval_const_expressions.yml b/pkg/golinters/goconst/testdata/goconst_eval_const_expressions.yml new file mode 100644 index 000000000000..7c2303aef7d8 --- /dev/null +++ b/pkg/golinters/goconst/testdata/goconst_eval_const_expressions.yml @@ -0,0 +1,6 @@ +version: "2" + +linters: + settings: + goconst: + eval-const-expressions: true diff --git a/pkg/golinters/goconst/testdata/goconst_find_duplicates.go b/pkg/golinters/goconst/testdata/goconst_find_duplicates.go new file mode 100644 index 000000000000..d26d871daf37 --- /dev/null +++ b/pkg/golinters/goconst/testdata/goconst_find_duplicates.go @@ -0,0 +1,29 @@ +//golangcitest:args -Egoconst +//golangcitest:config_path testdata/goconst_find_duplicates.yml +package testdata + +const SingleConst = "single constant" + +const ( + GroupedConst1 = "grouped constant" + GroupedConst2 = "another grouped" +) + +const ( + GroupedDuplicateConst1 = "grouped duplicate value" + GroupedDuplicateConst2 = "grouped duplicate value" // want "This constant is a duplicate of `GroupedDuplicateConst1` at goconst_find_duplicates.go:13:2" +) + +const DuplicateConst1 = "duplicate value" + +const DuplicateConst2 = "duplicate value" // want "This constant is a duplicate of `DuplicateConst1` at goconst_find_duplicates.go:17:7" + +const ( + SpecialDuplicateConst1 = "special\nvalue\twith\rchars" + SpecialDuplicateConst2 = "special\nvalue\twith\rchars" // want "This constant is a duplicate of `SpecialDuplicateConst1` at goconst_find_duplicates.go:22:2" +) + +func _() { + const DuplicateScopedConst1 = "duplicate scoped value" + const DuplicateScopedConst2 = "duplicate scoped value" // want "This constant is a duplicate of `DuplicateScopedConst1` at goconst_find_duplicates.go:27:8" +} diff --git a/pkg/golinters/goconst/testdata/goconst_find_duplicates.yml b/pkg/golinters/goconst/testdata/goconst_find_duplicates.yml new file mode 100644 index 000000000000..8a64450696e7 --- /dev/null +++ b/pkg/golinters/goconst/testdata/goconst_find_duplicates.yml @@ -0,0 +1,6 @@ +version: "2" + +linters: + settings: + goconst: + find-duplicates: true diff --git a/pkg/lint/lintersdb/builder_linter.go b/pkg/lint/lintersdb/builder_linter.go index c246250dad16..a05e0bbd7f4c 100644 --- a/pkg/lint/lintersdb/builder_linter.go +++ b/pkg/lint/lintersdb/builder_linter.go @@ -300,6 +300,7 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { linter.NewConfig(goconst.New(&cfg.Linters.Settings.Goconst)). WithSince("v1.0.0"). + WithLoadForGoAnalysis(). WithURL("https://github.com/jgautheron/goconst"), linter.NewConfig(gocritic.New(&cfg.Linters.Settings.Gocritic, placeholderReplacer)). From afb5317b2aa007f04556d831e820a8f1bcc365ba Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 9 Apr 2025 18:20:00 +0200 Subject: [PATCH 3/4] chore: windows, windows, windows, ... --- pkg/golinters/goconst/goconst.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/golinters/goconst/goconst.go b/pkg/golinters/goconst/goconst.go index f3af64625243..9ef695b54f5b 100644 --- a/pkg/golinters/goconst/goconst.go +++ b/pkg/golinters/goconst/goconst.go @@ -2,6 +2,7 @@ package goconst import ( "fmt" + "path/filepath" "sync" goconstAPI "github.com/jgautheron/goconst" @@ -100,7 +101,7 @@ func runGoconst(pass *analysis.Pass, settings *config.GoConstSettings) ([]goanal case issue.DuplicateConst != "": text = fmt.Sprintf("This constant is a duplicate of %s at %s", internal.FormatCode(issue.DuplicateConst, nil), - issue.DuplicatePos.String()) + filepath.ToSlash(issue.DuplicatePos.String())) default: continue From ff1134008b9ed853047fa95e1aa1e70d89edbc96 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 9 Apr 2025 19:07:37 +0200 Subject: [PATCH 4/4] chore: windows you are not my friend --- pkg/golinters/goconst/goconst.go | 3 +-- .../goconst/testdata/goconst_eval_and_find_duplicates.go | 4 ++-- pkg/golinters/goconst/testdata/goconst_find_duplicates.go | 8 ++++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pkg/golinters/goconst/goconst.go b/pkg/golinters/goconst/goconst.go index 9ef695b54f5b..f3af64625243 100644 --- a/pkg/golinters/goconst/goconst.go +++ b/pkg/golinters/goconst/goconst.go @@ -2,7 +2,6 @@ package goconst import ( "fmt" - "path/filepath" "sync" goconstAPI "github.com/jgautheron/goconst" @@ -101,7 +100,7 @@ func runGoconst(pass *analysis.Pass, settings *config.GoConstSettings) ([]goanal case issue.DuplicateConst != "": text = fmt.Sprintf("This constant is a duplicate of %s at %s", internal.FormatCode(issue.DuplicateConst, nil), - filepath.ToSlash(issue.DuplicatePos.String())) + issue.DuplicatePos.String()) default: continue diff --git a/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.go b/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.go index 24d43af14df6..64a4c3e119eb 100644 --- a/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.go +++ b/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.go @@ -10,14 +10,14 @@ const ( EnvPassword = envPrefix + "PASSWORD" ) -const EnvUserFull = "FOO_USER" // want "This constant is a duplicate of `EnvUser` at goconst_eval_and_find_duplicates.go:9:16" +const EnvUserFull = "FOO_USER" // want "This constant is a duplicate of `EnvUser` at .*goconst_eval_and_find_duplicates.go:9:16" const KiB = 1 << 10 func _() { fmt.Println(envPrefix, EnvUser, EnvPassword, EnvUserFull) - const kilobytes = 1024 // want "This constant is a duplicate of `KiB` at goconst_eval_and_find_duplicates.go:15:13" + const kilobytes = 1024 // want "This constant is a duplicate of `KiB` at .*goconst_eval_and_find_duplicates.go:15:13" fmt.Println(kilobytes) kib := 1024 diff --git a/pkg/golinters/goconst/testdata/goconst_find_duplicates.go b/pkg/golinters/goconst/testdata/goconst_find_duplicates.go index d26d871daf37..a1605cfe6358 100644 --- a/pkg/golinters/goconst/testdata/goconst_find_duplicates.go +++ b/pkg/golinters/goconst/testdata/goconst_find_duplicates.go @@ -11,19 +11,19 @@ const ( const ( GroupedDuplicateConst1 = "grouped duplicate value" - GroupedDuplicateConst2 = "grouped duplicate value" // want "This constant is a duplicate of `GroupedDuplicateConst1` at goconst_find_duplicates.go:13:2" + GroupedDuplicateConst2 = "grouped duplicate value" // want "This constant is a duplicate of `GroupedDuplicateConst1` at .*goconst_find_duplicates.go:13:2" ) const DuplicateConst1 = "duplicate value" -const DuplicateConst2 = "duplicate value" // want "This constant is a duplicate of `DuplicateConst1` at goconst_find_duplicates.go:17:7" +const DuplicateConst2 = "duplicate value" // want "This constant is a duplicate of `DuplicateConst1` at .*goconst_find_duplicates.go:17:7" const ( SpecialDuplicateConst1 = "special\nvalue\twith\rchars" - SpecialDuplicateConst2 = "special\nvalue\twith\rchars" // want "This constant is a duplicate of `SpecialDuplicateConst1` at goconst_find_duplicates.go:22:2" + SpecialDuplicateConst2 = "special\nvalue\twith\rchars" // want "This constant is a duplicate of `SpecialDuplicateConst1` at .*goconst_find_duplicates.go:22:2" ) func _() { const DuplicateScopedConst1 = "duplicate scoped value" - const DuplicateScopedConst2 = "duplicate scoped value" // want "This constant is a duplicate of `DuplicateScopedConst1` at goconst_find_duplicates.go:27:8" + const DuplicateScopedConst2 = "duplicate scoped value" // want "This constant is a duplicate of `DuplicateScopedConst1` at .*goconst_find_duplicates.go:27:8" }