api/vendor/honnef.co/go/tools/lint/lintutil/format/format.go

163 lines
3.2 KiB
Go

// Package format provides formatters for linter problems.
package format
import (
"encoding/json"
"fmt"
"go/token"
"io"
"os"
"path/filepath"
"text/tabwriter"
"honnef.co/go/tools/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(p lint.Problem)
}
type Text struct {
W io.Writer
}
func (o Text) Format(p lint.Problem) {
fmt.Fprintf(o.W, "%s: %s\n", relativePositionString(p.Pos), p.String())
for _, r := range p.Related {
fmt.Fprintf(o.W, "\t%s: %s\n", relativePositionString(r.Pos), r.Message)
}
}
type JSON struct {
W io.Writer
}
func severity(s lint.Severity) string {
switch s {
case lint.Error:
return "error"
case lint.Warning:
return "warning"
case lint.Ignored:
return "ignored"
}
return ""
}
func (o JSON) Format(p lint.Problem) {
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"`
}
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.Check,
Severity: severity(p.Severity),
Location: location{
File: p.Pos.Filename,
Line: p.Pos.Line,
Column: p.Pos.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.Pos.Filename,
Line: r.Pos.Line,
Column: r.Pos.Column,
},
End: location{
File: r.End.Filename,
Line: r.End.Line,
Column: r.End.Column,
},
Message: r.Message,
})
}
_ = json.NewEncoder(o.W).Encode(jp)
}
type Stylish struct {
W io.Writer
prevFile string
tw *tabwriter.Writer
}
func (o *Stylish) Format(p lint.Problem) {
pos := p.Pos
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.Check, p.Message)
for _, r := range p.Related {
fmt.Fprintf(o.tw, " (%d, %d)\t\t %s\n", r.Pos.Line, r.Pos.Column, r.Message)
}
}
func (o *Stylish) 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)
}