github.com/ldez/golangci-lint@v1.10.1/pkg/result/processors/source_code.go (about) 1 package processors 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 8 "github.com/golangci/golangci-lint/pkg/logutils" 9 "github.com/golangci/golangci-lint/pkg/result" 10 ) 11 12 type linesCache [][]byte 13 type filesLineCache map[string]linesCache 14 15 type SourceCode struct { 16 cache filesLineCache 17 log logutils.Log 18 } 19 20 var _ Processor = SourceCode{} 21 22 func NewSourceCode(log logutils.Log) *SourceCode { 23 return &SourceCode{ 24 cache: filesLineCache{}, 25 log: log, 26 } 27 } 28 29 func (p SourceCode) Name() string { 30 return "source_code" 31 } 32 33 func (p SourceCode) Process(issues []result.Issue) ([]result.Issue, error) { 34 return transformIssues(issues, func(i *result.Issue) *result.Issue { 35 lines, err := p.getFileLinesForIssue(i) 36 if err != nil { 37 p.log.Warnf("Failed to get lines for file %s: %s", i.FilePath(), err) 38 return i 39 } 40 41 newI := *i 42 43 lineRange := i.GetLineRange() 44 var lineStr string 45 for line := lineRange.From; line <= lineRange.To; line++ { 46 if line == 0 { // some linters, e.g. gas can do it: it really means first line 47 line = 1 48 } 49 50 zeroIndexedLine := line - 1 51 if zeroIndexedLine >= len(lines) { 52 p.log.Warnf("No line %d in file %s", line, i.FilePath()) 53 break 54 } 55 56 lineStr = string(bytes.Trim(lines[zeroIndexedLine], "\r")) 57 newI.SourceLines = append(newI.SourceLines, lineStr) 58 } 59 60 return &newI 61 }), nil 62 } 63 64 func (p *SourceCode) getFileLinesForIssue(i *result.Issue) (linesCache, error) { 65 fc := p.cache[i.FilePath()] 66 if fc != nil { 67 return fc, nil 68 } 69 70 // TODO: make more optimal algorithm: don't load all files into memory 71 fileBytes, err := ioutil.ReadFile(i.FilePath()) 72 if err != nil { 73 return nil, fmt.Errorf("can't read file %s for printing issued line: %s", i.FilePath(), err) 74 } 75 lines := bytes.Split(fileBytes, []byte("\n")) // TODO: what about \r\n? 76 fc = lines 77 p.cache[i.FilePath()] = fc 78 return fc, nil 79 } 80 81 func (p SourceCode) Finish() {}