another group of fixes after running on golang source code
This commit is contained in:
parent
d993d3a264
commit
07ddc548dc
@ -86,6 +86,7 @@ func (e *Executor) initRun() {
|
||||
fmt.Sprintf("Use or not use default excludes: (%s)", strings.Join(config.DefaultExcludePatterns, "|")))
|
||||
|
||||
runCmd.Flags().IntVar(&rc.MaxIssuesPerLinter, "max-issues-per-linter", 50, "Maximum issues count per one linter. Set to 0 to disable")
|
||||
runCmd.Flags().IntVar(&rc.MaxSameIssues, "max-same-issues", 3, "Maximum count of issues with the same text. Set to 0 to disable")
|
||||
|
||||
runCmd.Flags().BoolVarP(&rc.Diff, "new", "n", false, "Show only new issues: if there are unstaged changes or untracked files, only those changes are shown, else only changes in HEAD~ are shown")
|
||||
runCmd.Flags().StringVar(&rc.DiffFromRevision, "new-from-rev", "", "Show only new issues created after git revision `REV`")
|
||||
@ -225,6 +226,7 @@ func (e *Executor) runAnalysis(ctx context.Context, args []string) (chan result.
|
||||
processors.NewDiff(e.cfg.Run.Diff, e.cfg.Run.DiffFromRevision, e.cfg.Run.DiffPatchFilePath),
|
||||
processors.NewMaxPerFileFromLinter(),
|
||||
processors.NewMaxFromLinter(e.cfg.Run.MaxIssuesPerLinter),
|
||||
processors.NewMaxSameIssues(e.cfg.Run.MaxSameIssues),
|
||||
processors.NewPathPrettifier(),
|
||||
},
|
||||
}
|
||||
|
@ -15,12 +15,21 @@ const (
|
||||
var OutFormats = []string{OutFormatColoredLineNumber, OutFormatLineNumber, OutFormatJSON}
|
||||
|
||||
var DefaultExcludePatterns = []string{
|
||||
"Error return value of `(os\\.Std(out|err)\\.Write|.*\\.Close)` is not checked",
|
||||
// errcheck
|
||||
"Error return value of .(os\\.Std(out|err)\\.*|.*\\.Close|std(out|err)\\..*|os\\.Remove(All)?|.*[pP]rintf?). is not checked",
|
||||
|
||||
// golint
|
||||
"should have comment",
|
||||
"comment on exported method",
|
||||
"G104", // disable what errcheck does: it reports on Close etc
|
||||
"G204", // Subprocess launching should be audited: too lot false positives
|
||||
"G304", // Potential file inclusion via variable: `src, err := ioutil.ReadFile(filename)`
|
||||
|
||||
// gas
|
||||
"G103:", // Use of unsafe calls should be audited
|
||||
"G104:", // disable what errcheck does: it reports on Close etc
|
||||
"G204:", // Subprocess launching should be audited: too lot false positives
|
||||
"G304:", // Potential file inclusion via variable: `src, err := ioutil.ReadFile(filename)`
|
||||
|
||||
// govet
|
||||
"possible misuse of unsafe.Pointer",
|
||||
}
|
||||
|
||||
type Common struct {
|
||||
@ -92,6 +101,7 @@ type Run struct { // nolint:maligned
|
||||
Deadline time.Duration
|
||||
|
||||
MaxIssuesPerLinter int
|
||||
MaxSameIssues int
|
||||
|
||||
DiffFromRevision string
|
||||
DiffPatchFilePath string
|
||||
|
@ -75,6 +75,10 @@ func (p Text) Print(issues chan result.Issue) (bool, error) {
|
||||
|
||||
lineRange := i.GetLineRange()
|
||||
for line := lineRange.From; line <= lineRange.To; line++ {
|
||||
if line == 0 { // some linters, e.g. gas can do it: it really means first line
|
||||
line = 1
|
||||
}
|
||||
|
||||
zeroIndexedLine := line - 1
|
||||
if zeroIndexedLine >= len(fc) {
|
||||
logrus.Warnf("No line %d in file %s", line, i.FilePath())
|
||||
|
46
pkg/result/processors/max_same_issues.go
Normal file
46
pkg/result/processors/max_same_issues.go
Normal file
@ -0,0 +1,46 @@
|
||||
package processors
|
||||
|
||||
import (
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type textToCountMap map[string]int
|
||||
|
||||
type MaxSameIssues struct {
|
||||
tc textToCountMap
|
||||
limit int
|
||||
}
|
||||
|
||||
var _ Processor = &MaxSameIssues{}
|
||||
|
||||
func NewMaxSameIssues(limit int) *MaxSameIssues {
|
||||
return &MaxSameIssues{
|
||||
tc: textToCountMap{},
|
||||
limit: limit,
|
||||
}
|
||||
}
|
||||
|
||||
func (MaxSameIssues) Name() string {
|
||||
return "max_same_issues"
|
||||
}
|
||||
|
||||
func (p *MaxSameIssues) Process(issues []result.Issue) ([]result.Issue, error) {
|
||||
if p.limit <= 0 { // no limit
|
||||
return issues, nil
|
||||
}
|
||||
|
||||
return filterIssues(issues, func(i *result.Issue) bool {
|
||||
p.tc[i.Text]++ // always inc for stat
|
||||
return p.tc[i.Text] <= p.limit
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (p MaxSameIssues) Finish() {
|
||||
for text, count := range p.tc {
|
||||
if count > p.limit {
|
||||
logrus.Infof("%d/%d issues with text %q were hidden, use --max-same-issues",
|
||||
count-p.limit, count, text)
|
||||
}
|
||||
}
|
||||
}
|
21
pkg/result/processors/max_same_issues_test.go
Normal file
21
pkg/result/processors/max_same_issues_test.go
Normal file
@ -0,0 +1,21 @@
|
||||
package processors
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
func TestMaxSameIssues(t *testing.T) {
|
||||
p := NewMaxSameIssues(1)
|
||||
i1 := result.Issue{
|
||||
Text: "1",
|
||||
}
|
||||
i2 := result.Issue{
|
||||
Text: "2",
|
||||
}
|
||||
|
||||
processAssertSame(t, p, i1) // ok
|
||||
processAssertSame(t, p, i2) // ok: another
|
||||
processAssertEmpty(t, p, i1) // skip
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
package processors
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
@ -15,17 +18,21 @@ type comment struct {
|
||||
line int
|
||||
}
|
||||
type fileComments []comment
|
||||
type commentsCache map[string]fileComments
|
||||
type fileData struct {
|
||||
comments fileComments
|
||||
isGenerated bool
|
||||
}
|
||||
type filesCache map[string]*fileData
|
||||
|
||||
type Nolint struct {
|
||||
fset *token.FileSet
|
||||
cache commentsCache
|
||||
cache filesCache
|
||||
}
|
||||
|
||||
func NewNolint(fset *token.FileSet) *Nolint {
|
||||
return &Nolint{
|
||||
fset: fset,
|
||||
cache: commentsCache{},
|
||||
cache: filesCache{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,19 +46,53 @@ func (p *Nolint) Process(issues []result.Issue) ([]result.Issue, error) {
|
||||
return filterIssuesErr(issues, p.shouldPassIssue)
|
||||
}
|
||||
|
||||
var (
|
||||
genHdr = []byte("// Code generated ")
|
||||
genFtr = []byte(" DO NOT EDIT.")
|
||||
)
|
||||
|
||||
// isGenerated reports whether the source file is generated code
|
||||
// according the rules from https://golang.org/s/generatedcode.
|
||||
func isGenerated(src []byte) bool {
|
||||
sc := bufio.NewScanner(bytes.NewReader(src))
|
||||
for sc.Scan() {
|
||||
b := sc.Bytes()
|
||||
if bytes.HasPrefix(b, genHdr) && bytes.HasSuffix(b, genFtr) && len(b) >= len(genHdr)+len(genFtr) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Nolint) shouldPassIssue(i *result.Issue) (bool, error) {
|
||||
comments := p.cache[i.FilePath()]
|
||||
if comments == nil {
|
||||
file, err := parser.ParseFile(p.fset, i.FilePath(), nil, parser.ParseComments)
|
||||
fd := p.cache[i.FilePath()]
|
||||
if fd == nil {
|
||||
fd = &fileData{}
|
||||
p.cache[i.FilePath()] = fd
|
||||
|
||||
src, err := ioutil.ReadFile(i.FilePath())
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("can't read file %s: %s", i.FilePath(), err)
|
||||
}
|
||||
|
||||
fd.isGenerated = isGenerated(src)
|
||||
if fd.isGenerated { // don't report issues for autogenerated files
|
||||
return false, nil
|
||||
}
|
||||
|
||||
file, err := parser.ParseFile(p.fset, i.FilePath(), src, parser.ParseComments)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("can't parse file %s", i.FilePath())
|
||||
}
|
||||
|
||||
comments = extractFileComments(p.fset, file.Comments...)
|
||||
p.cache[i.FilePath()] = comments
|
||||
fd.comments = extractFileComments(p.fset, file.Comments...)
|
||||
}
|
||||
|
||||
for _, comment := range comments {
|
||||
if fd.isGenerated { // don't report issues for autogenerated files
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for _, comment := range fd.comments {
|
||||
if comment.line != i.Line() {
|
||||
continue
|
||||
}
|
||||
|
@ -29,3 +29,14 @@ func TestNolint(t *testing.T) {
|
||||
|
||||
processAssertSame(t, p, newNolintFileIssue(1, "golint"))
|
||||
}
|
||||
|
||||
func TestNoIssuesInAutogeneratedFile(t *testing.T) {
|
||||
i := result.Issue{
|
||||
Pos: token.Position{
|
||||
Filename: filepath.Join("testdata", "nolint_autogenerated.go"),
|
||||
Line: 4,
|
||||
},
|
||||
}
|
||||
p := NewNolint(token.NewFileSet())
|
||||
processAssertEmpty(t, p, i)
|
||||
}
|
||||
|
4
pkg/result/processors/testdata/nolint_autogenerated.go
vendored
Normal file
4
pkg/result/processors/testdata/nolint_autogenerated.go
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
// Code generated by ... DO NOT EDIT.
|
||||
package testdata
|
||||
|
||||
var v int
|
Loading…
x
Reference in New Issue
Block a user