another group of fixes after running on golang source code

This commit is contained in:
golangci 2018-05-08 18:08:28 +03:00
parent d993d3a264
commit 07ddc548dc
8 changed files with 152 additions and 13 deletions

View File

@ -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(),
},
}

View File

@ -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

View File

@ -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())

View 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)
}
}
}

View 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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -0,0 +1,4 @@
// Code generated by ... DO NOT EDIT.
package testdata
var v int