kilo/vendor/honnef.co/go/tools/lintcmd/format.go

162 lines
3.4 KiB
Go
Raw Normal View History

package lintcmd
import (
"encoding/json"
"fmt"
"go/token"
"io"
"os"
"path/filepath"
"text/tabwriter"
"honnef.co/go/tools/analysis/lint"
)
func shortPath(path string) string {
cwd, err := os.Getwd()
if err != nil {
return path
}
if rel, err := filepath.Rel(cwd, path); err == nil && len(rel) < len(path) {
return rel
}
return path
}
func relativePositionString(pos token.Position) string {
s := shortPath(pos.Filename)
if pos.IsValid() {
if s != "" {
s += ":"
}
s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
}
if s == "" {
s = "-"
}
return s
}
type statter interface {
Stats(total, errors, warnings, ignored int)
}
type formatter interface {
Format(checks []*lint.Analyzer, diagnostics []diagnostic)
}
type textFormatter struct {
W io.Writer
}
func (o textFormatter) Format(_ []*lint.Analyzer, ps []diagnostic) {
for _, p := range ps {
fmt.Fprintf(o.W, "%s: %s\n", relativePositionString(p.Position), p.String())
for _, r := range p.Related {
fmt.Fprintf(o.W, "\t%s: %s\n", relativePositionString(r.Position), r.Message)
}
}
}
type nullFormatter struct{}
func (nullFormatter) Format([]*lint.Analyzer, []diagnostic) {}
type jsonFormatter struct {
W io.Writer
}
func (o jsonFormatter) Format(_ []*lint.Analyzer, ps []diagnostic) {
type location struct {
File string `json:"file"`
Line int `json:"line"`
Column int `json:"column"`
}
type related struct {
Location location `json:"location"`
End location `json:"end"`
Message string `json:"message"`
}
enc := json.NewEncoder(o.W)
for _, p := range ps {
jp := struct {
Code string `json:"code"`
Severity string `json:"severity,omitempty"`
Location location `json:"location"`
End location `json:"end"`
Message string `json:"message"`
Related []related `json:"related,omitempty"`
}{
Code: p.Category,
Severity: p.Severity.String(),
Location: location{
File: p.Position.Filename,
Line: p.Position.Line,
Column: p.Position.Column,
},
End: location{
File: p.End.Filename,
Line: p.End.Line,
Column: p.End.Column,
},
Message: p.Message,
}
for _, r := range p.Related {
jp.Related = append(jp.Related, related{
Location: location{
File: r.Position.Filename,
Line: r.Position.Line,
Column: r.Position.Column,
},
End: location{
File: r.End.Filename,
Line: r.End.Line,
Column: r.End.Column,
},
Message: r.Message,
})
}
_ = enc.Encode(jp)
}
}
type stylishFormatter struct {
W io.Writer
prevFile string
tw *tabwriter.Writer
}
func (o *stylishFormatter) Format(_ []*lint.Analyzer, ps []diagnostic) {
for _, p := range ps {
pos := p.Position
if pos.Filename == "" {
pos.Filename = "-"
}
if pos.Filename != o.prevFile {
if o.prevFile != "" {
o.tw.Flush()
fmt.Fprintln(o.W)
}
fmt.Fprintln(o.W, pos.Filename)
o.prevFile = pos.Filename
o.tw = tabwriter.NewWriter(o.W, 0, 4, 2, ' ', 0)
}
fmt.Fprintf(o.tw, " (%d, %d)\t%s\t%s\n", pos.Line, pos.Column, p.Category, p.Message)
for _, r := range p.Related {
fmt.Fprintf(o.tw, " (%d, %d)\t\t %s\n", r.Position.Line, r.Position.Column, r.Message)
}
}
}
func (o *stylishFormatter) Stats(total, errors, warnings, ignored int) {
if o.tw != nil {
o.tw.Flush()
fmt.Fprintln(o.W)
}
fmt.Fprintf(o.W, " ✖ %d problems (%d errors, %d warnings, %d ignored)\n",
total, errors, warnings, ignored)
}