diff --git a/.golangci.yml b/.golangci.yml index 08460ba96136..f2fcc17cc0fa 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -139,6 +139,18 @@ issues: - path: pkg/golinters/scopelint.go text: 'directive `//nolint:interfacer` is unused for linter interfacer' + # TODO temporary rule, must be removed + # related to https://github.com/golangci/golangci-lint/pull/1756 + # must be replaced by '//nolint:staticcheck // require changes in github.com/OpenPeeDeeP/depguard' + - path: pkg/golinters/depguard.go + text: 'SA1019: package golang.org/x/tools/go/loader is deprecated' + + # TODO temporary rule, must be removed + # related to https://github.com/golangci/golangci-lint/pull/1756 + # must be replaced by '///nolint:staticcheck // it's an adapter for golang.org/x/tools/go/packages' + - path: pkg/golinters/goanalysis/adapters.go + text: 'SA1019: package golang.org/x/tools/go/loader is deprecated' + run: skip-dirs: - test/testdata_etc diff --git a/go.mod b/go.mod index ecb318aec6d4..ba63e10b8e5a 100644 --- a/go.mod +++ b/go.mod @@ -77,7 +77,7 @@ require ( golang.org/x/text v0.3.4 // indirect golang.org/x/tools v0.1.0 gopkg.in/yaml.v2 v2.4.0 - honnef.co/go/tools v0.0.1-2020.1.6 + honnef.co/go/tools v0.1.2 mvdan.cc/gofumpt v0.1.0 mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect diff --git a/go.sum b/go.sum index 181e1417edab..874315fd6a58 100644 --- a/go.sum +++ b/go.sum @@ -571,7 +571,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -653,8 +652,8 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.6 h1:W18jzjh8mfPez+AwGLxmOImucz/IFjpNlrKVnaj2YVc= -honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY= +honnef.co/go/tools v0.1.2 h1:SMdYLJl312RXuxXziCCHhRsp/tvct9cGKey0yv95tZM= +honnef.co/go/tools v0.1.2/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= mvdan.cc/gofumpt v0.1.0 h1:hsVv+Y9UsZ/mFZTxJZuHVI6shSQCtzZ11h1JEFPAZLw= mvdan.cc/gofumpt v0.1.0/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= diff --git a/pkg/golinters/unused.go b/pkg/golinters/unused.go index bbe1e4b6903d..6998ebde053f 100644 --- a/pkg/golinters/unused.go +++ b/pkg/golinters/unused.go @@ -1,10 +1,10 @@ package golinters import ( - "go/types" + "fmt" + "sync" "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/packages" "honnef.co/go/tools/unused" "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" @@ -13,53 +13,53 @@ import ( ) func NewUnused() *goanalysis.Linter { - u := unused.NewChecker(false) - analyzers := []*analysis.Analyzer{u.Analyzer()} + const name = "unused" + + var mu sync.Mutex + var resIssues []goanalysis.Issue + + analyzer := &analysis.Analyzer{ + Name: name, + Doc: unused.Analyzer.Doc, + Requires: unused.Analyzer.Requires, + Run: func(pass *analysis.Pass) (interface{}, error) { + res, err := unused.Analyzer.Run(pass) + if err != nil { + return nil, err + } + + sr := unused.Serialize(pass, res.(unused.Result), pass.Fset) + + var issues []goanalysis.Issue + for _, object := range sr.Unused { + issue := goanalysis.NewIssue(&result.Issue{ + FromLinter: name, + Text: fmt.Sprintf("%s %s is unused", object.Kind, object.Name), + Pos: object.Position, + }, pass) + + issues = append(issues, issue) + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + }, + } + + analyzers := []*analysis.Analyzer{analyzer} setAnalyzersGoVersion(analyzers) - const name = "unused" lnt := goanalysis.NewLinter( name, "Checks Go code for unused constants, variables, functions and types", analyzers, nil, ).WithIssuesReporter(func(lintCtx *linter.Context) []goanalysis.Issue { - typesToPkg := map[*types.Package]*packages.Package{} - for _, pkg := range lintCtx.OriginalPackages { - typesToPkg[pkg.Types] = pkg - } + return resIssues + }).WithLoadMode(goanalysis.LoadModeSyntax | goanalysis.LoadModeTypesInfo) - var issues []goanalysis.Issue - for _, ur := range u.Result() { - p := u.ProblemObject(lintCtx.Packages[0].Fset, ur) - pkg := typesToPkg[ur.Pkg()] - i := &result.Issue{ - FromLinter: name, - Text: p.Message, - Pos: p.Pos, - Pkg: pkg, - LineRange: &result.Range{ - From: p.Pos.Line, - To: p.End.Line, - }, - } - // See https://github.com/golangci/golangci-lint/issues/1048 - // If range is invalid, this will break `--fix` mode. - if i.LineRange.To >= i.LineRange.From { - i.Replacement = &result.Replacement{ - // Suggest deleting unused stuff. - NeedOnlyDelete: true, - } - } - issues = append(issues, goanalysis.NewIssue(i, nil)) - } - return issues - }).WithContextSetter(func(lintCtx *linter.Context) { - if lintCtx.Settings().Unused.CheckExported { - lintCtx.Log.Infof("Using whole program analysis for unused, it can be memory-heavy") - u.WholeProgram = true - } - }).WithLoadMode(goanalysis.LoadModeWholeProgram) - lnt.UseOriginalPackages() return lnt } diff --git a/test/testdata/staticcheck.go b/test/testdata/staticcheck.go index 5ab2d78cba4c..d20f26efdb8c 100644 --- a/test/testdata/staticcheck.go +++ b/test/testdata/staticcheck.go @@ -23,7 +23,7 @@ func StaticcheckNolintMegacheck() { } func StaticcheckDeprecated() { - _ = runtime.CPUProfile() // ERROR "SA1019: runtime.CPUProfile is deprecated" + _ = runtime.CPUProfile() // ERROR "SA1019: runtime.CPUProfile has been deprecated .*" } func StaticcheckPrintf() { diff --git a/test/testdata/unused.go b/test/testdata/unused.go index 46c497292eec..1fa3c0b80a19 100644 --- a/test/testdata/unused.go +++ b/test/testdata/unused.go @@ -1,6 +1,19 @@ //args: -Eunused package testdata +func fn1() {} // ERROR "func `fn1` is unused" + +//nolint:unused +func fn2() { fn3() } + +func fn3() {} // ERROR "func `fn3` is unused" + +func fn4() { fn5() } // ERROR "func `fn4` is unused" + +func fn5() {} // ERROR "func `fn5` is unused" + +func fn6() { fn4() } // ERROR "func `fn6` is unused" + type unusedStruct struct{} // ERROR "type `unusedStruct` is unused" type unusedStructNolintUnused struct{} //nolint:unused