github.com/elek/golangci-lint@v1.42.2-0.20211208090441-c05b7fcb3a9a/pkg/golinters/dupl.go (about) 1 package golinters 2 3 import ( 4 "fmt" 5 "go/token" 6 "sync" 7 8 duplAPI "github.com/golangci/dupl" 9 "github.com/pkg/errors" 10 "golang.org/x/tools/go/analysis" 11 12 "github.com/elek/golangci-lint/pkg/fsutils" 13 "github.com/elek/golangci-lint/pkg/golinters/goanalysis" 14 "github.com/elek/golangci-lint/pkg/lint/linter" 15 "github.com/elek/golangci-lint/pkg/result" 16 ) 17 18 const duplLinterName = "dupl" 19 20 func NewDupl() *goanalysis.Linter { 21 var mu sync.Mutex 22 var resIssues []goanalysis.Issue 23 24 analyzer := &analysis.Analyzer{ 25 Name: duplLinterName, 26 Doc: goanalysis.TheOnlyanalyzerDoc, 27 } 28 return goanalysis.NewLinter( 29 duplLinterName, 30 "Tool for code clone detection", 31 []*analysis.Analyzer{analyzer}, 32 nil, 33 ).WithContextSetter(func(lintCtx *linter.Context) { 34 analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { 35 var fileNames []string 36 for _, f := range pass.Files { 37 pos := pass.Fset.PositionFor(f.Pos(), false) 38 fileNames = append(fileNames, pos.Filename) 39 } 40 41 issues, err := duplAPI.Run(fileNames, lintCtx.Settings().Dupl.Threshold) 42 if err != nil { 43 return nil, err 44 } 45 46 if len(issues) == 0 { 47 return nil, nil 48 } 49 50 res := make([]goanalysis.Issue, 0, len(issues)) 51 for _, i := range issues { 52 toFilename, err := fsutils.ShortestRelPath(i.To.Filename(), "") 53 if err != nil { 54 return nil, errors.Wrapf(err, "failed to get shortest rel path for %q", i.To.Filename()) 55 } 56 dupl := fmt.Sprintf("%s:%d-%d", toFilename, i.To.LineStart(), i.To.LineEnd()) 57 text := fmt.Sprintf("%d-%d lines are duplicate of %s", 58 i.From.LineStart(), i.From.LineEnd(), 59 formatCode(dupl, lintCtx.Cfg)) 60 res = append(res, goanalysis.NewIssue(&result.Issue{ 61 Pos: token.Position{ 62 Filename: i.From.Filename(), 63 Line: i.From.LineStart(), 64 }, 65 LineRange: &result.Range{ 66 From: i.From.LineStart(), 67 To: i.From.LineEnd(), 68 }, 69 Text: text, 70 FromLinter: duplLinterName, 71 }, pass)) 72 } 73 74 mu.Lock() 75 resIssues = append(resIssues, res...) 76 mu.Unlock() 77 78 return nil, nil 79 } 80 }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { 81 return resIssues 82 }).WithLoadMode(goanalysis.LoadModeSyntax) 83 }