github.com/elek/golangci-lint@v1.42.2-0.20211208090441-c05b7fcb3a9a/pkg/golinters/goconst.go (about) 1 package golinters 2 3 import ( 4 "fmt" 5 "sync" 6 7 goconstAPI "github.com/jgautheron/goconst" 8 "golang.org/x/tools/go/analysis" 9 10 "github.com/elek/golangci-lint/pkg/golinters/goanalysis" 11 "github.com/elek/golangci-lint/pkg/lint/linter" 12 "github.com/elek/golangci-lint/pkg/result" 13 ) 14 15 const goconstName = "goconst" 16 17 func NewGoconst() *goanalysis.Linter { 18 var mu sync.Mutex 19 var resIssues []goanalysis.Issue 20 21 analyzer := &analysis.Analyzer{ 22 Name: goconstName, 23 Doc: goanalysis.TheOnlyanalyzerDoc, 24 } 25 return goanalysis.NewLinter( 26 goconstName, 27 "Finds repeated strings that could be replaced by a constant", 28 []*analysis.Analyzer{analyzer}, 29 nil, 30 ).WithContextSetter(func(lintCtx *linter.Context) { 31 analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { 32 issues, err := checkConstants(pass, lintCtx) 33 if err != nil || len(issues) == 0 { 34 return nil, err 35 } 36 37 mu.Lock() 38 resIssues = append(resIssues, issues...) 39 mu.Unlock() 40 41 return nil, nil 42 } 43 }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { 44 return resIssues 45 }).WithLoadMode(goanalysis.LoadModeSyntax) 46 } 47 48 func checkConstants(pass *analysis.Pass, lintCtx *linter.Context) ([]goanalysis.Issue, error) { 49 settings := lintCtx.Settings().Goconst 50 51 cfg := goconstAPI.Config{ 52 IgnoreTests: settings.IgnoreTests, 53 MatchWithConstants: settings.MatchWithConstants, 54 MinStringLength: settings.MinStringLen, 55 MinOccurrences: settings.MinOccurrencesCount, 56 ParseNumbers: settings.ParseNumbers, 57 NumberMin: settings.NumberMin, 58 NumberMax: settings.NumberMax, 59 ExcludeTypes: map[goconstAPI.Type]bool{}, 60 } 61 62 if settings.IgnoreCalls { 63 cfg.ExcludeTypes[goconstAPI.Call] = true 64 } 65 66 goconstIssues, err := goconstAPI.Run(pass.Files, pass.Fset, &cfg) 67 if err != nil { 68 return nil, err 69 } 70 71 if len(goconstIssues) == 0 { 72 return nil, nil 73 } 74 75 res := make([]goanalysis.Issue, 0, len(goconstIssues)) 76 for _, i := range goconstIssues { 77 textBegin := fmt.Sprintf("string %s has %d occurrences", formatCode(i.Str, lintCtx.Cfg), i.OccurrencesCount) 78 var textEnd string 79 if i.MatchingConst == "" { 80 textEnd = ", make it a constant" 81 } else { 82 textEnd = fmt.Sprintf(", but such constant %s already exists", formatCode(i.MatchingConst, lintCtx.Cfg)) 83 } 84 res = append(res, goanalysis.NewIssue(&result.Issue{ 85 Pos: i.Pos, 86 Text: textBegin + textEnd, 87 FromLinter: goconstName, 88 }, pass)) 89 } 90 91 return res, nil 92 }