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, "|")))
 | 
							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.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().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`")
 | 
						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.NewDiff(e.cfg.Run.Diff, e.cfg.Run.DiffFromRevision, e.cfg.Run.DiffPatchFilePath),
 | 
				
			||||||
			processors.NewMaxPerFileFromLinter(),
 | 
								processors.NewMaxPerFileFromLinter(),
 | 
				
			||||||
			processors.NewMaxFromLinter(e.cfg.Run.MaxIssuesPerLinter),
 | 
								processors.NewMaxFromLinter(e.cfg.Run.MaxIssuesPerLinter),
 | 
				
			||||||
 | 
								processors.NewMaxSameIssues(e.cfg.Run.MaxSameIssues),
 | 
				
			||||||
			processors.NewPathPrettifier(),
 | 
								processors.NewPathPrettifier(),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -15,12 +15,21 @@ const (
 | 
				
			|||||||
var OutFormats = []string{OutFormatColoredLineNumber, OutFormatLineNumber, OutFormatJSON}
 | 
					var OutFormats = []string{OutFormatColoredLineNumber, OutFormatLineNumber, OutFormatJSON}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var DefaultExcludePatterns = []string{
 | 
					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",
 | 
						"should have comment",
 | 
				
			||||||
	"comment on exported method",
 | 
						"comment on exported method",
 | 
				
			||||||
	"G104", // disable what errcheck does: it reports on Close etc
 | 
					
 | 
				
			||||||
	"G204", // Subprocess launching should be audited: too lot false positives
 | 
						// gas
 | 
				
			||||||
	"G304", // Potential file inclusion via variable: `src, err := ioutil.ReadFile(filename)`
 | 
						"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 {
 | 
					type Common struct {
 | 
				
			||||||
@ -92,6 +101,7 @@ type Run struct { // nolint:maligned
 | 
				
			|||||||
	Deadline time.Duration
 | 
						Deadline time.Duration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	MaxIssuesPerLinter int
 | 
						MaxIssuesPerLinter int
 | 
				
			||||||
 | 
						MaxSameIssues      int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DiffFromRevision  string
 | 
						DiffFromRevision  string
 | 
				
			||||||
	DiffPatchFilePath string
 | 
						DiffPatchFilePath string
 | 
				
			||||||
 | 
				
			|||||||
@ -75,6 +75,10 @@ func (p Text) Print(issues chan result.Issue) (bool, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		lineRange := i.GetLineRange()
 | 
							lineRange := i.GetLineRange()
 | 
				
			||||||
		for line := lineRange.From; line <= lineRange.To; line++ {
 | 
							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
 | 
								zeroIndexedLine := line - 1
 | 
				
			||||||
			if zeroIndexedLine >= len(fc) {
 | 
								if zeroIndexedLine >= len(fc) {
 | 
				
			||||||
				logrus.Warnf("No line %d in file %s", line, i.FilePath())
 | 
									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
 | 
					package processors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"bufio"
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"go/ast"
 | 
						"go/ast"
 | 
				
			||||||
	"go/parser"
 | 
						"go/parser"
 | 
				
			||||||
	"go/token"
 | 
						"go/token"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/golangci/golangci-lint/pkg/result"
 | 
						"github.com/golangci/golangci-lint/pkg/result"
 | 
				
			||||||
@ -15,17 +18,21 @@ type comment struct {
 | 
				
			|||||||
	line    int
 | 
						line    int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
type fileComments []comment
 | 
					type fileComments []comment
 | 
				
			||||||
type commentsCache map[string]fileComments
 | 
					type fileData struct {
 | 
				
			||||||
 | 
						comments    fileComments
 | 
				
			||||||
 | 
						isGenerated bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					type filesCache map[string]*fileData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Nolint struct {
 | 
					type Nolint struct {
 | 
				
			||||||
	fset  *token.FileSet
 | 
						fset  *token.FileSet
 | 
				
			||||||
	cache commentsCache
 | 
						cache filesCache
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewNolint(fset *token.FileSet) *Nolint {
 | 
					func NewNolint(fset *token.FileSet) *Nolint {
 | 
				
			||||||
	return &Nolint{
 | 
						return &Nolint{
 | 
				
			||||||
		fset:  fset,
 | 
							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)
 | 
						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) {
 | 
					func (p *Nolint) shouldPassIssue(i *result.Issue) (bool, error) {
 | 
				
			||||||
	comments := p.cache[i.FilePath()]
 | 
						fd := p.cache[i.FilePath()]
 | 
				
			||||||
	if comments == nil {
 | 
						if fd == nil {
 | 
				
			||||||
		file, err := parser.ParseFile(p.fset, i.FilePath(), nil, parser.ParseComments)
 | 
							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 {
 | 
							if err != nil {
 | 
				
			||||||
			return false, fmt.Errorf("can't parse file %s", i.FilePath())
 | 
								return false, fmt.Errorf("can't parse file %s", i.FilePath())
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		comments = extractFileComments(p.fset, file.Comments...)
 | 
							fd.comments = extractFileComments(p.fset, file.Comments...)
 | 
				
			||||||
		p.cache[i.FilePath()] = 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() {
 | 
							if comment.line != i.Line() {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -29,3 +29,14 @@ func TestNolint(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	processAssertSame(t, p, newNolintFileIssue(1, "golint"))
 | 
						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