prettify issue texts

This commit is contained in:
Denis Isaev 2018-08-18 22:15:24 +03:00 committed by Isaev Denis
parent e58c27e463
commit 284447fc07
19 changed files with 84 additions and 29 deletions

4
Gopkg.lock generated
View File

@ -146,7 +146,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:7d1f12e47120a4e50790f423446888ef01fcc1a3c17fcf9d5f1be7774cfd963c" digest = "1:bfaf14a1dd31e57f9b433739af5f0411558d9ba90566c7342c02da9a48ea8e75"
name = "github.com/golangci/govet" name = "github.com/golangci/govet"
packages = [ packages = [
".", ".",
@ -154,7 +154,7 @@
"lib/whitelist", "lib/whitelist",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "e3b43b6cb1916e0000f244f26ee752733e544429" revision = "44ddbe260190d79165f4150b828650780405d801"
[[projects]] [[projects]]
branch = "master" branch = "master"

View File

@ -39,7 +39,7 @@ func (lint Gas) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issu
res := make([]result.Issue, 0, len(issues)) res := make([]result.Issue, 0, len(issues))
for _, i := range issues { for _, i := range issues {
text := fmt.Sprintf("%s: %s", i.RuleID, i.What) // TODO: use severity and confidence text := fmt.Sprintf("%s: %s", i.RuleID, markIdentifiers(i.What)) // TODO: use severity and confidence
var r *result.Range var r *result.Range
line, err := strconv.Atoi(i.Line) line, err := strconv.Atoi(i.Line)
if err != nil { if err != nil {

View File

@ -83,9 +83,9 @@ func (g Gofmt) extractIssuesFromPatch(patch string, log logutils.Log) ([]result.
} }
} }
text := "File is not gofmt-ed with -s" text := "File is not `gofmt`-ed with `-s`"
if g.UseGoimports { if g.UseGoimports {
text = "File is not goimports-ed" text = "File is not `goimports`-ed"
} }
i := result.Issue{ i := result.Issue{
FromLinter: g.Name(), FromLinter: g.Name(),

View File

@ -60,7 +60,7 @@ func (g Golint) lintPkg(minConfidence float64, files []*ast.File, fset *token.Fi
if p.Confidence >= minConfidence { if p.Confidence >= minConfidence {
issues = append(issues, result.Issue{ issues = append(issues, result.Issue{
Pos: p.Position, Pos: p.Position,
Text: p.Text, Text: markIdentifiers(p.Text),
FromLinter: g.Name(), FromLinter: g.Name(),
}) })
// TODO: use p.Link and p.Category // TODO: use p.Link and p.Category

View File

@ -53,7 +53,7 @@ func (g Govet) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue
for _, i := range govetIssues { for _, i := range govetIssues {
res = append(res, result.Issue{ res = append(res, result.Issue{
Pos: i.Pos, Pos: i.Pos,
Text: i.Message, Text: markIdentifiers(i.Message),
FromLinter: g.Name(), FromLinter: g.Name(),
}) })
} }

View File

@ -37,7 +37,7 @@ func (lint Interfacer) Run(ctx context.Context, lintCtx *linter.Context) ([]resu
pos := lintCtx.SSAProgram.Fset.Position(i.Pos()) pos := lintCtx.SSAProgram.Fset.Position(i.Pos())
res = append(res, result.Issue{ res = append(res, result.Issue{
Pos: pos, Pos: pos,
Text: i.Message(), Text: markIdentifiers(i.Message()),
FromLinter: lint.Name(), FromLinter: lint.Name(),
}) })
} }

View File

@ -43,7 +43,6 @@ func (lint Lll) getIssuesForFile(filename string, maxLineLen int, tabSpaces stri
Pos: token.Position{ Pos: token.Position{
Filename: filename, Filename: filename,
Line: lineNumber, Line: lineNumber,
Column: 1,
}, },
Text: fmt.Sprintf("line is %d characters", lineLen), Text: fmt.Sprintf("line is %d characters", lineLen),
FromLinter: lint.Name(), FromLinter: lint.Name(),

View File

@ -112,7 +112,7 @@ func (m Megacheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.I
for _, i := range issues { for _, i := range issues {
res = append(res, result.Issue{ res = append(res, result.Issue{
Pos: i.Position, Pos: i.Position,
Text: i.Text, Text: markIdentifiers(i.Text),
FromLinter: m.Name(), FromLinter: m.Name(),
}) })
} }

View File

@ -61,7 +61,7 @@ func (lint TypeCheck) parseError(srcErr error) (*result.Issue, error) {
Line: line, Line: line,
Column: column, Column: column,
}, },
Text: message, Text: markIdentifiers(message),
FromLinter: lint.Name(), FromLinter: lint.Name(),
}, nil }, nil
} }

View File

@ -36,7 +36,7 @@ func (lint Unparam) Run(ctx context.Context, lintCtx *linter.Context) ([]result.
for _, i := range unparamIssues { for _, i := range unparamIssues {
res = append(res, result.Issue{ res = append(res, result.Issue{
Pos: lintCtx.Program.Fset.Position(i.Pos()), Pos: lintCtx.Program.Fset.Position(i.Pos()),
Text: i.Message(), Text: markIdentifiers(i.Message()),
FromLinter: lint.Name(), FromLinter: lint.Name(),
}) })
} }

View File

@ -4,7 +4,9 @@ import (
"fmt" "fmt"
"go/ast" "go/ast"
"go/token" "go/token"
"regexp"
"strings" "strings"
"sync"
"github.com/golangci/golangci-lint/pkg/lint/linter" "github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/packages" "github.com/golangci/golangci-lint/pkg/packages"
@ -28,6 +30,65 @@ func formatCodeBlock(code string, _ *config.Config) string {
return fmt.Sprintf("```\n%s\n```", code) return fmt.Sprintf("```\n%s\n```", code)
} }
type replacePattern struct {
re string
repl string
}
type replaceRegexp struct {
re *regexp.Regexp
repl string
}
var replaceRegexps []replaceRegexp
var replaceRegexpsOnce sync.Once
var replacePatterns = []replacePattern{
// unparam
{`^(\S+) - (\S+) is unused$`, "`${1}` - `${2}` is unused"},
{`^(\S+) - (\S+) always receives (\S+) \((.*)\)$`, "`${1}` - `${2}` always receives `${3}` (`${4}`)"},
{`^(\S+) - (\S+) always receives (.*)$`, "`${1}` - `${2}` always receives `${3}`"},
// interfacer
{`^(\S+) can be (\S+)$`, "`${1}` can be `${2}`"},
// govet
{`^(\S+) arg list ends with redundant newline$`, "`${1}` arg list ends with redundant newline"},
{`^(\S+) composite literal uses unkeyed fields$`, "`${1}` composite literal uses unkeyed fields"},
// gas
{`^Blacklisted import (\S+): weak cryptographic primitive$`,
"Blacklisted import `${1}`: weak cryptographic primitive"},
{`^TLS InsecureSkipVerify set true.$`, "TLS `InsecureSkipVerify` set true."},
// megacheck
{`^this value of (\S+) is never used$`, "this value of `${1}` is never used"},
{`^should use time.Since instead of time.Now().Sub$`,
"should use `time.Since` instead of `time.Now().Sub`"},
{`^(func|const|field|type) (\S+) is unused$`, "${1} `${2}` is unused"},
}
func markIdentifiers(s string) string {
replaceRegexpsOnce.Do(func() {
for _, p := range replacePatterns {
r := replaceRegexp{
re: regexp.MustCompile(p.re),
repl: p.repl,
}
replaceRegexps = append(replaceRegexps, r)
}
})
for _, rr := range replaceRegexps {
rs := rr.re.ReplaceAllString(s, rr.repl)
if rs != s {
return rs
}
}
return s
}
func getASTFilesForPkg(ctx *linter.Context, pkg *packages.Package) ([]*ast.File, *token.FileSet, error) { func getASTFilesForPkg(ctx *linter.Context, pkg *packages.Package) ([]*ast.File, *token.FileSet, error) {
filenames := pkg.Files(ctx.Cfg.Run.AnalyzeTests) filenames := pkg.Files(ctx.Cfg.Run.AnalyzeTests)
files := make([]*ast.File, 0, len(filenames)) files := make([]*ast.File, 0, len(filenames))

View File

@ -69,6 +69,7 @@ func (p Text) printSourceCode(i *result.Issue) {
} }
func (p Text) printUnderLinePointer(i *result.Issue) { func (p Text) printUnderLinePointer(i *result.Issue) {
// if column == 0 it means column is unknown (e.g. for gas)
if len(i.SourceLines) != 1 || i.Pos.Column == 0 { if len(i.SourceLines) != 1 || i.Pos.Column == 0 {
return return
} }

View File

@ -2,7 +2,7 @@
package testdata package testdata
import ( import (
"crypto/md5" // ERROR "G501: Blacklisted import crypto/md5: weak cryptographic primitive" "crypto/md5" // ERROR "G501: Blacklisted import `crypto/md5`: weak cryptographic primitive"
"log" "log"
) )

View File

@ -5,5 +5,5 @@ import "fmt"
func GofmtNotSimplified() { func GofmtNotSimplified() {
var x []string var x []string
fmt.Print(x[1:len(x)]) // ERROR "File is not gofmt-ed with -s" fmt.Print(x[1:len(x)]) // ERROR "File is not `gofmt`-ed with `-s`"
} }

View File

@ -2,7 +2,7 @@
package testdata package testdata
import ( import (
"fmt" // ERROR "File is not goimports-ed" "fmt" // ERROR "File is not `goimports`-ed"
"github.com/golangci/golangci-lint/pkg/config" "github.com/golangci/golangci-lint/pkg/config"
) )

View File

@ -7,7 +7,7 @@ import (
) )
func Govet() error { func Govet() error {
return &os.PathError{"first", "path", os.ErrNotExist} // ERROR "os.PathError composite literal uses unkeyed fields" return &os.PathError{"first", "path", os.ErrNotExist} // ERROR "`os.PathError` composite literal uses unkeyed fields"
} }
func GovetShadow(f io.Reader, buf []byte) (err error) { func GovetShadow(f io.Reader, buf []byte) (err error) {

View File

@ -3,6 +3,6 @@ package testdata
import "io" import "io"
func InterfacerCheck(f io.ReadCloser) { // ERROR "f can be io.Closer" func InterfacerCheck(f io.ReadCloser) { // ERROR "`f` can be `io.Closer`"
f.Close() f.Close()
} }

View File

@ -1,7 +1,7 @@
// args: -Eunparam // args: -Eunparam
package testdata package testdata
func unparamUnused(a, b uint) uint { // ERROR "unparamUnused - b is unused" func unparamUnused(a, b uint) uint { // ERROR "`unparamUnused` - `b` is unused"
a++ a++
return a return a
} }

View File

@ -73,19 +73,13 @@ func checkUnkeyedLiteral(f *File, node ast.Node) {
return return
} }
f.Badf(cl.Pos(), "%s composite literal uses unkeyed fields", typeName) f.Badf(cl.Pos(), "%s composite literal uses unkeyed fields",
types.TypeString(typ, func(pkg *types.Package) string {
return pkg.Name()
}))
} }
func isLocalType(f *File, typ types.Type) bool { func isLocalType(f *File, typ types.Type) bool {
structNameParts := strings.Split(typ.String(), ".")
if len(structNameParts) >= 2 {
structName := structNameParts[len(structNameParts)-1]
firstLetter := string(structName[0])
if firstLetter == strings.ToLower(firstLetter) {
return true
}
}
switch x := typ.(type) { switch x := typ.(type) {
case *types.Struct: case *types.Struct:
// struct literals are local types // struct literals are local types
@ -94,7 +88,7 @@ func isLocalType(f *File, typ types.Type) bool {
return isLocalType(f, x.Elem()) return isLocalType(f, x.Elem())
case *types.Named: case *types.Named:
// names in package foo are local to foo_test too // names in package foo are local to foo_test too
return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(f.pkg.path, "_test") return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(f.pkg.typesPkg.Path(), "_test")
} }
return false return false
} }