Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: add exhaustruct linter
This linter can be called a successor of `exhaustivestruct`, and:

- it is at least **2.5+ times faster**, due to better algorithm;
- can receive `include` and/or `exclude` patterns;
- expects received patterns to be RegExp, therefore this package is not api-compatible with `exhaustivestruct`.

Also: deprecate `exhaustivestruct` linter
  • Loading branch information
xobotyi authored and ldez committed Apr 30, 2022
commit 89f665c51d4d5cc8a488b4864053e2e621012de3
10 changes: 10 additions & 0 deletions .golangci.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,16 @@ linters-settings:
- '*.Test'
- 'example.com/package.ExampleStruct'

exhaustruct:
# List of regular expressions to match struct packages and names.
# If this list is empty, all structs are tested.
include:
- '.*\.Test'
- 'example\.com/package\.ExampleStruct'
# List of regular expressions to exclude struct packages and names from check.
exclude:
- 'cobra\.Command$'

forbidigo:
# Forbid the following identifiers (list of regexp).
forbid:
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ require (
mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5
)

require github.com/GaijinEntertainment/go-exhaustruct v1.0.0

require (
github.com/Masterminds/semver v1.5.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions pkg/config/linters_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ type LintersSettings struct {
ErrorLint ErrorLintSettings
Exhaustive ExhaustiveSettings
ExhaustiveStruct ExhaustiveStructSettings
Exhaustruct ExhaustructSettings
Forbidigo ForbidigoSettings
Funlen FunlenSettings
Gci GciSettings
Expand Down Expand Up @@ -255,6 +256,11 @@ type ExhaustiveStructSettings struct {
StructPatterns []string `mapstructure:"struct-patterns"`
}

type ExhaustructSettings struct {
Include []string `mapstructure:"include"`
Exclude []string `mapstructure:"exclude"`
}

type ForbidigoSettings struct {
Forbid []string `mapstructure:"forbid"`
ExcludeGodocExamples bool `mapstructure:"exclude-godoc-examples"`
Expand Down
32 changes: 32 additions & 0 deletions pkg/golinters/exhaustruct.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package golinters

import (
"strings"

"github.com/GaijinEntertainment/go-exhaustruct/pkg/analyzer"
"golang.org/x/tools/go/analysis"

"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
)

func NewExhaustruct(settings *config.ExhaustructSettings) *goanalysis.Linter {
a := analyzer.Analyzer

var cfg map[string]map[string]interface{}
if settings != nil {
cfg = map[string]map[string]interface{}{
a.Name: {
"include": strings.Join(settings.Include, ","),
"exclude": strings.Join(settings.Exclude, ","),
},
}
}

return goanalysis.NewLinter(
a.Name,
a.Doc,
[]*analysis.Analyzer{a},
cfg,
).WithLoadMode(goanalysis.LoadModeTypesInfo)
}
11 changes: 10 additions & 1 deletion pkg/lint/lintersdb/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
var errorlintCfg *config.ErrorLintSettings
var exhaustiveCfg *config.ExhaustiveSettings
var exhaustiveStructCfg *config.ExhaustiveStructSettings
var exhaustructCfg *config.ExhaustructSettings
var gciCfg *config.GciSettings
var goModDirectivesCfg *config.GoModDirectivesSettings
var goMndCfg *config.GoMndSettings
Expand Down Expand Up @@ -140,6 +141,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
errorlintCfg = &m.cfg.LintersSettings.ErrorLint
exhaustiveCfg = &m.cfg.LintersSettings.Exhaustive
exhaustiveStructCfg = &m.cfg.LintersSettings.ExhaustiveStruct
exhaustructCfg = &m.cfg.LintersSettings.Exhaustruct
gciCfg = &m.cfg.LintersSettings.Gci
goModDirectivesCfg = &m.cfg.LintersSettings.GoModDirectives
goMndCfg = &m.cfg.LintersSettings.Gomnd
Expand Down Expand Up @@ -281,7 +283,14 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithSince("v1.32.0").
WithPresets(linter.PresetStyle, linter.PresetTest).
WithLoadForGoAnalysis().
WithURL("https://github.com/mbilski/exhaustivestruct"),
WithURL("https://github.com/mbilski/exhaustivestruct").
Deprecated("Owner seems to abandon linter.", "v1.46.0", "exhaustruct"),

linter.NewConfig(golinters.NewExhaustruct(exhaustructCfg)).
WithSince("v1.46.0").
WithPresets(linter.PresetStyle, linter.PresetTest).
WithLoadForGoAnalysis().
WithURL("https://github.com/GaijinEntertainment/go-exhaustruct"),

linter.NewConfig(golinters.NewExportLoopRef()).
WithSince("v1.28.0").
Expand Down
40 changes: 40 additions & 0 deletions test/testdata/exhaustruct.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//args: -Eexhaustruct
package testdata

import "time"

type Test struct {
A string
B int
c bool // private field inside the same package are not ignored
D float64
E time.Time
}

var pass = Test{
A: "a",
B: 0,
c: false,
D: 1.0,
E: time.Now(),
}

var failPrivate = Test{ // ERROR "c is missing in Test"
A: "a",
B: 0,
D: 1.0,
E: time.Now(),
}

var fail = Test{ // ERROR "B is missing in Test"
A: "a",
c: false,
D: 1.0,
E: time.Now(),
}

var failMultiple = Test{ // ERROR "B, D are missing in Test"
A: "a",
c: false,
E: time.Now(),
}
114 changes: 114 additions & 0 deletions test/testdata/exhaustruct_custom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//args: -Eexhaustruct
//config: linters-settings.exhaustruct.include=.*\.Test1$
//config: linters-settings.exhaustruct.exclude=.*\.Test3$
package testdata

import "time"

type Test1 struct {
A string
B int
c bool // private field inside the same package are not ignored
D float64
E time.Time
}

var passTest1 = Test1{
A: "a",
B: 0,
c: false,
D: 1.0,
E: time.Now(),
}

var failTest1 = Test1{ // ERROR "B is missing in Test"
A: "a",
c: false,
D: 1.0,
E: time.Now(),
}

var failMultipleTest1 = Test1{ // ERROR "B, D are missing in Test"
A: "a",
c: false,
E: time.Now(),
}

var failPrivateTest1 = Test1{ // ERROR "c is missing in Test"
A: "a",
B: 0,
D: 1.0,
E: time.Now(),
}

type Test2 struct {
A string
B int
c bool // private field inside the same package are not ignored
D float64
E time.Time
}

var passTest2 = Test1{
A: "a",
B: 0,
c: false,
D: 1.0,
E: time.Now(),
}

var failTest2 = Test2{
A: "a",
c: false,
D: 1.0,
E: time.Now(),
}

var failMultipleTest2 = Test2{
A: "a",
c: false,
E: time.Now(),
}

var failPrivateTest2 = Test2{
A: "a",
B: 0,
D: 1.0,
E: time.Now(),
}

type Test3 struct {
A string
B int
c bool // private field inside the same package are not ignored
D float64
E time.Time
}

var passTest3 = Test3{
A: "a",
B: 0,
c: false,
D: 1.0,
E: time.Now(),
}

var failTest3 = Test3{
A: "a",
c: false,
D: 1.0,
E: time.Now(),
}

var failMultipleTest3 = Test3{
A: "a",
c: false,
E: time.Now(),
}

var failPrivateTest3 = Test3{
A: "a",
B: 0,
D: 1.0,
E: time.Now(),
}