diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2020-09-15 18:05:35 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2020-09-15 19:34:30 +0200 |
| commit | 712de1c63d9db97c81af68cd0dc4372c53d2e57a (patch) | |
| tree | ae1761fec52c3ae4ddd003a4130ddbda8d0a2d69 /vendor/github.com/golangci | |
| parent | 298a69c38dd5c8a9bbd7a022e88f4ddbcf885e16 (diff) | |
vendor/github.com/golangci/golangci-lint: update to v1.31
Diffstat (limited to 'vendor/github.com/golangci')
39 files changed, 1240 insertions, 265 deletions
diff --git a/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go b/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go index ae5b7da18..51c75a77d 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go +++ b/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go @@ -81,7 +81,7 @@ func (c *Cache) fileName(id [HashSize]byte, key string) string { var errMissing = errors.New("cache entry not found") func IsErrMissing(err error) bool { - return err == errMissing + return errors.Cause(err) == errMissing } const ( @@ -199,26 +199,6 @@ func (c *Cache) get(id ActionID) (Entry, error) { return Entry{buf, size, time.Unix(0, tm)}, nil } -// GetFile looks up the action ID in the cache and returns -// the name of the corresponding data file. -func (c *Cache) GetFile(id ActionID) (file string, entry Entry, err error) { - entry, err = c.Get(id) - if err != nil { - return "", Entry{}, err - } - - file, err = c.OutputFile(entry.OutputID) - if err != nil { - return "", Entry{}, err - } - - info, err := os.Stat(file) - if err != nil || info.Size() != entry.Size { - return "", Entry{}, errMissing - } - return file, entry, nil -} - // GetBytes looks up the action ID in the cache and returns // the corresponding output bytes. // GetBytes should only be used for data that can be expected to fit in memory. @@ -282,6 +262,9 @@ const ( func (c *Cache) used(file string) error { info, err := os.Stat(file) if err != nil { + if os.IsNotExist(err) { + return errMissing + } return errors.Wrapf(err, "failed to stat file %s", file) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go b/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go index 9581acab2..0becc9900 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go @@ -218,11 +218,15 @@ func (e *Executor) acquireFileLock() bool { lockFile := filepath.Join(os.TempDir(), "golangci-lint.lock") e.debugf("Locking on file %s...", lockFile) f := flock.New(lockFile) - const totalTimeout = 5 * time.Second const retryDelay = time.Second - ctx, finish := context.WithTimeout(context.Background(), totalTimeout) - defer finish() + ctx := context.Background() + if !e.cfg.Run.AllowSerialRunners { + const totalTimeout = 5 * time.Second + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, totalTimeout) + defer cancel() + } if ok, _ := f.TryLockContext(ctx, retryDelay); !ok { return false } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go b/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go index e4887d587..57cb5471f 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go @@ -80,7 +80,9 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config, m *lintersdb.Manager, is fs.BoolVar(&oc.PrintIssuedLine, "print-issued-lines", true, wh("Print lines of code with issue")) fs.BoolVar(&oc.PrintLinterName, "print-linter-name", true, wh("Print linter name in issue line")) fs.BoolVar(&oc.UniqByLine, "uniq-by-line", true, wh("Make issues output unique by line")) + fs.BoolVar(&oc.SortResults, "sort-results", false, wh("Sort linter results")) fs.BoolVar(&oc.PrintWelcomeMessage, "print-welcome", false, wh("Print welcome message")) + fs.StringVar(&oc.PathPrefix, "path-prefix", "", wh("Path prefix to add to output")) hideFlag("print-welcome") // no longer used // Run config @@ -109,6 +111,9 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config, m *lintersdb.Manager, is const allowParallelDesc = "Allow multiple parallel golangci-lint instances running. " + "If false (default) - golangci-lint acquires file lock on start." fs.BoolVar(&rc.AllowParallelRunners, "allow-parallel-runners", false, wh(allowParallelDesc)) + const allowSerialDesc = "Allow multiple golangci-lint instances running, but serialize them around a lock. " + + "If false (default) - golangci-lint exits with an error if it fails to acquire file lock on start." + fs.BoolVar(&rc.AllowSerialRunners, "allow-serial-runners", false, wh(allowSerialDesc)) // Linters settings config lsc := &cfg.LintersSettings @@ -232,6 +237,7 @@ func (e *Executor) getConfigForCommandLine() (*config.Config, error) { // Use another config variable here, not e.cfg, to not // affect main parsing by this parsing of only config option. initFlagSet(fs, &cfg, e.DBManager, false) + initVersionFlagSet(fs, &cfg) // Parse max options, even force version option: don't want // to get access to Executor here: it's error-prone to use @@ -446,8 +452,8 @@ func (e *Executor) executeRun(_ *cobra.Command, args []string) { // to be removed when deadline is finally decommissioned func (e *Executor) setTimeoutToDeadlineIfOnlyDeadlineIsSet() { - //lint:ignore SA1019 We want to promoted the deprecated config value when needed - deadlineValue := e.cfg.Run.Deadline // nolint:staticcheck + // nolint:staticcheck + deadlineValue := e.cfg.Run.Deadline if deadlineValue != 0 && e.cfg.Run.Timeout == defaultTimeout { e.cfg.Run.Timeout = deadlineValue } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/version.go b/vendor/github.com/golangci/golangci-lint/pkg/commands/version.go index fdb5aa884..3918d6b7b 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/version.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/commands/version.go @@ -1,17 +1,59 @@ package commands import ( + "encoding/json" + "strings" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/golangci/golangci-lint/pkg/config" ) +type jsonVersion struct { + Version string `json:"version"` + Commit string `json:"commit"` + Date string `json:"date"` +} + +func (e *Executor) initVersionConfiguration(cmd *cobra.Command) { + fs := cmd.Flags() + fs.SortFlags = false // sort them as they are defined here + initVersionFlagSet(fs, e.cfg) +} + +func initVersionFlagSet(fs *pflag.FlagSet, cfg *config.Config) { + // Version config + vc := &cfg.Version + fs.StringVar(&vc.Format, "format", "", wh("The version's format can be: 'short', 'json'")) +} + func (e *Executor) initVersion() { versionCmd := &cobra.Command{ Use: "version", Short: "Version", - Run: func(cmd *cobra.Command, _ []string) { - cmd.Printf("golangci-lint has version %s built from %s on %s\n", e.version, e.commit, e.date) + RunE: func(cmd *cobra.Command, _ []string) error { + switch strings.ToLower(e.cfg.Version.Format) { + case "short": + cmd.Println(e.version) + case "json": + ver := jsonVersion{ + Version: e.version, + Commit: e.commit, + Date: e.date, + } + data, err := json.Marshal(&ver) + if err != nil { + return err + } + cmd.Println(string(data)) + default: + cmd.Printf("golangci-lint has version %s built from %s on %s\n", e.version, e.commit, e.date) + } + return nil }, } e.rootCmd.AddCommand(versionCmd) + e.initVersionConfiguration(versionCmd) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/config.go b/vendor/github.com/golangci/golangci-lint/pkg/config/config.go index 89e3559c1..9689ea092 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/config.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/config/config.go @@ -152,9 +152,13 @@ type Run struct { UseDefaultSkipDirs bool `mapstructure:"skip-dirs-use-default"` AllowParallelRunners bool `mapstructure:"allow-parallel-runners"` + AllowSerialRunners bool `mapstructure:"allow-serial-runners"` } type LintersSettings struct { + Gci struct { + LocalPrefixes string `mapstructure:"local-prefixes"` + } Govet GovetSettings Golint struct { MinConfidence float64 `mapstructure:"min-confidence"` @@ -221,6 +225,10 @@ type LintersSettings struct { Recommendations []string `mapstructure:"recommendations"` Reason string `mapstructure:"reason"` } `mapstructure:"modules"` + Versions []map[string]struct { + Version string `mapstructure:"version"` + Reason string `mapstructure:"reason"` + } `mapstructure:"versions"` } `mapstructure:"blocked"` } @@ -235,13 +243,22 @@ type LintersSettings struct { Dogsled DogsledSettings Gocognit GocognitSettings Godot GodotSettings + Goheader GoHeaderSettings Testpackage TestpackageSettings Nestif NestifSettings NoLintLint NoLintLintSettings + Exhaustive ExhaustiveSettings + Gofumpt GofumptSettings Custom map[string]CustomLinterSettings } +type GoHeaderSettings struct { + Values map[string]map[string]string `mapstructure:"values"` + Template string `mapstructure:"template"` + TemplatePath string `mapstructure:"template-path"` +} + type GovetSettings struct { CheckShadowing bool `mapstructure:"check-shadowing"` Settings map[string]map[string]interface{} @@ -335,6 +352,14 @@ type NestifSettings struct { MinComplexity int `mapstructure:"min-complexity"` } +type ExhaustiveSettings struct { + DefaultSignifiesExhaustive bool `mapstructure:"default-signifies-exhaustive"` +} + +type GofumptSettings struct { + ExtraRules bool `mapstructure:"extra-rules"` +} + var defaultLintersSettings = LintersSettings{ Lll: LllSettings{ LineLength: 120, @@ -385,6 +410,12 @@ var defaultLintersSettings = LintersSettings{ Nestif: NestifSettings{ MinComplexity: 5, }, + Exhaustive: ExhaustiveSettings{ + DefaultSignifiesExhaustive: false, + }, + Gofumpt: GofumptSettings{ + ExtraRules: false, + }, } type CustomLinterSettings struct { @@ -403,51 +434,71 @@ type Linters struct { Presets []string } -type ExcludeRule struct { +type BaseRule struct { Linters []string Path string Text string Source string } -func validateOptionalRegex(value string) error { - if value == "" { - return nil - } - _, err := regexp.Compile(value) - return err -} - -func (e ExcludeRule) Validate() error { - if err := validateOptionalRegex(e.Path); err != nil { +func (b BaseRule) Validate(minConditionsCount int) error { + if err := validateOptionalRegex(b.Path); err != nil { return fmt.Errorf("invalid path regex: %v", err) } - if err := validateOptionalRegex(e.Text); err != nil { + if err := validateOptionalRegex(b.Text); err != nil { return fmt.Errorf("invalid text regex: %v", err) } - if err := validateOptionalRegex(e.Source); err != nil { + if err := validateOptionalRegex(b.Source); err != nil { return fmt.Errorf("invalid source regex: %v", err) } nonBlank := 0 - if len(e.Linters) > 0 { + if len(b.Linters) > 0 { nonBlank++ } - if e.Path != "" { + if b.Path != "" { nonBlank++ } - if e.Text != "" { + if b.Text != "" { nonBlank++ } - if e.Source != "" { + if b.Source != "" { nonBlank++ } - const minConditionsCount = 2 if nonBlank < minConditionsCount { - return errors.New("at least 2 of (text, source, path, linters) should be set") + return fmt.Errorf("at least %d of (text, source, path, linters) should be set", minConditionsCount) } return nil } +const excludeRuleMinConditionsCount = 2 + +type ExcludeRule struct { + BaseRule `mapstructure:",squash"` +} + +func validateOptionalRegex(value string) error { + if value == "" { + return nil + } + _, err := regexp.Compile(value) + return err +} + +func (e ExcludeRule) Validate() error { + return e.BaseRule.Validate(excludeRuleMinConditionsCount) +} + +const severityRuleMinConditionsCount = 1 + +type SeverityRule struct { + BaseRule `mapstructure:",squash"` + Severity string +} + +func (s *SeverityRule) Validate() error { + return s.BaseRule.Validate(severityRuleMinConditionsCount) +} + type Issues struct { IncludeDefaultExcludes []string `mapstructure:"include"` ExcludeCaseSensitive bool `mapstructure:"exclude-case-sensitive"` @@ -465,21 +516,35 @@ type Issues struct { NeedFix bool `mapstructure:"fix"` } +type Severity struct { + Default string `mapstructure:"default-severity"` + CaseSensitive bool `mapstructure:"case-sensitive"` + Rules []SeverityRule `mapstructure:"rules"` +} + +type Version struct { + Format string `mapstructure:"format"` +} + type Config struct { Run Run Output struct { Format string Color string - PrintIssuedLine bool `mapstructure:"print-issued-lines"` - PrintLinterName bool `mapstructure:"print-linter-name"` - UniqByLine bool `mapstructure:"uniq-by-line"` - PrintWelcomeMessage bool `mapstructure:"print-welcome"` + PrintIssuedLine bool `mapstructure:"print-issued-lines"` + PrintLinterName bool `mapstructure:"print-linter-name"` + UniqByLine bool `mapstructure:"uniq-by-line"` + SortResults bool `mapstructure:"sort-results"` + PrintWelcomeMessage bool `mapstructure:"print-welcome"` + PathPrefix string `mapstructure:"path-prefix"` } LintersSettings LintersSettings `mapstructure:"linters-settings"` Linters Linters Issues Issues + Severity Severity + Version Version InternalTest bool // Option is used only for testing golangci-lint code, don't use it } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/config_gocritic.go b/vendor/github.com/golangci/golangci-lint/pkg/config/config_gocritic.go index bbfd7bb13..26317a678 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/config_gocritic.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/config/config_gocritic.go @@ -5,7 +5,7 @@ import ( "sort" "strings" - "github.com/go-lintpack/lintpack" + "github.com/go-critic/go-critic/framework/linter" "github.com/pkg/errors" _ "github.com/go-critic/go-critic/checkers" // this import register checkers @@ -18,9 +18,9 @@ const gocriticDebugKey = "gocritic" var ( gocriticDebugf = logutils.Debug(gocriticDebugKey) isGocriticDebug = logutils.HaveDebugTag(gocriticDebugKey) - allGocriticCheckers = lintpack.GetCheckersInfo() - allGocriticCheckerMap = func() map[string]*lintpack.CheckerInfo { - checkInfoMap := make(map[string]*lintpack.CheckerInfo) + allGocriticCheckers = linter.GetCheckersInfo() + allGocriticCheckerMap = func() map[string]*linter.CheckerInfo { + checkInfoMap := make(map[string]*linter.CheckerInfo) for _, checkInfo := range allGocriticCheckers { checkInfoMap[checkInfo.Name] = checkInfo } @@ -281,7 +281,7 @@ func getAllCheckerNames() map[string]bool { return allCheckerNames } -func isEnabledByDefaultGocriticCheck(info *lintpack.CheckerInfo) bool { +func isEnabledByDefaultGocriticCheck(info *linter.CheckerInfo) bool { return !info.HasTag("experimental") && !info.HasTag("opinionated") && !info.HasTag("performance") @@ -290,9 +290,6 @@ func isEnabledByDefaultGocriticCheck(info *lintpack.CheckerInfo) bool { func getDefaultEnabledGocriticCheckersNames() []string { var enabled []string for _, info := range allGocriticCheckers { - // get in sync with lintpack behavior in bindDefaultEnabledList - // in https://github.com/go-lintpack/lintpack/blob/master/linter/lintmain/internal/check/check.go#L317 - enable := isEnabledByDefaultGocriticCheck(info) if enable { enabled = append(enabled, info.Name) @@ -305,9 +302,6 @@ func getDefaultEnabledGocriticCheckersNames() []string { func getDefaultDisabledGocriticCheckersNames() []string { var disabled []string for _, info := range allGocriticCheckers { - // get in sync with lintpack behavior in bindDefaultEnabledList - // in https://github.com/go-lintpack/lintpack/blob/master/linter/lintmain/internal/check/check.go#L317 - enable := isEnabledByDefaultGocriticCheck(info) if !enable { disabled = append(disabled, info.Name) diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/reader.go b/vendor/github.com/golangci/golangci-lint/pkg/config/reader.go index 1e355e722..00722ba63 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/reader.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/config/reader.go @@ -12,6 +12,7 @@ import ( "github.com/golangci/golangci-lint/pkg/fsutils" "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/pkg/sliceutil" ) type FileReader struct { @@ -113,6 +114,14 @@ func (r *FileReader) validateConfig() error { return fmt.Errorf("error in exclude rule #%d: %v", i, err) } } + if len(c.Severity.Rules) > 0 && c.Severity.Default == "" { + return errors.New("can't set severity rule option: no default severity defined") + } + for i, rule := range c.Severity.Rules { + if err := rule.Validate(); err != nil { + return fmt.Errorf("error in severity rule #%d: %v", i, err) + } + } if err := c.LintersSettings.Govet.Validate(); err != nil { return fmt.Errorf("error in govet config: %v", err) } @@ -162,6 +171,7 @@ func (r *FileReader) setupConfigFileSearch() { // find all dirs from it up to the root configSearchPaths := []string{"./"} + for { configSearchPaths = append(configSearchPaths, curDir) newCurDir := filepath.Dir(curDir) @@ -171,6 +181,13 @@ func (r *FileReader) setupConfigFileSearch() { curDir = newCurDir } + // find home directory for global config + if home, err := homedir.Dir(); err != nil { + r.log.Warnf("Can't get user's home directory: %s", err.Error()) + } else if !sliceutil.Contains(configSearchPaths, home) { + configSearchPaths = append(configSearchPaths, home) + } + r.log.Infof("Config search paths: %s", configSearchPaths) viper.SetConfigName(".golangci") for _, p := range configSearchPaths { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive.go new file mode 100644 index 000000000..cae37ecc6 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive.go @@ -0,0 +1,25 @@ +package golinters + +import ( + "github.com/nishanths/exhaustive" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewExhaustive(settings *config.ExhaustiveSettings) *goanalysis.Linter { + a := exhaustive.Analyzer + + var cfg map[string]map[string]interface{} + if settings != nil { + cfg = map[string]map[string]interface{}{ + a.Name: { + exhaustive.DefaultSignifiesExhaustiveFlag: settings.DefaultSignifiesExhaustive, + }, + } + } + + return goanalysis.NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/exportloopref.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/exportloopref.go new file mode 100644 index 000000000..1131c575b --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/exportloopref.go @@ -0,0 +1,19 @@ +package golinters + +import ( + "github.com/kyoh86/exportloopref" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewExportLoopRef() *goanalysis.Linter { + a := exportloopref.Analyzer + + return goanalysis.NewLinter( + a.Name, + a.Doc, + []*analysis.Analyzer{a}, + nil, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gci.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gci.go new file mode 100644 index 000000000..6fa43544e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gci.go @@ -0,0 +1,92 @@ +package golinters + +import ( + "bytes" + "fmt" + "sync" + + "github.com/daixiang0/gci/pkg/gci" + "github.com/pkg/errors" + "github.com/shazow/go-diff/difflib" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" + "github.com/golangci/golangci-lint/pkg/lint/linter" +) + +const gciName = "gci" + +func NewGci() *goanalysis.Linter { + var mu sync.Mutex + var resIssues []goanalysis.Issue + differ := difflib.New() + + analyzer := &analysis.Analyzer{ + Name: gciName, + Doc: goanalysis.TheOnlyanalyzerDoc, + } + return goanalysis.NewLinter( + gciName, + "Gci control golang package import order and make it always deterministic.", + []*analysis.Analyzer{analyzer}, + nil, + ).WithContextSetter(func(lintCtx *linter.Context) { + localFlag := lintCtx.Settings().Gci.LocalPrefixes + goimportsFlag := lintCtx.Settings().Goimports.LocalPrefixes + if localFlag == "" && goimportsFlag != "" { + localFlag = goimportsFlag + } + + analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { + var fileNames []string + for _, f := range pass.Files { + pos := pass.Fset.PositionFor(f.Pos(), false) + fileNames = append(fileNames, pos.Filename) + } + + var issues []goanalysis.Issue + + for _, f := range fileNames { + source, result, err := gci.Run(f, &gci.FlagSet{LocalFlag: localFlag}) + if err != nil { + return nil, err + } + if result == nil { + continue + } + + diff := bytes.Buffer{} + _, err = diff.WriteString(fmt.Sprintf("--- %[1]s\n+++ %[1]s\n", f)) + if err != nil { + return nil, fmt.Errorf("can't write diff header: %v", err) + } + + err = differ.Diff(&diff, bytes.NewReader(source), bytes.NewReader(result)) + if err != nil { + return nil, fmt.Errorf("can't get gci diff output: %v", err) + } + + is, err := extractIssuesFromPatch(diff.String(), lintCtx.Log, lintCtx, gciName) + if err != nil { + return nil, errors.Wrapf(err, "can't extract issues from gci diff output %q", diff.String()) + } + + for i := range is { + issues = append(issues, goanalysis.NewIssue(&is[i], pass)) + } + } + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + } + }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { + return resIssues + }).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner.go index d07294245..db193f37b 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner.go @@ -935,7 +935,8 @@ func sizeOfReflectValueTreeBytes(rv reflect.Value, visitedPtrs map[uintptr]struc return rv.Len() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, - reflect.Uintptr, reflect.Bool, reflect.Float32, reflect.Float64, reflect.UnsafePointer: + reflect.Uintptr, reflect.Bool, reflect.Float32, reflect.Float64, + reflect.Complex64, reflect.Complex128, reflect.Func, reflect.UnsafePointer: return int(rv.Type().Size()) case reflect.Invalid: return 0 diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic.go index fb2925209..7181c4863 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic.go @@ -10,7 +10,7 @@ import ( "strings" "sync" - "github.com/go-lintpack/lintpack" + gocriticlinter "github.com/go-critic/go-critic/framework/linter" "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/pkg/config" @@ -38,15 +38,15 @@ func NewGocritic() *goanalysis.Linter { nil, ).WithContextSetter(func(lintCtx *linter.Context) { analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { - lintpackCtx := lintpack.NewContext(pass.Fset, sizes) - enabledCheckers, err := buildEnabledCheckers(lintCtx, lintpackCtx) + linterCtx := gocriticlinter.NewContext(pass.Fset, sizes) + enabledCheckers, err := buildEnabledCheckers(lintCtx, linterCtx) if err != nil { return nil, err } - lintpackCtx.SetPackageInfo(pass.TypesInfo, pass.Pkg) + linterCtx.SetPackageInfo(pass.TypesInfo, pass.Pkg) var res []goanalysis.Issue - pkgIssues := runGocriticOnPackage(lintpackCtx, enabledCheckers, pass.Files) + pkgIssues := runGocriticOnPackage(linterCtx, enabledCheckers, pass.Files) for i := range pkgIssues { res = append(res, goanalysis.NewIssue(&pkgIssues[i], pass)) } @@ -65,9 +65,9 @@ func NewGocritic() *goanalysis.Linter { }).WithLoadMode(goanalysis.LoadModeTypesInfo) } -func normalizeCheckerInfoParams(info *lintpack.CheckerInfo) lintpack.CheckerParams { +func normalizeCheckerInfoParams(info *gocriticlinter.CheckerInfo) gocriticlinter.CheckerParams { // lowercase info param keys here because golangci-lint's config parser lowercases all strings - ret := lintpack.CheckerParams{} + ret := gocriticlinter.CheckerParams{} for k, v := range info.Params { ret[strings.ToLower(k)] = v } @@ -75,7 +75,7 @@ func normalizeCheckerInfoParams(info *lintpack.CheckerInfo) lintpack.CheckerPara return ret } -func configureCheckerInfo(info *lintpack.CheckerInfo, allParams map[string]config.GocriticCheckSettings) error { +func configureCheckerInfo(info *gocriticlinter.CheckerInfo, allParams map[string]config.GocriticCheckSettings) error { params := allParams[strings.ToLower(info.Name)] if params == nil { // no config for this checker return nil @@ -108,12 +108,12 @@ func configureCheckerInfo(info *lintpack.CheckerInfo, allParams map[string]confi return nil } -func buildEnabledCheckers(lintCtx *linter.Context, lintpackCtx *lintpack.Context) ([]*lintpack.Checker, error) { +func buildEnabledCheckers(lintCtx *linter.Context, linterCtx *gocriticlinter.Context) ([]*gocriticlinter.Checker, error) { s := lintCtx.Settings().Gocritic allParams := s.GetLowercasedParams() - var enabledCheckers []*lintpack.Checker - for _, info := range lintpack.GetCheckersInfo() { + var enabledCheckers []*gocriticlinter.Checker + for _, info := range gocriticlinter.GetCheckersInfo() { if !s.IsCheckEnabled(info.Name) { continue } @@ -122,27 +122,27 @@ func buildEnabledCheckers(lintCtx *linter.Context, lintpackCtx *lintpack.Context return nil, err } - c := lintpack.NewChecker(lintpackCtx, info) + c := gocriticlinter.NewChecker(linterCtx, info) enabledCheckers = append(enabledCheckers, c) } return enabledCheckers, nil } -func runGocriticOnPackage(lintpackCtx *lintpack.Context, checkers []*lintpack.Checker, +func runGocriticOnPackage(linterCtx *gocriticlinter.Context, checkers []*gocriticlinter.Checker, files []*ast.File) []result.Issue { var res []result.Issue for _, f := range files { - filename := filepath.Base(lintpackCtx.FileSet.Position(f.Pos()).Filename) - lintpackCtx.SetFileInfo(filename, f) + filename := filepath.Base(linterCtx.FileSet.Position(f.Pos()).Filename) + linterCtx.SetFileInfo(filename, f) - issues := runGocriticOnFile(lintpackCtx, f, checkers) + issues := runGocriticOnFile(linterCtx, f, checkers) res = append(res, issues...) } return res } -func runGocriticOnFile(ctx *lintpack.Context, f *ast.File, checkers []*lintpack.Checker) []result.Issue { +func runGocriticOnFile(ctx *gocriticlinter.Context, f *ast.File, checkers []*gocriticlinter.Checker) []result.Issue { var res []result.Issue for _, c := range checkers { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/godot.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/godot.go index 7e5b233a6..5139713c4 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/godot.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/godot.go @@ -31,7 +31,7 @@ func NewGodot() *goanalysis.Linter { settings := godot.Settings{CheckAll: cfg.CheckAll} analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { - var issues []godot.Message + var issues []godot.Issue for _, file := range pass.Files { issues = append(issues, godot.Run(file, pass.Fset, settings)...) } @@ -46,6 +46,9 @@ func NewGodot() *goanalysis.Linter { Pos: i.Pos, Text: i.Message, FromLinter: godotName, + Replacement: &result.Replacement{ + NewLines: []string{i.Replacement}, + }, } res[k] = goanalysis.NewIssue(&issue, pass) diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt.go index a7bd88a73..aa340dcf3 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt.go @@ -46,7 +46,7 @@ func NewGofmt() *goanalysis.Linter { continue } - is, err := extractIssuesFromPatch(string(diff), lintCtx.Log, lintCtx, false) + is, err := extractIssuesFromPatch(string(diff), lintCtx.Log, lintCtx, gofmtName) if err != nil { return nil, errors.Wrapf(err, "can't extract issues from gofmt diff output %q", string(diff)) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt_common.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt_common.go index fb1e3f662..3235622e8 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt_common.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt_common.go @@ -207,7 +207,40 @@ func (p *hunkChangesParser) parse(h *diffpkg.Hunk) []Change { return p.ret } -func extractIssuesFromPatch(patch string, log logutils.Log, lintCtx *linter.Context, isGoimports bool) ([]result.Issue, error) { +func getErrorTextForLinter(lintCtx *linter.Context, linterName string) string { + text := "File is not formatted" + switch linterName { + case gofumptName: + text = "File is not `gofumpt`-ed" + if lintCtx.Settings().Gofumpt.ExtraRules { + text += " with `-extra`" + } + case gofmtName: + text = "File is not `gofmt`-ed" + if lintCtx.Settings().Gofmt.Simplify { + text += " with `-s`" + } + case goimportsName: + text = "File is not `goimports`-ed" + if lintCtx.Settings().Goimports.LocalPrefixes != "" { + text += " with -local " + lintCtx.Settings().Goimports.LocalPrefixes + } + case gciName: + text = "File is not `gci`-ed" + localPrefixes := lintCtx.Settings().Gci.LocalPrefixes + goimportsFlag := lintCtx.Settings().Goimports.LocalPrefixes + if localPrefixes == "" && goimportsFlag != "" { + localPrefixes = goimportsFlag + } + + if localPrefixes != "" { + text += " with -local " + localPrefixes + } + } + return text +} + +func extractIssuesFromPatch(patch string, log logutils.Log, lintCtx *linter.Context, linterName string) ([]result.Issue, error) { diffs, err := diffpkg.ParseMultiFileDiff([]byte(patch)) if err != nil { return nil, errors.Wrap(err, "can't parse patch") @@ -225,35 +258,19 @@ func extractIssuesFromPatch(patch string, log logutils.Log, lintCtx *linter.Cont } for _, hunk := range d.Hunks { - var text string - if isGoimports { - text = "File is not `goimports`-ed" - if lintCtx.Settings().Goimports.LocalPrefixes != "" { - text += " with -local " + lintCtx.Settings().Goimports.LocalPrefixes - } - } else { - text = "File is not `gofmt`-ed" - if lintCtx.Settings().Gofmt.Simplify { - text += " with `-s`" - } - } p := hunkChangesParser{ log: log, } changes := p.parse(hunk) for _, change := range changes { change := change // fix scope - linterName := gofmtName - if isGoimports { - linterName = goimportsName - } i := result.Issue{ FromLinter: linterName, Pos: token.Position{ Filename: d.NewName, Line: change.LineRange.From, }, - Text: text, + Text: getErrorTextForLinter(lintCtx, linterName), Replacement: &change.Replacement, } if change.LineRange.From != change.LineRange.To { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofumpt.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofumpt.go new file mode 100644 index 000000000..e91e54eea --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofumpt.go @@ -0,0 +1,92 @@ +package golinters + +import ( + "bytes" + "fmt" + "io/ioutil" + "sync" + + "github.com/pkg/errors" + "github.com/shazow/go-diff/difflib" + "golang.org/x/tools/go/analysis" + "mvdan.cc/gofumpt/format" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" + "github.com/golangci/golangci-lint/pkg/lint/linter" +) + +const gofumptName = "gofumpt" + +func NewGofumpt() *goanalysis.Linter { + var mu sync.Mutex + var resIssues []goanalysis.Issue + differ := difflib.New() + + analyzer := &analysis.Analyzer{ + Name: gofumptName, + Doc: goanalysis.TheOnlyanalyzerDoc, + } + return goanalysis.NewLinter( + gofumptName, + "Gofumpt checks whether code was gofumpt-ed.", + []*analysis.Analyzer{analyzer}, + nil, + ).WithContextSetter(func(lintCtx *linter.Context) { + analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { + var fileNames []string + for _, f := range pass.Files { + pos := pass.Fset.PositionFor(f.Pos(), false) + fileNames = append(fileNames, pos.Filename) + } + + var issues []goanalysis.Issue + + for _, f := range fileNames { + input, err := ioutil.ReadFile(f) + if err != nil { + return nil, fmt.Errorf("unable to open file %s: %w", f, err) + } + output, err := format.Source(input, format.Options{ + ExtraRules: lintCtx.Settings().Gofumpt.ExtraRules, + }) + if err != nil { + return nil, fmt.Errorf("error while running gofumpt: %w", err) + } + if !bytes.Equal(input, output) { + out := bytes.Buffer{} + _, err = out.WriteString(fmt.Sprintf("--- %[1]s\n+++ %[1]s\n", f)) + if err != nil { + return nil, fmt.Errorf("error while running gofumpt: %w", err) + } + + err = differ.Diff(&out, bytes.NewReader(input), bytes.NewReader(output)) + if err != nil { + return nil, fmt.Errorf("error while running gofumpt: %w", err) + } + + diff := out.String() + is, err := extractIssuesFromPatch(diff, lintCtx.Log, lintCtx, gofumptName) + if err != nil { + return nil, errors.Wrapf(err, "can't extract issues from gofumpt diff output %q", diff) + } + + for i := range is { + issues = append(issues, goanalysis.NewIssue(&is[i], pass)) + } + } + } + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + } + }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { + return resIssues + }).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goheader.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goheader.go new file mode 100644 index 000000000..8517e173d --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goheader.go @@ -0,0 +1,81 @@ +package golinters + +import ( + "go/token" + "sync" + + goheader "github.com/denis-tingajkin/go-header" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" + "github.com/golangci/golangci-lint/pkg/lint/linter" + "github.com/golangci/golangci-lint/pkg/result" +) + +const goHeaderName = "goheader" + +func NewGoHeader() *goanalysis.Linter { + var mu sync.Mutex + var issues []goanalysis.Issue + + analyzer := &analysis.Analyzer{ + Name: goHeaderName, + Doc: goanalysis.TheOnlyanalyzerDoc, + } + return goanalysis.NewLinter( + goHeaderName, + "Checks is file header matches to pattern", + []*analysis.Analyzer{analyzer}, + nil, + ).WithContextSetter(func(lintCtx *linter.Context) { + cfg := lintCtx.Cfg.LintersSettings.Goheader + c := &goheader.Configuration{ + Values: cfg.Values, + Template: cfg.Template, + TemplatePath: cfg.TemplatePath, + } + analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { + if c.TemplatePath == "" && c.Template == "" { + // User did not pass template, so then do not run go-header linter + return nil, nil + } + template, err := c.GetTemplate() + if err != nil { + return nil, err + } + values, err := c.GetValues() + if err != nil { + return nil, err + } + a := goheader.New(goheader.WithTemplate(template), goheader.WithValues(values)) + var res []goanalysis.Issue + for _, file := range pass.Files { + i := a.Analyze(file) + if i == nil { + continue + } + issue := result.Issue{ + Pos: token.Position{ + Line: i.Location().Line + 1, + Column: i.Location().Position, + Filename: pass.Fset.Position(file.Pos()).Filename, + }, + Text: i.Message(), + FromLinter: goHeaderName, + } + res = append(res, goanalysis.NewIssue(&issue, pass)) + } + if len(res) == 0 { + return nil, nil + } + + mu.Lock() + issues = append(issues, res...) + mu.Unlock() + + return nil, nil + } + }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { + return issues + }).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports.go index 97767db8b..9ea4558f4 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports.go @@ -47,7 +47,7 @@ func NewGoimports() *goanalysis.Linter { continue } - is, err := extractIssuesFromPatch(string(diff), lintCtx.Log, lintCtx, true) + is, err := extractIssuesFromPatch(string(diff), lintCtx.Log, lintCtx, goimportsName) if err != nil { return nil, errors.Wrapf(err, "can't extract issues from gofmt diff output %q", string(diff)) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomodguard.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomodguard.go index 5b1406313..1376ad157 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomodguard.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomodguard.go @@ -30,7 +30,9 @@ func NewGomodguard() *goanalysis.Linter { return goanalysis.NewLinter( gomodguardName, - "Allow and block list linter for direct Go module dependencies.", + "Allow and block list linter for direct Go module dependencies. "+ + "This is different from depguard where there are different block "+ + "types for example version constraints and module recommendations.", []*analysis.Analyzer{analyzer}, nil, ).WithContextSetter(func(lintCtx *linter.Context) { @@ -44,7 +46,7 @@ func NewGomodguard() *goanalysis.Linter { processorCfg.Allowed.Domains = linterCfg.Allowed.Domains for n := range linterCfg.Blocked.Modules { for k, v := range linterCfg.Blocked.Modules[n] { - m := gomodguard.BlockedModule{k: gomodguard.Recommendations{ + m := map[string]gomodguard.BlockedModule{k: { Recommendations: v.Recommendations, Reason: v.Reason, }} @@ -53,6 +55,17 @@ func NewGomodguard() *goanalysis.Linter { } } + for n := range linterCfg.Blocked.Versions { + for k, v := range linterCfg.Blocked.Versions[n] { + m := map[string]gomodguard.BlockedVersion{k: { + Version: v.Version, + Reason: v.Reason, + }} + processorCfg.Blocked.Versions = append(processorCfg.Blocked.Versions, m) + break + } + } + for _, file := range pass.Files { files = append(files, pass.Fset.PositionFor(file.Pos(), false).Filename) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nlreturn.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nlreturn.go new file mode 100644 index 000000000..3b661c64c --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nlreturn.go @@ -0,0 +1,19 @@ +package golinters + +import ( + "github.com/ssgreg/nlreturn/v2/pkg/nlreturn" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewNLReturn() *goanalysis.Linter { + return goanalysis.NewLinter( + "nlreturn", + "nlreturn checks for a new line before return and branch statements to increase code clarity", + []*analysis.Analyzer{ + nlreturn.NewAnalyzer(), + }, + nil, + ).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/noctx.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/noctx.go new file mode 100644 index 000000000..b5c4a4be2 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/noctx.go @@ -0,0 +1,21 @@ +package golinters + +import ( + "github.com/sonatard/noctx" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewNoctx() *goanalysis.Linter { + analyzers := []*analysis.Analyzer{ + noctx.Analyzer, + } + + return goanalysis.NewLinter( + "noctx", + "noctx finds sending http request without context.Context", + analyzers, + nil, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/sqlclosecheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/sqlclosecheck.go new file mode 100644 index 000000000..48ca246e7 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/sqlclosecheck.go @@ -0,0 +1,21 @@ +package golinters + +import ( + "github.com/ryanrolds/sqlclosecheck/pkg/analyzer" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewSQLCloseCheck() *goanalysis.Linter { + analyzers := []*analysis.Analyzer{ + analyzer.NewAnalyzer(), + } + + return goanalysis.NewLinter( + "sqlclosecheck", + "Checks that sql.Rows and sql.Stmt are closed.", + analyzers, + nil, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go b/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go index 1ec78de28..7ffaf9c2e 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go @@ -87,9 +87,11 @@ func enableLinterConfigs(lcs []*linter.Config, isEnabled func(lc *linter.Config) func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { var govetCfg *config.GovetSettings var testpackageCfg *config.TestpackageSettings + var exhaustiveCfg *config.ExhaustiveSettings if m.cfg != nil { govetCfg = &m.cfg.LintersSettings.Govet testpackageCfg = &m.cfg.LintersSettings.Testpackage + exhaustiveCfg = &m.cfg.LintersSettings.Exhaustive } const megacheckName = "megacheck" lcs := []*linter.Config{ @@ -102,6 +104,10 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithLoadForGoAnalysis(). WithPresets(linter.PresetPerformance, linter.PresetBugs). WithURL("https://github.com/timakin/bodyclose"), + linter.NewConfig(golinters.NewNoctx()). + WithLoadForGoAnalysis(). + WithPresets(linter.PresetPerformance, linter.PresetBugs). + WithURL("https://github.com/sonatard/noctx"), linter.NewConfig(golinters.NewErrcheck()). WithLoadForGoAnalysis(). WithPresets(linter.PresetBugs). @@ -189,10 +195,22 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetFormatting). WithAutoFix(). WithURL("https://golang.org/cmd/gofmt/"), + linter.NewConfig(golinters.NewGofumpt()). + WithPresets(linter.PresetFormatting). + WithAutoFix(). + WithURL("https://github.com/mvdan/gofumpt"), linter.NewConfig(golinters.NewGoimports()). WithPresets(linter.PresetFormatting). WithAutoFix(). WithURL("https://godoc.org/golang.org/x/tools/cmd/goimports"), + linter.NewConfig(golinters.NewGoHeader()). + WithPresets(linter.PresetStyle). + WithLoadForGoAnalysis(). + WithURL("https://github.com/denis-tingajkin/go-header"), + linter.NewConfig(golinters.NewGci()). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/daixiang0/gci"), linter.NewConfig(golinters.NewMaligned()). WithLoadForGoAnalysis(). WithPresets(linter.PresetPerformance). @@ -263,6 +281,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithURL("https://github.com/ryancurrah/gomodguard"), linter.NewConfig(golinters.NewGodot()). WithPresets(linter.PresetStyle). + WithAutoFix(). WithURL("https://github.com/tetafro/godot"), linter.NewConfig(golinters.NewTestpackage(testpackageCfg)). WithPresets(linter.PresetStyle). @@ -271,10 +290,25 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { linter.NewConfig(golinters.NewNestif()). WithPresets(linter.PresetComplexity). WithURL("https://github.com/nakabonne/nestif"), + linter.NewConfig(golinters.NewExportLoopRef()). + WithPresets(linter.PresetBugs). + WithURL("https://github.com/kyoh86/exportloopref"), + linter.NewConfig(golinters.NewExhaustive(exhaustiveCfg)). + WithPresets(linter.PresetBugs). + WithLoadForGoAnalysis(). + WithURL("https://github.com/nishanths/exhaustive"), + linter.NewConfig(golinters.NewSQLCloseCheck()). + WithPresets(linter.PresetBugs). + WithLoadForGoAnalysis(). + WithURL("https://github.com/ryanrolds/sqlclosecheck"), + linter.NewConfig(golinters.NewNLReturn()). + WithPresets(linter.PresetStyle). + WithLoadForGoAnalysis(). + WithURL("https://github.com/ssgreg/nlreturn"), // nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives linter.NewConfig(golinters.NewNoLintLint()). WithPresets(linter.PresetStyle). - WithURL("https://github.com/golangci-lint/pkg/golinters/nolintlint"), + WithURL("https://github.com/golangci/golangci-lint/blob/master/pkg/golinters/nolintlint/README.md"), } isLocalRun := os.Getenv("GOLANGCI_COM_RUN") == "" diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/validator.go b/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/validator.go index d7e3699c8..dead59657 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/validator.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/validator.go @@ -22,7 +22,7 @@ func (v Validator) validateLintersNames(cfg *config.Linters) error { allNames = append(allNames, cfg.Disable...) for _, name := range allNames { if v.m.GetLinterConfigs(name) == nil { - return fmt.Errorf("no such linter %q", name) + return fmt.Errorf("no such linter %v, run 'golangci-lint linters' to see the list of supported linters", name) } } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go b/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go index e2928a57a..3525396bc 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go @@ -199,7 +199,14 @@ func (cl *ContextLoader) loadPackages(ctx context.Context, loadMode packages.Loa cl.debugf("Built loader args are %s", args) pkgs, err := packages.Load(conf, args...) if err != nil { - return nil, errors.Wrap(err, "failed to load program with go/packages") + return nil, errors.Wrap(err, "failed to load with go/packages") + } + + // Currently, go/packages doesn't guarantee that error will be returned + // if context was canceled. See + // https://github.com/golang/tools/commit/c5cec6710e927457c3c29d6c156415e8539a5111#r39261855 + if ctx.Err() != nil { + return nil, errors.Wrap(ctx.Err(), "timed out to load packages") } if loadMode&packages.NeedSyntax == 0 { @@ -280,7 +287,7 @@ func (cl *ContextLoader) Load(ctx context.Context, linters []*linter.Config) (*l loadMode := cl.findLoadMode(linters) pkgs, err := cl.loadPackages(ctx, loadMode) if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to load packages") } deduplicatedPkgs := cl.filterDuplicatePackages(pkgs) diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go b/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go index 05dc51ba9..084912226 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go @@ -31,24 +31,6 @@ type Runner struct { func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env, es *lintersdb.EnabledSet, lineCache *fsutils.LineCache, dbManager *lintersdb.Manager, pkgs []*gopackages.Package) (*Runner, error) { - icfg := cfg.Issues - excludePatterns := icfg.ExcludePatterns - if icfg.UseDefaultExcludes { - excludePatterns = append(excludePatterns, config.GetExcludePatternsStrings(icfg.IncludeDefaultExcludes)...) - } - - var excludeTotalPattern string - if len(excludePatterns) != 0 { - excludeTotalPattern = fmt.Sprintf("(%s)", strings.Join(excludePatterns, "|")) - } - - var excludeProcessor processors.Processor - if cfg.Issues.ExcludeCaseSensitive { - excludeProcessor = processors.NewExcludeCaseSensitive(excludeTotalPattern) - } else { - excludeProcessor = processors.NewExclude(excludeTotalPattern) - } - skipFilesProcessor, err := processors.NewSkipFiles(cfg.Run.SkipFiles) if err != nil { return nil, err @@ -63,22 +45,6 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env, es *lint return nil, err } - var excludeRules []processors.ExcludeRule - for _, r := range icfg.ExcludeRules { - excludeRules = append(excludeRules, processors.ExcludeRule{ - Text: r.Text, - Source: r.Source, - Path: r.Path, - Linters: r.Linters, - }) - } - var excludeRulesProcessor processors.Processor - if cfg.Issues.ExcludeCaseSensitive { - excludeRulesProcessor = processors.NewExcludeRulesCaseSensitive(excludeRules, lineCache, log.Child("exclude_rules")) - } else { - excludeRulesProcessor = processors.NewExcludeRules(excludeRules, lineCache, log.Child("exclude_rules")) - } - enabledLinters, err := es.GetEnabledLintersMap() if err != nil { return nil, errors.Wrap(err, "failed to get enabled linters") @@ -101,17 +67,20 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env, es *lint // Must be before exclude because users see already marked output and configure excluding by it. processors.NewIdentifierMarker(), - excludeProcessor, - excludeRulesProcessor, + getExcludeProcessor(&cfg.Issues), + getExcludeRulesProcessor(&cfg.Issues, log, lineCache), processors.NewNolint(log.Child("nolint"), dbManager, enabledLinters), processors.NewUniqByLine(cfg), - processors.NewDiff(icfg.Diff, icfg.DiffFromRevision, icfg.DiffPatchFilePath), + processors.NewDiff(cfg.Issues.Diff, cfg.Issues.DiffFromRevision, cfg.Issues.DiffPatchFilePath), processors.NewMaxPerFileFromLinter(cfg), - processors.NewMaxSameIssues(icfg.MaxSameIssues, log.Child("max_same_issues"), cfg), - processors.NewMaxFromLinter(icfg.MaxIssuesPerLinter, log.Child("max_from_linter"), cfg), + processors.NewMaxSameIssues(cfg.Issues.MaxSameIssues, log.Child("max_same_issues"), cfg), + processors.NewMaxFromLinter(cfg.Issues.MaxIssuesPerLinter, log.Child("max_from_linter"), cfg), processors.NewSourceCode(lineCache, log.Child("source_code")), processors.NewPathShortener(), + getSeverityRulesProcessor(&cfg.Severity, log, lineCache), + processors.NewPathPrefixer(cfg.Output.PathPrefix), + processors.NewSortResults(cfg), }, Log: log, }, nil @@ -254,3 +223,89 @@ func (r *Runner) processIssues(issues []result.Issue, sw *timeutils.Stopwatch, s return issues } + +func getExcludeProcessor(cfg *config.Issues) processors.Processor { + excludePatterns := cfg.ExcludePatterns + if cfg.UseDefaultExcludes { + excludePatterns = append(excludePatterns, config.GetExcludePatternsStrings(cfg.IncludeDefaultExcludes)...) + } + + var excludeTotalPattern string + if len(excludePatterns) != 0 { + excludeTotalPattern = fmt.Sprintf("(%s)", strings.Join(excludePatterns, "|")) + } + + var excludeProcessor processors.Processor + if cfg.ExcludeCaseSensitive { + excludeProcessor = processors.NewExcludeCaseSensitive(excludeTotalPattern) + } else { + excludeProcessor = processors.NewExclude(excludeTotalPattern) + } + + return excludeProcessor +} + +func getExcludeRulesProcessor(cfg *config.Issues, log logutils.Log, lineCache *fsutils.LineCache) processors.Processor { + var excludeRules []processors.ExcludeRule + for _, r := range cfg.ExcludeRules { + excludeRules = append(excludeRules, processors.ExcludeRule{ + BaseRule: processors.BaseRule{ + Text: r.Text, + Source: r.Source, + Path: r.Path, + Linters: r.Linters, + }, + }) + } + + var excludeRulesProcessor processors.Processor + if cfg.ExcludeCaseSensitive { + excludeRulesProcessor = processors.NewExcludeRulesCaseSensitive( + excludeRules, + lineCache, + log.Child("exclude_rules"), + ) + } else { + excludeRulesProcessor = processors.NewExcludeRules( + excludeRules, + lineCache, + log.Child("exclude_rules"), + ) + } + + return excludeRulesProcessor +} + +func getSeverityRulesProcessor(cfg *config.Severity, log logutils.Log, lineCache *fsutils.LineCache) processors.Processor { + var severityRules []processors.SeverityRule + for _, r := range cfg.Rules { + severityRules = append(severityRules, processors.SeverityRule{ + Severity: r.Severity, + BaseRule: processors.BaseRule{ + Text: r.Text, + Source: r.Source, + Path: r.Path, + Linters: r.Linters, + }, + }) + } + + var severityRulesProcessor processors.Processor + if cfg.CaseSensitive { + severityRulesProcessor = processors.NewSeverityRulesCaseSensitive( + cfg.Default, + severityRules, + lineCache, + log.Child("severity_rules"), + ) + } else { + severityRulesProcessor = processors.NewSeverityRules( + cfg.Default, + severityRules, + lineCache, + log.Child("severity_rules"), + ) + } + + return severityRulesProcessor +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/checkstyle.go b/vendor/github.com/golangci/golangci-lint/pkg/printers/checkstyle.go index f36bc108a..c5b948a98 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/checkstyle.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/printers/checkstyle.go @@ -5,6 +5,8 @@ import ( "encoding/xml" "fmt" + "github.com/go-xmlfmt/xmlfmt" + "github.com/golangci/golangci-lint/pkg/logutils" "github.com/golangci/golangci-lint/pkg/result" ) @@ -28,7 +30,7 @@ type checkstyleError struct { Source string `xml:"source,attr"` } -const defaultSeverity = "error" +const defaultCheckstyleSeverity = "error" type Checkstyle struct{} @@ -54,12 +56,17 @@ func (Checkstyle) Print(ctx context.Context, issues []result.Issue) error { files[issue.FilePath()] = file } + severity := defaultCheckstyleSeverity + if issue.Severity != "" { + severity = issue.Severity + } + newError := &checkstyleError{ Column: issue.Column(), Line: issue.Line(), Message: issue.Text, Source: issue.FromLinter, - Severity: defaultSeverity, + Severity: severity, } file.Errors = append(file.Errors, newError) @@ -75,6 +82,6 @@ func (Checkstyle) Print(ctx context.Context, issues []result.Issue) error { return err } - fmt.Fprintf(logutils.StdOut, "%s%s\n", xml.Header, data) + fmt.Fprintf(logutils.StdOut, "%s%s\n", xml.Header, xmlfmt.FormatXML(string(data), "", " ")) return nil } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/codeclimate.go b/vendor/github.com/golangci/golangci-lint/pkg/printers/codeclimate.go index 5d45c4eb3..35a22ce99 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/codeclimate.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/printers/codeclimate.go @@ -2,7 +2,6 @@ package printers import ( "context" - "crypto/md5" //nolint:gosec "encoding/json" "fmt" @@ -14,6 +13,7 @@ import ( // It is just enough to support GitLab CI Code Quality - https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html type CodeClimateIssue struct { Description string `json:"description"` + Severity string `json:"severity,omitempty"` Fingerprint string `json:"fingerprint"` Location struct { Path string `json:"path"` @@ -31,28 +31,23 @@ func NewCodeClimate() *CodeClimate { } func (p CodeClimate) Print(ctx context.Context, issues []result.Issue) error { - allIssues := []CodeClimateIssue{} - for ind := range issues { - i := &issues[ind] - var issue CodeClimateIssue - issue.Description = i.FromLinter + ": " + i.Text - issue.Location.Path = i.Pos.Filename - issue.Location.Lines.Begin = i.Pos.Line - - // Need a checksum of the issue, so we use MD5 of the filename, text, and first line of source if there is any - var firstLine string - if len(i.SourceLines) > 0 { - firstLine = i.SourceLines[0] + codeClimateIssues := []CodeClimateIssue{} + for i := range issues { + issue := &issues[i] + codeClimateIssue := CodeClimateIssue{} + codeClimateIssue.Description = issue.Description() + codeClimateIssue.Location.Path = issue.Pos.Filename + codeClimateIssue.Location.Lines.Begin = issue.Pos.Line + codeClimateIssue.Fingerprint = issue.Fingerprint() + + if issue.Severity != "" { + codeClimateIssue.Severity = issue.Severity } - hash := md5.New() //nolint:gosec - _, _ = hash.Write([]byte(i.Pos.Filename + i.Text + firstLine)) - issue.Fingerprint = fmt.Sprintf("%X", hash.Sum(nil)) - - allIssues = append(allIssues, issue) + codeClimateIssues = append(codeClimateIssues, codeClimateIssue) } - outputJSON, err := json.Marshal(allIssues) + outputJSON, err := json.Marshal(codeClimateIssues) if err != nil { return err } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/github.go b/vendor/github.com/golangci/golangci-lint/pkg/printers/github.go index fa11a2839..b8d70140a 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/github.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/printers/github.go @@ -11,6 +11,8 @@ import ( type github struct { } +const defaultGithubSeverity = "error" + // Github output format outputs issues according to Github actions format: // https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message func NewGithub() Printer { @@ -19,7 +21,12 @@ func NewGithub() Printer { // print each line as: ::error file=app.js,line=10,col=15::Something went wrong func formatIssueAsGithub(issue *result.Issue) string { - ret := fmt.Sprintf("::error file=%s,line=%d", issue.FilePath(), issue.Line()) + severity := defaultGithubSeverity + if issue.Severity != "" { + severity = issue.Severity + } + + ret := fmt.Sprintf("::%s file=%s,line=%d", severity, issue.FilePath(), issue.Line()) if issue.Pos.Column != 0 { ret += fmt.Sprintf(",col=%d", issue.Pos.Column) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/issue.go b/vendor/github.com/golangci/golangci-lint/pkg/result/issue.go index 16d9a8a8c..eafdbc4a9 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/issue.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/issue.go @@ -1,6 +1,8 @@ package result import ( + "crypto/md5" //nolint:gosec + "fmt" "go/token" "golang.org/x/tools/go/packages" @@ -26,6 +28,8 @@ type Issue struct { FromLinter string Text string + Severity string + // Source lines of a code with the issue to show SourceLines []string @@ -76,3 +80,19 @@ func (i *Issue) GetLineRange() Range { return *i.LineRange } + +func (i *Issue) Description() string { + return fmt.Sprintf("%s: %s", i.FromLinter, i.Text) +} + +func (i *Issue) Fingerprint() string { + firstLine := "" + if len(i.SourceLines) > 0 { + firstLine = i.SourceLines[0] + } + + hash := md5.New() //nolint:gosec + _, _ = hash.Write([]byte(fmt.Sprintf("%s%s%s", i.Pos.Filename, i.Text, firstLine))) + + return fmt.Sprintf("%X", hash.Sum(nil)) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go index 249ba9d44..112217952 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go @@ -1,9 +1,9 @@ package processors import ( - "bufio" "fmt" - "os" + "go/parser" + "go/token" "path/filepath" "strings" @@ -113,37 +113,15 @@ func (p *AutogeneratedExclude) getOrCreateFileSummary(i *result.Issue) (*ageFile } func getDoc(filePath string) (string, error) { - file, err := os.Open(filePath) + fset := token.NewFileSet() + syntax, err := parser.ParseFile(fset, filePath, nil, parser.PackageClauseOnly|parser.ParseComments) if err != nil { - return "", errors.Wrap(err, "failed to open file") + return "", errors.Wrap(err, "failed to parse file") } - defer file.Close() - - scanner := bufio.NewScanner(file) - - // Issue 954: Some lines can be very long, e.g. auto-generated - // embedded resources. Reported on file of 86.2KB. - const ( - maxSize = 10 * 1024 * 1024 // 10MB should be enough - initialSize = 4096 // same as startBufSize in bufio - ) - scanner.Buffer(make([]byte, initialSize), maxSize) var docLines []string - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if strings.HasPrefix(line, "//") { - text := strings.TrimSpace(strings.TrimPrefix(line, "//")) - docLines = append(docLines, text) - } else if line == "" || strings.HasPrefix(line, "package") { - // go to next line - } else { - break - } - } - - if err := scanner.Err(); err != nil { - return "", errors.Wrap(err, "failed to scan file") + for _, c := range syntax.Comments { + docLines = append(docLines, strings.TrimSpace(c.Text())) } return strings.Join(docLines, "\n"), nil diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/base_rule.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/base_rule.go new file mode 100644 index 000000000..b6ce4f215 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/base_rule.go @@ -0,0 +1,69 @@ +package processors + +import ( + "regexp" + + "github.com/golangci/golangci-lint/pkg/fsutils" + "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/pkg/result" +) + +type BaseRule struct { + Text string + Source string + Path string + Linters []string +} + +type baseRule struct { + text *regexp.Regexp + source *regexp.Regexp + path *regexp.Regexp + linters []string +} + +func (r *baseRule) isEmpty() bool { + return r.text == nil && r.source == nil && r.path == nil && len(r.linters) == 0 +} + +func (r *baseRule) match(issue *result.Issue, lineCache *fsutils.LineCache, log logutils.Log) bool { + if r.isEmpty() { + return false + } + if r.text != nil && !r.text.MatchString(issue.Text) { + return false + } + if r.path != nil && !r.path.MatchString(issue.FilePath()) { + return false + } + if len(r.linters) != 0 && !r.matchLinter(issue) { + return false + } + + // the most heavyweight checking last + if r.source != nil && !r.matchSource(issue, lineCache, log) { + return false + } + + return true +} + +func (r *baseRule) matchLinter(issue *result.Issue) bool { + for _, linter := range r.linters { + if linter == issue.FromLinter { + return true + } + } + + return false +} + +func (r *baseRule) matchSource(issue *result.Issue, lineCache *fsutils.LineCache, log logutils.Log) bool { // nolint:interfacer + sourceLine, errSourceLine := lineCache.GetLine(issue.FilePath(), issue.Line()) + if errSourceLine != nil { + log.Warnf("Failed to get line %s:%d from line cache: %s", issue.FilePath(), issue.Line(), errSourceLine) + return false // can't properly match + } + + return r.source.MatchString(sourceLine) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go index b926af5b1..d4d6569f4 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go @@ -9,21 +9,11 @@ import ( ) type excludeRule struct { - text *regexp.Regexp - source *regexp.Regexp - path *regexp.Regexp - linters []string -} - -func (r *excludeRule) isEmpty() bool { - return r.text == nil && r.path == nil && len(r.linters) == 0 + baseRule } type ExcludeRule struct { - Text string - Source string - Path string - Linters []string + BaseRule } type ExcludeRules struct { @@ -45,9 +35,8 @@ func NewExcludeRules(rules []ExcludeRule, lineCache *fsutils.LineCache, log logu func createRules(rules []ExcludeRule, prefix string) []excludeRule { parsedRules := make([]excludeRule, 0, len(rules)) for _, rule := range rules { - parsedRule := excludeRule{ - linters: rule.Linters, - } + parsedRule := excludeRule{} + parsedRule.linters = rule.Linters if rule.Text != "" { parsedRule.text = regexp.MustCompile(prefix + rule.Text) } @@ -69,7 +58,7 @@ func (p ExcludeRules) Process(issues []result.Issue) ([]result.Issue, error) { return filterIssues(issues, func(i *result.Issue) bool { for _, rule := range p.rules { rule := rule - if p.match(i, &rule) { + if rule.match(i, p.lineCache, p.log) { return false } } @@ -77,48 +66,6 @@ func (p ExcludeRules) Process(issues []result.Issue) ([]result.Issue, error) { }), nil } -func (p ExcludeRules) matchLinter(i *result.Issue, r *excludeRule) bool { - for _, linter := range r.linters { - if linter == i.FromLinter { - return true - } - } - - return false -} - -func (p ExcludeRules) matchSource(i *result.Issue, r *excludeRule) bool { //nolint:interfacer - sourceLine, err := p.lineCache.GetLine(i.FilePath(), i.Line()) - if err != nil { - p.log.Warnf("Failed to get line %s:%d from line cache: %s", i.FilePath(), i.Line(), err) - return false // can't properly match - } - - return r.source.MatchString(sourceLine) -} - -func (p ExcludeRules) match(i *result.Issue, r *excludeRule) bool { - if r.isEmpty() { - return false - } - if r.text != nil && !r.text.MatchString(i.Text) { - return false - } - if r.path != nil && !r.path.MatchString(i.FilePath()) { - return false - } - if len(r.linters) != 0 && !p.matchLinter(i, r) { - return false - } - - // the most heavyweight checking last - if r.source != nil && !p.matchSource(i, r) { - return false - } - - return true -} - func (ExcludeRules) Name() string { return "exclude-rules" } func (ExcludeRules) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/filename_unadjuster.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/filename_unadjuster.go index 5e692ceba..96540245b 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/filename_unadjuster.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/filename_unadjuster.go @@ -16,6 +16,11 @@ import ( type posMapper func(pos token.Position) token.Position +type adjustMap struct { + sync.Mutex + m map[string]posMapper +} + // FilenameUnadjuster is needed because a lot of linters use fset.Position(f.Pos()) // to get filename. And they return adjusted filename (e.g. *.qtpl) for an issue. We need // restore real .go filename to properly output it, parse it, etc. @@ -27,7 +32,7 @@ type FilenameUnadjuster struct { var _ Processor = &FilenameUnadjuster{} -func processUnadjusterPkg(m map[string]posMapper, pkg *packages.Package, log logutils.Log) { +func processUnadjusterPkg(m *adjustMap, pkg *packages.Package, log logutils.Log) { fset := token.NewFileSet() // it's more memory efficient to not store all in one fset for _, filename := range pkg.CompiledGoFiles { @@ -36,7 +41,7 @@ func processUnadjusterPkg(m map[string]posMapper, pkg *packages.Package, log log } } -func processUnadjusterFile(filename string, m map[string]posMapper, log logutils.Log, fset *token.FileSet) { +func processUnadjusterFile(filename string, m *adjustMap, log logutils.Log, fset *token.FileSet) { syntax, err := parser.ParseFile(fset, filename, nil, parser.ParseComments) if err != nil { // Error will be reported by typecheck @@ -57,7 +62,9 @@ func processUnadjusterFile(filename string, m map[string]posMapper, log logutils return // file.go -> /caches/cgo-xxx } - m[adjustedFilename] = func(adjustedPos token.Position) token.Position { + m.Lock() + defer m.Unlock() + m.m[adjustedFilename] = func(adjustedPos token.Position) token.Position { tokenFile := fset.File(syntax.Pos()) if tokenFile == nil { log.Warnf("Failed to get token file for %s", adjustedFilename) @@ -68,22 +75,23 @@ func processUnadjusterFile(filename string, m map[string]posMapper, log logutils } func NewFilenameUnadjuster(pkgs []*packages.Package, log logutils.Log) *FilenameUnadjuster { - m := map[string]posMapper{} + m := adjustMap{m: map[string]posMapper{}} + startedAt := time.Now() var wg sync.WaitGroup wg.Add(len(pkgs)) for _, pkg := range pkgs { go func(pkg *packages.Package) { // It's important to call func here to run GC - processUnadjusterPkg(m, pkg, log) + processUnadjusterPkg(&m, pkg, log) wg.Done() }(pkg) } wg.Wait() - log.Infof("Pre-built %d adjustments in %s", len(m), time.Since(startedAt)) + log.Infof("Pre-built %d adjustments in %s", len(m.m), time.Since(startedAt)) return &FilenameUnadjuster{ - m: m, + m: m.m, log: log, loggedUnadjustments: map[string]bool{}, } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go new file mode 100644 index 000000000..5ce940b39 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go @@ -0,0 +1,37 @@ +package processors + +import ( + "path" + + "github.com/golangci/golangci-lint/pkg/result" +) + +// PathPrefixer adds a customizable prefix to every output path +type PathPrefixer struct { + prefix string +} + +var _ Processor = new(PathPrefixer) + +// NewPathPrefixer returns a new path prefixer for the provided string +func NewPathPrefixer(prefix string) *PathPrefixer { + return &PathPrefixer{prefix: prefix} +} + +// Name returns the name of this processor +func (*PathPrefixer) Name() string { + return "path_prefixer" +} + +// Process adds the prefix to each path +func (p *PathPrefixer) Process(issues []result.Issue) ([]result.Issue, error) { + if p.prefix != "" { + for i := range issues { + issues[i].Pos.Filename = path.Join(p.prefix, issues[i].Pos.Filename) + } + } + return issues, nil +} + +// Finish is implemented to satisfy the Processor interface +func (*PathPrefixer) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity_rules.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity_rules.go new file mode 100644 index 000000000..5f11b5410 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity_rules.go @@ -0,0 +1,103 @@ +package processors + +import ( + "regexp" + + "github.com/golangci/golangci-lint/pkg/fsutils" + "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/pkg/result" +) + +type severityRule struct { + baseRule + severity string +} + +type SeverityRule struct { + BaseRule + Severity string +} + +type SeverityRules struct { + defaultSeverity string + rules []severityRule + lineCache *fsutils.LineCache + log logutils.Log +} + +func NewSeverityRules(defaultSeverity string, rules []SeverityRule, lineCache *fsutils.LineCache, log logutils.Log) *SeverityRules { + r := &SeverityRules{ + lineCache: lineCache, + log: log, + defaultSeverity: defaultSeverity, + } + r.rules = createSeverityRules(rules, "(?i)") + + return r +} + +func createSeverityRules(rules []SeverityRule, prefix string) []severityRule { + parsedRules := make([]severityRule, 0, len(rules)) + for _, rule := range rules { + parsedRule := severityRule{} + parsedRule.linters = rule.Linters + parsedRule.severity = rule.Severity + if rule.Text != "" { + parsedRule.text = regexp.MustCompile(prefix + rule.Text) + } + if rule.Source != "" { + parsedRule.source = regexp.MustCompile(prefix + rule.Source) + } + if rule.Path != "" { + parsedRule.path = regexp.MustCompile(rule.Path) + } + parsedRules = append(parsedRules, parsedRule) + } + return parsedRules +} + +func (p SeverityRules) Process(issues []result.Issue) ([]result.Issue, error) { + if len(p.rules) == 0 { + return issues, nil + } + return transformIssues(issues, func(i *result.Issue) *result.Issue { + for _, rule := range p.rules { + rule := rule + + ruleSeverity := p.defaultSeverity + if rule.severity != "" { + ruleSeverity = rule.severity + } + + if rule.match(i, p.lineCache, p.log) { + i.Severity = ruleSeverity + return i + } + } + i.Severity = p.defaultSeverity + return i + }), nil +} + +func (SeverityRules) Name() string { return "severity-rules" } +func (SeverityRules) Finish() {} + +var _ Processor = SeverityRules{} + +type SeverityRulesCaseSensitive struct { + *SeverityRules +} + +func NewSeverityRulesCaseSensitive(defaultSeverity string, rules []SeverityRule, + lineCache *fsutils.LineCache, log logutils.Log) *SeverityRulesCaseSensitive { + r := &SeverityRules{ + lineCache: lineCache, + log: log, + defaultSeverity: defaultSeverity, + } + r.rules = createSeverityRules(rules, "") + + return &SeverityRulesCaseSensitive{r} +} + +func (SeverityRulesCaseSensitive) Name() string { return "severity-rules-case-sensitive" } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/sort_results.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/sort_results.go new file mode 100644 index 000000000..e726c3adf --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/sort_results.go @@ -0,0 +1,173 @@ +package processors + +import ( + "sort" + "strings" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/result" +) + +// Base propose of this functionality to sort results (issues) +// produced by various linters by analyzing code. We achieving this +// by sorting results.Issues using processor step, and chain based +// rules that can compare different properties of the Issues struct. + +var _ Processor = (*SortResults)(nil) + +type SortResults struct { + cmp comparator + cfg *config.Config +} + +func NewSortResults(cfg *config.Config) *SortResults { + // For sorting we are comparing (in next order): file names, line numbers, + // position, and finally - giving up. + return &SortResults{ + cmp: ByName{ + next: ByLine{ + next: ByColumn{}, + }, + }, + cfg: cfg, + } +} + +// Process is performing sorting of the result issues. +func (sr SortResults) Process(issues []result.Issue) ([]result.Issue, error) { + if !sr.cfg.Output.SortResults { + return issues, nil + } + + sort.Slice(issues, func(i, j int) bool { + return sr.cmp.Compare(&issues[i], &issues[j]) == Less + }) + + return issues, nil +} + +func (sr SortResults) Name() string { return "sort_results" } +func (sr SortResults) Finish() {} + +type compareResult int + +const ( + Less compareResult = iota - 1 + Equal + Greater + None +) + +func (c compareResult) isNeutral() bool { + // return true if compare result is incomparable or equal. + return c == None || c == Equal +} + +//nolint:exhaustive +func (c compareResult) String() string { + switch c { + case Less: + return "Less" + case Equal: + return "Equal" + case Greater: + return "Greater" + } + + return "None" +} + +// comparator describe how to implement compare for two "issues" lexicographically +type comparator interface { + Compare(a, b *result.Issue) compareResult + Next() comparator +} + +var ( + _ comparator = (*ByName)(nil) + _ comparator = (*ByLine)(nil) + _ comparator = (*ByColumn)(nil) +) + +type ByName struct{ next comparator } + +//nolint:golint +func (cmp ByName) Next() comparator { return cmp.next } + +//nolint:golint +func (cmp ByName) Compare(a, b *result.Issue) compareResult { + var res compareResult + + if res = compareResult(strings.Compare(a.FilePath(), b.FilePath())); !res.isNeutral() { + return res + } + + if next := cmp.Next(); next != nil { + return next.Compare(a, b) + } + + return res +} + +type ByLine struct{ next comparator } + +//nolint:golint +func (cmp ByLine) Next() comparator { return cmp.next } + +//nolint:golint +func (cmp ByLine) Compare(a, b *result.Issue) compareResult { + var res compareResult + + if res = numericCompare(a.Line(), b.Line()); !res.isNeutral() { + return res + } + + if next := cmp.Next(); next != nil { + return next.Compare(a, b) + } + + return res +} + +type ByColumn struct{ next comparator } + +//nolint:golint +func (cmp ByColumn) Next() comparator { return cmp.next } + +//nolint:golint +func (cmp ByColumn) Compare(a, b *result.Issue) compareResult { + var res compareResult + + if res = numericCompare(a.Column(), b.Column()); !res.isNeutral() { + return res + } + + if next := cmp.Next(); next != nil { + return next.Compare(a, b) + } + + return res +} + +func numericCompare(a, b int) compareResult { + var ( + isValuesInvalid = a < 0 || b < 0 + isZeroValuesBoth = a == 0 && b == 0 + isEqual = a == b + isZeroValueInA = b > 0 && a == 0 + isZeroValueInB = a > 0 && b == 0 + ) + + switch { + case isZeroValuesBoth || isEqual: + return Equal + case isValuesInvalid || isZeroValueInA || isZeroValueInB: + return None + case a > b: + return Greater + case a < b: + return Less + } + + return Equal +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/sliceutil/sliceutil.go b/vendor/github.com/golangci/golangci-lint/pkg/sliceutil/sliceutil.go new file mode 100644 index 000000000..cb89e34e0 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/sliceutil/sliceutil.go @@ -0,0 +1,17 @@ +package sliceutil + +// IndexOf get the index of the given value in the given string slice, +// or -1 if not found. +func IndexOf(slice []string, value string) int { + for i, v := range slice { + if v == value { + return i + } + } + return -1 +} + +// Contains check if a string slice contains a value. +func Contains(slice []string, value string) bool { + return IndexOf(slice, value) != -1 +} diff --git a/vendor/github.com/golangci/revgrep/revgrep.go b/vendor/github.com/golangci/revgrep/revgrep.go index 1a56dcf4e..3650d646a 100644 --- a/vendor/github.com/golangci/revgrep/revgrep.go +++ b/vendor/github.com/golangci/revgrep/revgrep.go @@ -80,6 +80,7 @@ func (c *Checker) preparePatch() error { return nil } +// InputIssue represents issue found by some linter type InputIssue interface { FilePath() string Line() int @@ -98,12 +99,14 @@ func (i simpleInputIssue) Line() int { return i.lineNumber } +// Prepare extracts a patch and changed lines func (c *Checker) Prepare() error { returnErr := c.preparePatch() c.changes = c.linesChanged() return returnErr } +// IsNewIssue checks whether issue found by linter is new: it was found in changed lines func (c Checker) IsNewIssue(i InputIssue) (hunkPos int, isNew bool) { fchanges, ok := c.changes[i.FilePath()] if !ok { // file wasn't changed @@ -116,7 +119,7 @@ func (c Checker) IsNewIssue(i InputIssue) (hunkPos int, isNew bool) { ) // found file, see if lines matched for _, pos := range fchanges { - if pos.lineNo == int(i.Line()) { + if pos.lineNo == i.Line() { fpos = pos changed = true break @@ -338,7 +341,7 @@ func GitPatch(revisionFrom, revisionTo string) (io.Reader, []string, error) { // make a patch for untracked files var newFiles []string - ls, err := exec.Command("git", "ls-files", "-o").CombinedOutput() + ls, err := exec.Command("git", "ls-files", "--others", "--exclude-standard").CombinedOutput() if err != nil { return nil, nil, fmt.Errorf("error executing git ls-files: %s", err) } |
