diff --git a/.golangci.reference.yml b/.golangci.reference.yml index ea4cd438..b759aa9d 100644 --- a/.golangci.reference.yml +++ b/.golangci.reference.yml @@ -2140,6 +2140,7 @@ linters: - maintidx - makezero - maligned + - mirror - misspell - musttag - nakedret @@ -2253,6 +2254,7 @@ linters: - maintidx - makezero - maligned + - mirror - misspell - musttag - nakedret diff --git a/go.mod b/go.mod index b5e5132d..72e8ee3f 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( github.com/breml/bidichk v0.2.4 github.com/breml/errchkjson v0.3.1 github.com/butuzov/ireturn v0.2.0 + github.com/butuzov/mirror v1.1.0 github.com/charithe/durationcheck v0.0.10 github.com/curioswitch/go-reassign v0.2.0 github.com/daixiang0/gci v0.10.1 diff --git a/go.sum b/go.sum index 9c5f1683..4f45e944 100644 --- a/go.sum +++ b/go.sum @@ -94,6 +94,8 @@ github.com/breml/errchkjson v0.3.1 h1:hlIeXuspTyt8Y/UmP5qy1JocGNR00KQHgfaNtRAjox github.com/breml/errchkjson v0.3.1/go.mod h1:XroxrzKjdiutFyW3nWhw34VGg7kiMsDQox73yWCGI2U= github.com/butuzov/ireturn v0.2.0 h1:kCHi+YzC150GE98WFuZQu9yrTn6GEydO2AuPLbTgnO4= github.com/butuzov/ireturn v0.2.0/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= +github.com/butuzov/mirror v1.1.0 h1:ZqX54gBVMXu78QLoiqdwpl2mgmoOJTk7s4p4o+0avZI= +github.com/butuzov/mirror v1.1.0/go.mod h1:8Q0BdQU6rC6WILDiBM60DBfvV78OLJmMmixe7GF45AE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= diff --git a/pkg/golinters/mirror.go b/pkg/golinters/mirror.go new file mode 100644 index 00000000..4adc001a --- /dev/null +++ b/pkg/golinters/mirror.go @@ -0,0 +1,70 @@ +package golinters + +import ( + "sync" + + "github.com/butuzov/mirror" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" + "github.com/golangci/golangci-lint/pkg/lint/linter" + "github.com/golangci/golangci-lint/pkg/result" +) + +func NewMirror() *goanalysis.Linter { + var ( + mu sync.Mutex + issues []goanalysis.Issue + ) + + a := mirror.NewAnalyzer() + a.Run = func(pass *analysis.Pass) (any, error) { + // mirror only lints test files if the `--with-tests` flag is passed, + // so we pass the `with-tests` flag as true to the analyzer before running it. + // This can be turned off by using the regular golangci-lint flags such as `--tests` or `--skip-files` + // or can be disabled per linter via exclude rules. + // (see https://github.com/golangci/golangci-lint/issues/2527#issuecomment-1023707262) + violations := mirror.Run(pass, true) + + if len(violations) == 0 { + return nil, nil + } + + for index := range violations { + i := violations[index].Issue(pass.Fset) + + issue := result.Issue{ + FromLinter: a.Name, + Text: i.Message, + Pos: i.Start, + } + + if len(i.InlineFix) > 0 { + issue.Replacement = &result.Replacement{ + Inline: &result.InlineFix{ + StartCol: i.Start.Column - 1, + Length: len(i.Original), + NewString: i.InlineFix, + }, + } + } + + mu.Lock() + issues = append(issues, goanalysis.NewIssue(&issue, pass)) + mu.Unlock() + } + + return nil, nil + } + + analyzer := goanalysis.NewLinter( + a.Name, + a.Doc, + []*analysis.Analyzer{a}, + nil, + ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { + return issues + }).WithLoadMode(goanalysis.LoadModeTypesInfo) + + return analyzer +} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index 3c2394a4..17ce2d9c 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -654,6 +654,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithURL("https://github.com/mdempsky/maligned"). Deprecated("The repository of the linter has been archived by the owner.", "v1.38.0", "govet 'fieldalignment'"), + linter.NewConfig(golinters.NewMirror()). + WithSince("v1.53.0"). + WithPresets(linter.PresetStyle). + WithLoadForGoAnalysis(). + WithURL("https://github.com/butuzov/mirror"), + linter.NewConfig(golinters.NewMisspell(misspellCfg)). WithSince("v1.8.0"). WithPresets(linter.PresetStyle, linter.PresetComment). diff --git a/test/testdata/mirror.go b/test/testdata/mirror.go new file mode 100644 index 00000000..92967aea --- /dev/null +++ b/test/testdata/mirror.go @@ -0,0 +1,12 @@ +//golangcitest:args -Emirror +package testdata + +import ( + "strings" + "unicode/utf8" +) + +func foobar() { + _ = utf8.RuneCount([]byte("foobar")) // want `avoid allocations with utf8\.RuneCountInString` + _ = strings.Compare(string([]byte{'f', 'o', 'o', 'b', 'a', 'r'}), string([]byte{'f', 'o', 'o', 'b', 'a', 'r'})) // want `avoid allocations with bytes\.Compare` +}