github.com/chenfeining/golangci-lint@v1.0.2-0.20230730162517-14c6c67868df/pkg/golinters/unused.go (about) 1 package golinters 2 3 import ( 4 "fmt" 5 "sync" 6 7 "golang.org/x/tools/go/analysis" 8 "honnef.co/go/tools/unused" 9 10 "github.com/chenfeining/golangci-lint/pkg/config" 11 "github.com/chenfeining/golangci-lint/pkg/golinters/goanalysis" 12 "github.com/chenfeining/golangci-lint/pkg/lint/linter" 13 "github.com/chenfeining/golangci-lint/pkg/result" 14 ) 15 16 const unusedName = "unused" 17 18 type UnusedSettings struct { 19 GoVersion string 20 } 21 22 func NewUnused(settings *config.StaticCheckSettings) *goanalysis.Linter { 23 var mu sync.Mutex 24 var resIssues []goanalysis.Issue 25 26 analyzer := &analysis.Analyzer{ 27 Name: unusedName, 28 Doc: unused.Analyzer.Analyzer.Doc, 29 Requires: unused.Analyzer.Analyzer.Requires, 30 Run: func(pass *analysis.Pass) (any, error) { 31 issues, err := runUnused(pass) 32 if err != nil { 33 return nil, err 34 } 35 36 if len(issues) == 0 { 37 return nil, nil 38 } 39 40 mu.Lock() 41 resIssues = append(resIssues, issues...) 42 mu.Unlock() 43 44 return nil, nil 45 }, 46 } 47 48 setAnalyzerGoVersion(analyzer, getGoVersion(settings)) 49 50 return goanalysis.NewLinter( 51 unusedName, 52 "Checks Go code for unused constants, variables, functions and types", 53 []*analysis.Analyzer{analyzer}, 54 nil, 55 ).WithIssuesReporter(func(lintCtx *linter.Context) []goanalysis.Issue { 56 return resIssues 57 }).WithLoadMode(goanalysis.LoadModeTypesInfo) 58 } 59 60 func runUnused(pass *analysis.Pass) ([]goanalysis.Issue, error) { 61 res, err := unused.Analyzer.Analyzer.Run(pass) 62 if err != nil { 63 return nil, err 64 } 65 66 used := make(map[string]bool) 67 for _, obj := range res.(unused.Result).Used { 68 used[fmt.Sprintf("%s %d %s", obj.Position.Filename, obj.Position.Line, obj.Name)] = true 69 } 70 71 var issues []goanalysis.Issue 72 73 // Inspired by https://github.com/dominikh/go-tools/blob/d694aadcb1f50c2d8ac0a1dd06217ebb9f654764/lintcmd/lint.go#L177-L197 74 for _, object := range res.(unused.Result).Unused { 75 if object.Kind == "type param" { 76 continue 77 } 78 79 key := fmt.Sprintf("%s %d %s", object.Position.Filename, object.Position.Line, object.Name) 80 if used[key] { 81 continue 82 } 83 84 issue := goanalysis.NewIssue(&result.Issue{ 85 FromLinter: unusedName, 86 Text: fmt.Sprintf("%s %s is unused", object.Kind, object.Name), 87 Pos: object.Position, 88 }, pass) 89 90 issues = append(issues, issue) 91 } 92 93 return issues, nil 94 }