build(deps): bump github.com/golangci/golangci-lint in /tests/tools

Bumps [github.com/golangci/golangci-lint](https://github.com/golangci/golangci-lint) from 1.47.3 to 1.48.0.
- [Release notes](https://github.com/golangci/golangci-lint/releases)
- [Changelog](https://github.com/golangci/golangci-lint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/golangci/golangci-lint/compare/v1.47.3...v1.48.0)

---
updated-dependencies:
- dependency-name: github.com/golangci/golangci-lint
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot] 2022-08-05 08:27:42 +00:00 committed by GitHub
parent 053d7808c1
commit e8c7e3fe3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 771 additions and 213 deletions

View File

@ -4,6 +4,6 @@ go 1.14
require (
github.com/cpuguy83/go-md2man/v2 v2.0.2
github.com/golangci/golangci-lint v1.47.3
github.com/golangci/golangci-lint v1.48.0
github.com/onsi/ginkgo v1.16.5
)

View File

@ -176,8 +176,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHH
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/daixiang0/gci v0.5.0 h1:3+Z8nb/4dhJQYjpEbG4wt5na+KFJJTZ++PVEq/MVKX4=
github.com/daixiang0/gci v0.5.0/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c=
github.com/daixiang0/gci v0.6.2 h1:TXCP5RqjE/UupXO+p33MEhqdv7QxjKGw5MVkt9ATiMs=
github.com/daixiang0/gci v0.6.2/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c=
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -315,16 +315,16 @@ github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe h1:6RGUuS7EGotKx6
github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ=
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a h1:iR3fYXUjHCR97qWS8ch1y9zPNsgXThGwjKPrYfqMPks=
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
github.com/golangci/golangci-lint v1.47.3 h1:ri7A2DgtFpxgqcMSsU3qIT0IBm/SCdYgXlvmJx4szUU=
github.com/golangci/golangci-lint v1.47.3/go.mod h1:IvT5xyPX1W8JUJJrV60gcMzgQe1ttW/38yAzn6LuHOk=
github.com/golangci/golangci-lint v1.48.0 h1:hRiBNk9iRqdAKMa06ntfEiLyza1/3IE9rHLNJaek4a8=
github.com/golangci/golangci-lint v1.48.0/go.mod h1:5N+oxduCho+7yuccW69upg/O7cxjfR/d+IQeiNxGmKM=
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA=
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA=
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
github.com/golangci/misspell v0.3.5 h1:pLzmVdl3VxTOncgzHcvLOKirdvcx/TydsClUQXTehjo=
github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2 h1:SgM7GDZTxtTTQPU84heOxy34iG5Du7F2jcoZnvp+fXI=
github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY=
github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 h1:DIPQnGy2Gv2FSA4B/hh8Q7xx3B7AIDk3DAMeHclH1vQ=
github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6/go.mod h1:0AKcRCkMoKvUvlf89F6O7H2LYdhr1zBh736mBItOdRs=
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys=
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@ -500,8 +500,8 @@ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/errcheck v1.6.1 h1:cErYo+J4SmEjdXZrVXGwLJCE2sB06s23LpkcyWNrT+s=
github.com/kisielk/errcheck v1.6.1/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw=
github.com/kisielk/errcheck v1.6.2 h1:uGQ9xI8/pgc9iOoCe7kWQgRE6SBTrCGmTSf0LrEtY7c=
github.com/kisielk/errcheck v1.6.2/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
@ -747,6 +747,8 @@ github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43
github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8=
github.com/sanposhiho/wastedassign/v2 v2.0.6 h1:+6/hQIHKNJAUixEj6EmOngGIisyeI+T3335lYTyxRoA=
github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI=
github.com/sashamelentyev/usestdlibvars v1.8.0 h1:QnWP9IOEuRyYKH+IG0LlQIjuJlc0rfdo4K3/Zh3WRMw=
github.com/sashamelentyev/usestdlibvars v1.8.0/go.mod h1:BFt7b5mSVHaaa26ZupiNRV2ODViQBxZZVhtAxAJRrjs=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/securego/gosec/v2 v2.12.0 h1:CQWdW7ATFpvLSohMVsajscfyHJ5rsGmEXmsNcsDNmAg=
github.com/securego/gosec/v2 v2.12.0/go.mod h1:iTpT+eKTw59bSgklBHlSnH5O2tNygHMDxfvMubA4i7I=

View File

@ -2,17 +2,28 @@ package config
import (
"io/ioutil"
"sort"
"strings"
"gopkg.in/yaml.v3"
"github.com/daixiang0/gci/pkg/section"
)
var defaultOrder = map[string]int{
section.StandardType: 0,
section.DefaultType: 1,
section.CustomType: 2,
section.BlankType: 3,
section.DotType: 4,
}
type BoolConfig struct {
NoInlineComments bool `yaml:"no-inlineComments"`
NoPrefixComments bool `yaml:"no-prefixComments"`
Debug bool `yaml:"-"`
SkipGenerated bool `yaml:"skipGenerated"`
CustomOrder bool `yaml:"customOrder"`
}
type Config struct {
@ -38,6 +49,18 @@ func (g YamlConfig) Parse() (*Config, error) {
sections = section.DefaultSections()
}
// if default order sorted sections
if !g.Cfg.CustomOrder {
sort.Slice(sections, func(i, j int) bool {
sectionI, sectionJ := sections[i].Type(), sections[j].Type()
if strings.Compare(sectionI, sectionJ) == 0 {
return strings.Compare(sections[i].String(), sections[j].String()) < 0
}
return defaultOrder[sectionI] < defaultOrder[sectionJ]
})
}
sectionSeparators, err := section.Parse(g.SectionSeparatorStrings)
if err != nil {
return nil, err

View File

@ -5,8 +5,6 @@ import (
"errors"
"fmt"
"os"
"sort"
"strings"
"sync"
"github.com/hexops/gotextdiff"
@ -143,67 +141,21 @@ func LoadFormatGoFile(file io.FileObj, cfg config.Config) (src, dist []byte, err
head := src[:headEnd]
tail := src[tailStart:]
// sort for custom sections
customKeys := make([]string, 0, len(result))
for k := range result {
if strings.HasPrefix(k, "prefix(") {
customKeys = append(customKeys, k)
}
}
firstWithIndex := true
var body []byte
// order: standard > default > custom
if len(result["standard"]) > 0 {
for _, d := range result["standard"] {
AddIndent(&body, &firstWithIndex)
body = append(body, src[d.Start:d.End]...)
}
body = append(body, utils.Linebreak)
}
if len(result["default"]) > 0 {
for _, d := range result["default"] {
AddIndent(&body, &firstWithIndex)
body = append(body, src[d.Start:d.End]...)
}
body = append(body, utils.Linebreak)
}
if len(customKeys) > 0 {
sort.Sort(sort.StringSlice(customKeys))
for i, k := range customKeys {
for _, d := range result[k] {
// order by section list
for _, s := range cfg.Sections {
if len(result[s.String()]) > 0 {
if body != nil && len(body) > 0 {
body = append(body, utils.Linebreak)
}
for _, d := range result[s.String()] {
AddIndent(&body, &firstWithIndex)
body = append(body, src[d.Start:d.End]...)
}
if i+1 < len(customKeys) {
body = append(body, utils.Linebreak)
}
}
body = append(body, utils.Linebreak)
}
if len(result["blank"]) > 0 {
for _, d := range result["blank"] {
AddIndent(&body, &firstWithIndex)
body = append(body, src[d.Start:d.End]...)
}
body = append(body, utils.Linebreak)
}
if len(result["dot"]) > 0 {
for _, d := range result["dot"] {
AddIndent(&body, &firstWithIndex)
body = append(body, src[d.Start:d.End]...)
}
body = append(body, utils.Linebreak)
}
// remove breakline in the end

View File

@ -7,6 +7,8 @@ import (
type Blank struct{}
const BlankType = "blank"
func (b Blank) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecificity {
if spec.Name == "_" {
return specificity.NameMatch{}
@ -15,5 +17,9 @@ func (b Blank) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecifi
}
func (b Blank) String() string {
return "blank"
return BlankType
}
func (b Blank) Type() string {
return BlankType
}

View File

@ -18,3 +18,7 @@ func (c CommentLine) MatchSpecificity(spec *parse.GciImports) specificity.MatchS
func (c CommentLine) String() string {
return fmt.Sprintf("commentline(%s)", c.Comment)
}
func (c CommentLine) Type() string {
return "commentline"
}

View File

@ -5,7 +5,7 @@ import (
"github.com/daixiang0/gci/pkg/specificity"
)
const defaultName = "default"
const DefaultType = "default"
type Default struct{}
@ -14,5 +14,9 @@ func (d Default) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpeci
}
func (d Default) String() string {
return defaultName
return DefaultType
}
func (d Default) Type() string {
return DefaultType
}

View File

@ -7,6 +7,8 @@ import (
type Dot struct{}
const DotType = "dot"
func (d Dot) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecificity {
if spec.Name == "." {
return specificity.NameMatch{}
@ -15,5 +17,9 @@ func (d Dot) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecifici
}
func (d Dot) String() string {
return "dot"
return DotType
}
func (d Dot) Type() string {
return DotType
}

View File

@ -16,3 +16,7 @@ func (n NewLine) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpeci
func (n NewLine) String() string {
return newLineName
}
func (n NewLine) Type() string {
return newLineName
}

View File

@ -12,6 +12,8 @@ type Custom struct {
Prefix string
}
const CustomType = "custom"
func (c Custom) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecificity {
if strings.HasPrefix(spec.Path, c.Prefix) {
return specificity.Match{Length: len(c.Prefix)}
@ -22,3 +24,7 @@ func (c Custom) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecif
func (c Custom) String() string {
return fmt.Sprintf("prefix(%s)", c.Prefix)
}
func (c Custom) Type() string {
return CustomType
}

View File

@ -12,6 +12,9 @@ type Section interface {
// String Implements the stringer interface
String() string
// return section type
Type() string
}
type SectionList []Section

View File

@ -5,7 +5,7 @@ import (
"github.com/daixiang0/gci/pkg/specificity"
)
const StandardName = "standard"
const StandardType = "standard"
type Standard struct{}
@ -17,7 +17,11 @@ func (s Standard) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpec
}
func (s Standard) String() string {
return StandardName
return StandardType
}
func (s Standard) Type() string {
return StandardType
}
func isStandard(pkg string) bool {

View File

@ -77,7 +77,6 @@ var defaultLintersSettings = LintersSettings{
},
NoLintLint: NoLintLintSettings{
RequireExplanation: false,
AllowLeadingSpace: true,
RequireSpecific: false,
AllowUnused: false,
},
@ -179,6 +178,7 @@ type LintersSettings struct {
Thelper ThelperSettings
Unparam UnparamSettings
Unused StaticCheckSettings
UseStdlibVars UseStdlibVarsSettings
Varcheck VarCheckSettings
Varnamelen VarnamelenSettings
Whitespace WhitespaceSettings
@ -288,6 +288,7 @@ type GciSettings struct {
LocalPrefixes string `mapstructure:"local-prefixes"` // Deprecated
Sections []string `mapstructure:"sections"`
SkipGenerated bool `mapstructure:"skip-generated"`
CustomOrder bool `mapstructure:"custom-order"`
}
type GocognitSettings struct {
@ -488,7 +489,6 @@ type NlreturnSettings struct {
type NoLintLintSettings struct {
RequireExplanation bool `mapstructure:"require-explanation"`
AllowLeadingSpace bool `mapstructure:"allow-leading-space"`
RequireSpecific bool `mapstructure:"require-specific"`
AllowNoExplanation []string `mapstructure:"allow-no-explanation"`
AllowUnused bool `mapstructure:"allow-unused"`
@ -588,6 +588,16 @@ type TenvSettings struct {
All bool `mapstructure:"all"`
}
type UseStdlibVarsSettings struct {
HTTPMethod bool `mapstructure:"http-method"`
HTTPStatusCode bool `mapstructure:"http-status-code"`
TimeWeekday bool `mapstructure:"time-weekday"`
TimeMonth bool `mapstructure:"time-month"`
TimeLayout bool `mapstructure:"time-layout"`
CryptoHash bool `mapstructure:"crypto-hash"`
DefaultRPCPathFlag bool `mapstructure:"default-rpc-path"`
}
type UnparamSettings struct {
CheckExported bool `mapstructure:"check-exported"`
Algo string

View File

@ -37,6 +37,7 @@ func NewGci(settings *config.GciSettings) *goanalysis.Linter {
rawCfg := gcicfg.YamlConfig{
Cfg: gcicfg.BoolConfig{
SkipGenerated: settings.SkipGenerated,
CustomOrder: settings.CustomOrder,
},
SectionStrings: settings.Sections,
}

View File

@ -121,7 +121,15 @@ func (lp *loadingPackage) loadFromSource(loadMode LoadMode) error {
pkg.IllTyped = true
pkg.TypesInfo = newTypesInfo()
pkg.TypesInfo = &types.Info{
Types: make(map[ast.Expr]types.TypeAndValue),
Instances: make(map[*ast.Ident]types.Instance),
Defs: make(map[*ast.Ident]types.Object),
Uses: make(map[*ast.Ident]types.Object),
Implicits: make(map[ast.Node]types.Object),
Scopes: make(map[ast.Node]*types.Scope),
Selections: make(map[*ast.SelectorExpr]*types.Selection),
}
importer := func(path string) (*types.Package, error) {
if path == unsafePkgName {

View File

@ -1,21 +0,0 @@
//go:build go1.18
// +build go1.18
package goanalysis
import (
"go/ast"
"go/types"
)
func newTypesInfo() *types.Info {
return &types.Info{
Types: make(map[ast.Expr]types.TypeAndValue),
Instances: make(map[*ast.Ident]types.Instance),
Defs: make(map[*ast.Ident]types.Object),
Uses: make(map[*ast.Ident]types.Object),
Implicits: make(map[ast.Node]types.Object),
Scopes: make(map[ast.Node]*types.Scope),
Selections: make(map[*ast.SelectorExpr]*types.Selection),
}
}

View File

@ -1,20 +0,0 @@
//go:build go1.17 && !go1.18
// +build go1.17,!go1.18
package goanalysis
import (
"go/ast"
"go/types"
)
func newTypesInfo() *types.Info {
return &types.Info{
Types: make(map[ast.Expr]types.TypeAndValue),
Defs: make(map[*ast.Ident]types.Object),
Uses: make(map[*ast.Ident]types.Object),
Implicits: make(map[ast.Node]types.Object),
Scopes: make(map[ast.Node]*types.Scope),
Selections: make(map[*ast.SelectorExpr]*types.Selection),
}
}

View File

@ -30,7 +30,7 @@ func NewGodot(settings *config.GodotSettings) *goanalysis.Linter {
// Convert deprecated setting
// todo(butuzov): remove on v2 release
if settings.CheckAll { // nolint:staticcheck // Keep for retro-compatibility.
if settings.CheckAll { //nolint:staticcheck // Keep for retro-compatibility.
dotSettings.Scope = godot.AllScope
}
}

View File

@ -4,7 +4,7 @@ import (
"fmt"
"strconv"
"github.com/julz/importas" // nolint: misspell
"github.com/julz/importas" //nolint:misspell
"golang.org/x/tools/go/analysis"
"github.com/golangci/golangci-lint/pkg/config"
@ -25,7 +25,7 @@ func NewImportAs(settings *config.ImportAsSettings) *goanalysis.Linter {
return
}
if len(settings.Alias) == 0 {
lintCtx.Log.Infof("importas settings found, but no aliases listed. List aliases under alias: key.") // nolint: misspell
lintCtx.Log.Infof("importas settings found, but no aliases listed. List aliases under alias: key.") //nolint:misspell
}
if err := analyzer.Flags.Set("no-unaliased", strconv.FormatBool(settings.NoUnaliased)); err != nil {

View File

@ -57,9 +57,6 @@ func runNoLintLint(pass *analysis.Pass, settings *config.NoLintLintSettings) ([]
if settings.RequireExplanation {
needs |= nolintlint.NeedsExplanation
}
if !settings.AllowLeadingSpace {
needs |= nolintlint.NeedsMachineOnly
}
if settings.RequireSpecific {
needs |= nolintlint.NeedsSpecific
}

View File

@ -1,6 +1,6 @@
# nolintlint
nolintlint is a Go static analysis tool to find ill-formed or insufficiently explained `// nolint` directives for golangci
nolintlint is a Go static analysis tool to find ill-formed or insufficiently explained `//nolint` directives for golangci
(or any other linter, using th )
## Purpose
@ -8,10 +8,10 @@ nolintlint is a Go static analysis tool to find ill-formed or insufficiently exp
To ensure that lint exceptions have explanations. Consider the case below:
```Go
import "crypto/md5" //nolint
import "crypto/md5" //nolint:all
func hash(data []byte) []byte {
return md5.New().Sum(data) //nolint
return md5.New().Sum(data) //nolint:all
}
```
@ -27,5 +27,5 @@ func hash(data []byte) []byte {
```
`nolintlint` can also identify cases where you may have written `// nolint`. Finally `nolintlint`, can also enforce that you
use the machine-readable nolint directive format `//nolint` and that you mention what linter is being suppressed, as shown above when we write `//nolint:gosec`.
use the machine-readable nolint directive format `//nolint:all` and that you mention what linter is being suppressed, as shown above when we write `//nolint:gosec`.

View File

@ -152,7 +152,7 @@ func NewLinter(needs Needs, excludes []string) (*Linter, error) {
}
return &Linter{
needs: needs,
needs: needs | NeedsMachineOnly,
excludeByLinter: excludeByName,
}, nil
}
@ -184,12 +184,14 @@ func (l Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) {
leadingSpace = leadingSpaceMatches[1]
}
directiveWithOptionalLeadingSpace := comment.Text
directiveWithOptionalLeadingSpace := "//"
if len(leadingSpace) > 0 {
split := strings.Split(strings.SplitN(comment.Text, ":", 2)[0], "//")
directiveWithOptionalLeadingSpace = "// " + strings.TrimSpace(split[1])
directiveWithOptionalLeadingSpace += " "
}
split := strings.Split(strings.SplitN(comment.Text, ":", 2)[0], "//")
directiveWithOptionalLeadingSpace += strings.TrimSpace(split[1])
pos := fset.Position(comment.Pos())
end := fset.Position(comment.End())
@ -227,8 +229,9 @@ func (l Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) {
}
lintersText, explanation := fullMatches[1], fullMatches[2]
var linters []string
if len(lintersText) > 0 {
if len(lintersText) > 0 && !strings.HasPrefix(lintersText, "all") {
lls := strings.Split(lintersText, ",")
linters = make([]string, 0, len(lls))
rangeStart := (pos.Column - 1) + len("//") + len(leadingSpace) + len("nolint:")

View File

@ -98,7 +98,8 @@ func staticCheckConfig(settings *config.StaticCheckSettings) *scconfig.Config {
}
// https://github.com/dominikh/go-tools/blob/9bf17c0388a65710524ba04c2d821469e639fdc2/lintcmd/lint.go#L437-L477
// nolint // Keep the original source code.
//
//nolint:gocritic // Keep the original source code.
func filterAnalyzerNames(analyzers []string, checks []string) map[string]bool {
allowedChecks := map[string]bool{}

View File

@ -0,0 +1,33 @@
package golinters
import (
"github.com/sashamelentyev/usestdlibvars/pkg/analyzer"
"golang.org/x/tools/go/analysis"
"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
)
func NewUseStdlibVars(cfg *config.UseStdlibVarsSettings) *goanalysis.Linter {
a := analyzer.New()
cfgMap := make(map[string]map[string]interface{})
if cfg != nil {
cfgMap[a.Name] = map[string]interface{}{
analyzer.HTTPMethodFlag: cfg.HTTPMethod,
analyzer.HTTPStatusCodeFlag: cfg.HTTPStatusCode,
analyzer.TimeWeekdayFlag: cfg.TimeWeekday,
analyzer.TimeMonthFlag: cfg.TimeMonth,
analyzer.TimeLayoutFlag: cfg.TimeLayout,
analyzer.CryptoHashFlag: cfg.CryptoHash,
analyzer.DefaultRPCPathFlag: cfg.DefaultRPCPathFlag,
}
}
return goanalysis.NewLinter(
a.Name,
a.Doc,
[]*analysis.Analyzer{a},
cfgMap,
).WithLoadMode(goanalysis.LoadModeSyntax)
}

View File

@ -21,8 +21,8 @@ type Noop struct {
}
func (n Noop) Run(_ context.Context, lintCtx *Context) ([]result.Issue, error) {
lintCtx.Log.Warnf("%s is disabled because of go1.18."+
" You can track the evolution of the go1.18 support by following the https://github.com/golangci/golangci-lint/issues/2649.", n.name)
lintCtx.Log.Warnf("%s is disabled because of generics."+
" You can track the evolution of the generics support by following the https://github.com/golangci/golangci-lint/issues/2649.", n.name)
return nil, nil
}

View File

@ -164,6 +164,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
thelperCfg *config.ThelperSettings
unparamCfg *config.UnparamSettings
unusedCfg *config.StaticCheckSettings
usestdlibvars *config.UseStdlibVarsSettings
varcheckCfg *config.VarCheckSettings
varnamelenCfg *config.VarnamelenSettings
whitespaceCfg *config.WhitespaceSettings
@ -299,7 +300,8 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithSince("v1.43.0").
WithPresets(linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/sylvia7788/contextcheck"),
WithURL("https://github.com/sylvia7788/contextcheck").
WithNoopFallback(m.cfg),
linter.NewConfig(golinters.NewCyclop(cyclopCfg)).
WithSince("v1.37.0").
@ -541,7 +543,8 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
linter.NewConfig(golinters.NewIfshort(ifshortCfg)).
WithSince("v1.36.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/esimonov/ifshort"),
WithURL("https://github.com/esimonov/ifshort").
Deprecated("The repository of the linter has been deprecated by the owner.", "v1.48.0", ""),
linter.NewConfig(golinters.NewImportAs(importAsCfg)).
WithSince("v1.38.0").
@ -766,6 +769,11 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithChangeTypes().
WithURL("https://github.com/dominikh/go-tools/tree/master/unused"),
linter.NewConfig(golinters.NewUseStdlibVars(usestdlibvars)).
WithSince("v1.48.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/sashamelentyev/usestdlibvars"),
linter.NewConfig(golinters.NewVarcheck(varcheckCfg)).
WithSince("v1.0.0").
WithLoadForGoAnalysis().

View File

@ -58,7 +58,7 @@ func (r *baseRule) matchLinter(issue *result.Issue) bool {
return false
}
func (r *baseRule) matchSource(issue *result.Issue, lineCache *fsutils.LineCache, log logutils.Log) bool { // nolint:interfacer
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)

View File

@ -252,7 +252,7 @@ func (p *Nolint) extractInlineRangeFromComment(text string, g ast.Node, fset *to
}
}
if !strings.HasPrefix(text, "nolint:") {
if strings.HasPrefix(text, "nolint:all") || !strings.HasPrefix(text, "nolint:") {
return buildRange(nil) // ignore all linters
}
@ -260,8 +260,12 @@ func (p *Nolint) extractInlineRangeFromComment(text string, g ast.Node, fset *to
var linters []string
text = strings.Split(text, "//")[0] // allow another comment after this comment
linterItems := strings.Split(strings.TrimPrefix(text, "nolint:"), ",")
for _, linter := range linterItems {
linterName := strings.ToLower(strings.TrimSpace(linter))
for _, item := range linterItems {
linterName := strings.ToLower(strings.TrimSpace(item))
if linterName == "all" {
p.unknownLintersSet = map[string]bool{}
return buildRange(nil)
}
lcs := p.dbManager.GetLinterConfigs(linterName)
if lcs == nil {

View File

@ -0,0 +1,73 @@
run:
timeout: 2m
linters-settings:
govet:
check-shadowing: true
enable-all: true
disable:
- fieldalignment
gocyclo:
min-complexity: 30 # 30 by default (but we recommend 10-20)
goconst:
min-len: 3
min-occurrences: 3
misspell:
locale: US
funlen:
lines: -1
statements: 80 # default 40
gocognit:
min-complexity: 65 # default 30
gofumpt:
extra-rules: true
godox:
keywords:
- FIXME
linters:
enable-all: true
disable:
- maligned # Deprecated
- scopelint # Deprecated
- golint # Deprecated
- interfacer # Deprecated
- exhaustivestruct # Deprecated
- cyclop # duplicate of gocyclo
- dupl
- lll
- nestif
- gomnd
- goerr113
# - wrapcheck
- nlreturn
- wsl
- exhaustive
- exhaustruct
- tparallel
- testpackage
- paralleltest
- ifshort
- forcetypeassert
- varnamelen
- prealloc # false-positives
- nosnakecase
- nonamedreturns
- nilerr
issues:
exclude-use-default: false
max-per-linter: 0
max-same-issues: 0
exclude:
- 'ST1000: at least one file in a package should have a package comment'
exclude-rules:
- path: (.+)_test.go
linters:
- funlen
- goconst
- gosec
- maintidx
- path: cmd/revgrep/main.go
linters:
- forbidigo

View File

@ -1,7 +0,0 @@
language: go
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
script:
- $HOME/gopath/bin/goveralls -service=travis-ci

View File

@ -0,0 +1,12 @@
.PHONY: clean lint lint-fix test
default: lint test
test:
go test -v -cover ./...
lint:
golangci-lint run
lint-fix:
golangci-lint run --fix

View File

@ -1,14 +1,11 @@
# Overview
[![Build Status](https://travis-ci.org/bradleyfalzon/revgrep.svg?branch=master)](https://travis-ci.org/bradleyfalzon/revgrep) [![Coverage
Status](https://coveralls.io/repos/github/bradleyfalzon/revgrep/badge.svg?branch=master)](https://coveralls.io/github/bradleyfalzon/revgrep?branch=master) [![GoDoc](https://godoc.org/github.com/bradleyfalzon/revgrep?status.svg)](https://godoc.org/github.com/bradleyfalzon/revgrep)
`revgrep` is a CLI tool used to filter static analysis tools to only lines changed based on a commit reference.
# Install
```bash
go get -u github.com/bradleyfalzon/revgrep/...
go get -u github.com/golangci/revgrep/...
```
# Usage

View File

@ -1,3 +1,3 @@
module github.com/golangci/revgrep
go 1.13
go 1.17

View File

@ -67,23 +67,7 @@ type Issue struct {
Message string
}
func (c *Checker) preparePatch() error {
// Check if patch is supplied, if not, retrieve from VCS
if c.Patch == nil {
var err error
c.Patch, c.NewFiles, err = GitPatch(c.RevisionFrom, c.RevisionTo)
if err != nil {
return fmt.Errorf("could not read git repo: %s", err)
}
if c.Patch == nil {
return errors.New("no version control repository found")
}
}
return nil
}
// InputIssue represents issue found by some linter
// InputIssue represents issue found by some linter.
type InputIssue interface {
FilePath() string
Line() int
@ -94,6 +78,11 @@ type simpleInputIssue struct {
lineNumber int
}
type pos struct {
lineNo int // line number
hunkPos int // position relative to first @@ in file
}
func (i simpleInputIssue) FilePath() string {
return i.filePath
}
@ -102,16 +91,16 @@ func (i simpleInputIssue) Line() int {
return i.lineNumber
}
// Prepare extracts a patch and changed lines
// 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()]
// 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[filepath.ToSlash(i.FilePath())]
if !ok { // file wasn't changed
return 0, false
}
@ -149,24 +138,24 @@ func (c Checker) IsNewIssue(i InputIssue) (hunkPos int, isNew bool) {
// Check scans reader and writes any lines to writer that have been added in
// Checker.Patch.
//
// Returns issues written to writer when no error occurs.
// Returns the issues written to writer when no error occurs.
//
// If no VCS could be found or other VCS errors occur, all issues are written
// to writer and an error is returned.
//
// File paths in reader must be relative to current working directory or
// absolute.
func (c Checker) Check(reader io.Reader, writer io.Writer) (issues []Issue, err error) {
func (c *Checker) Check(reader io.Reader, writer io.Writer) (issues []Issue, err error) {
returnErr := c.Prepare()
writeAll := returnErr != nil
// file.go:lineNo:colNo:message
// colNo is optional, strip spaces before message
lineRE := regexp.MustCompile(`(.*?\.go):([0-9]+):([0-9]+)?:?\s*(.*)`)
lineRE := regexp.MustCompile(`(.+\.go):([0-9]+):([0-9]+)?:?\s*(.*)`)
if c.Regexp != "" {
lineRE, err = regexp.Compile(c.Regexp)
if err != nil {
return nil, fmt.Errorf("could not parse regexp: %v", err)
return nil, fmt.Errorf("could not parse regexp: %w", err)
}
}
@ -178,7 +167,7 @@ func (c Checker) Check(reader io.Reader, writer io.Writer) (issues []Issue, err
if absPath == "" {
absPath, err = os.Getwd()
if err != nil {
returnErr = fmt.Errorf("could not get current working directory: %s", err)
returnErr = fmt.Errorf("could not get current working directory: %w", err)
}
}
@ -192,7 +181,7 @@ func (c Checker) Check(reader io.Reader, writer io.Writer) (issues []Issue, err
}
if writeAll {
fmt.Fprintln(writer, scanner.Text())
_, _ = fmt.Fprintln(writer, scanner.Text())
continue
}
@ -224,11 +213,10 @@ func (c Checker) Check(reader io.Reader, writer io.Writer) (issues []Issue, err
msg := string(line[4])
c.debugf("path: %q, lineNo: %v, colNo: %v, msg: %q", path, lno, cno, msg)
i := simpleInputIssue{
filePath: path,
lineNumber: int(lno),
}
hunkPos, changed := c.IsNewIssue(i)
simpleIssue := simpleInputIssue{filePath: path, lineNumber: int(lno)}
hunkPos, changed := c.IsNewIssue(simpleIssue)
if changed {
issue := Issue{
File: path,
@ -239,33 +227,47 @@ func (c Checker) Check(reader io.Reader, writer io.Writer) (issues []Issue, err
Message: msg,
}
issues = append(issues, issue)
fmt.Fprintln(writer, scanner.Text())
_, _ = fmt.Fprintln(writer, scanner.Text())
} else {
c.debugf("unchanged: %s", scanner.Text())
}
}
if err := scanner.Err(); err != nil {
returnErr = fmt.Errorf("error reading standard input: %s", err)
returnErr = fmt.Errorf("error reading standard input: %w", err)
}
return issues, returnErr
}
func (c Checker) debugf(format string, s ...interface{}) {
func (c *Checker) debugf(format string, s ...interface{}) {
if c.Debug != nil {
fmt.Fprint(c.Debug, "DEBUG: ")
fmt.Fprintf(c.Debug, format+"\n", s...)
_, _ = fmt.Fprint(c.Debug, "DEBUG: ")
_, _ = fmt.Fprintf(c.Debug, format+"\n", s...)
}
}
type pos struct {
lineNo int // line number
hunkPos int // position relative to first @@ in file
func (c *Checker) preparePatch() error {
// Check if patch is supplied, if not, retrieve from VCS
if c.Patch == nil {
var err error
c.Patch, c.NewFiles, err = GitPatch(c.RevisionFrom, c.RevisionTo)
if err != nil {
return fmt.Errorf("could not read git repo: %w", err)
}
if c.Patch == nil {
return errors.New("no version control repository found")
}
}
return nil
}
// linesChanges returns a map of file names to line numbers being changed.
// If key is nil, the file has been recently added, else it contains a slice
// of positions that have been added.
func (c Checker) linesChanged() map[string][]pos {
func (c *Checker) linesChanged() map[string][]pos {
type state struct {
file string
lineNo int // current line number within chunk
@ -273,10 +275,7 @@ func (c Checker) linesChanged() map[string][]pos {
changes []pos // position of changes
}
var (
s state
changes = make(map[string][]pos)
)
changes := make(map[string][]pos)
for _, file := range c.NewFiles {
changes[file] = nil
@ -286,6 +285,8 @@ func (c Checker) linesChanged() map[string][]pos {
return changes
}
var s state
scanner := bufio.NewReader(c.Patch)
var scanErr error
for {
@ -330,11 +331,12 @@ func (c Checker) linesChanged() map[string][]pos {
case strings.HasPrefix(line, "+"):
s.changes = append(s.changes, pos{lineNo: s.lineNo, hunkPos: s.hunkPos})
}
}
if !errors.Is(scanErr, io.EOF) {
_, _ = fmt.Fprintln(os.Stderr, "reading standard input:", scanErr)
}
if scanErr != nil && scanErr != io.EOF {
fmt.Fprintln(os.Stderr, "reading standard input:", scanErr)
}
// record the last state
changes[s.file] = s.changes
@ -353,17 +355,18 @@ func GitPatch(revisionFrom, revisionTo string) (io.Reader, []string, error) {
var patch bytes.Buffer
// check if git repo exists
if err := exec.Command("git", "status").Run(); err != nil {
if err := exec.Command("git", "status", "--porcelain").Run(); err != nil {
// don't return an error, we assume the error is not repo exists
return nil, nil, nil
}
// make a patch for untracked files
var newFiles []string
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)
return nil, nil, fmt.Errorf("error executing git ls-files: %w", err)
}
var newFiles []string
for _, file := range bytes.Split(ls, []byte{'\n'}) {
if len(file) == 0 || bytes.HasSuffix(file, []byte{'/'}) {
// ls-files was sometimes showing directories when they were ignored
@ -375,13 +378,15 @@ func GitPatch(revisionFrom, revisionTo string) (io.Reader, []string, error) {
}
if revisionFrom != "" {
cmd := exec.Command("git", "diff", "--relative", revisionFrom)
cmd := exec.Command("git", "diff", "--color=never", "--relative", revisionFrom)
if revisionTo != "" {
cmd.Args = append(cmd.Args, revisionTo)
}
cmd.Args = append(cmd.Args, "--")
cmd.Stdout = &patch
if err := cmd.Run(); err != nil {
return nil, nil, fmt.Errorf("error executing git diff %q %q: %s", revisionFrom, revisionTo, err)
return nil, nil, fmt.Errorf("error executing git diff %q %q: %w", revisionFrom, revisionTo, err)
}
if revisionTo == "" {
@ -392,10 +397,10 @@ func GitPatch(revisionFrom, revisionTo string) (io.Reader, []string, error) {
// make a patch for unstaged changes
// use --no-prefix to remove b/ given: +++ b/main.go
cmd := exec.Command("git", "diff", "--relative")
cmd := exec.Command("git", "diff", "--color=never", "--relative", "--")
cmd.Stdout = &patch
if err := cmd.Run(); err != nil {
return nil, nil, fmt.Errorf("error executing git diff: %s", err)
return nil, nil, fmt.Errorf("error executing git diff: %w", err)
}
unstaged := patch.Len() > 0
@ -407,10 +412,10 @@ func GitPatch(revisionFrom, revisionTo string) (io.Reader, []string, error) {
// check for changes in recent commit
cmd = exec.Command("git", "diff", "--relative", "HEAD~")
cmd = exec.Command("git", "diff", "--color=never", "--relative", "HEAD~", "--")
cmd.Stdout = &patch
if err := cmd.Run(); err != nil {
return nil, nil, fmt.Errorf("error executing git diff HEAD~: %s", err)
return nil, nil, fmt.Errorf("error executing git diff HEAD~: %w", err)
}
return &patch, nil, nil

View File

@ -3,7 +3,6 @@ package errcheck
import (
"fmt"
"go/ast"
"go/token"
"reflect"
"regexp"
@ -66,7 +65,7 @@ func runAnalyzer(pass *analysis.Pass) (interface{}, error) {
for _, err := range v.errors {
pass.Report(analysis.Diagnostic{
Pos: token.Pos(int(f.Pos()) + err.Pos.Offset),
Pos: pass.Fset.File(f.Pos()).Pos(err.Pos.Offset),
Message: "unchecked error",
})
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Sasha Melentyev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,255 @@
package analyzer
import (
"flag"
"go/ast"
"go/token"
"strings"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)
const (
TimeWeekdayFlag = "time-weekday"
TimeMonthFlag = "time-month"
TimeLayoutFlag = "time-layout"
CryptoHashFlag = "crypto-hash"
HTTPMethodFlag = "http-method"
HTTPStatusCodeFlag = "http-status-code"
DefaultRPCPathFlag = "default-rpc-path"
)
// New returns new usestdlibvars analyzer.
func New() *analysis.Analyzer {
return &analysis.Analyzer{
Name: "usestdlibvars",
Doc: "A linter that detect the possibility to use variables/constants from the Go standard library.",
Run: run,
Flags: flags(),
Requires: []*analysis.Analyzer{inspect.Analyzer},
}
}
func flags() flag.FlagSet {
flags := flag.NewFlagSet("", flag.ExitOnError)
flags.Bool(HTTPMethodFlag, true, "suggest the use of http.MethodXX")
flags.Bool(HTTPStatusCodeFlag, true, "suggest the use of http.StatusXX")
flags.Bool(TimeWeekdayFlag, false, "suggest the use of time.Weekday")
flags.Bool(TimeMonthFlag, false, "suggest the use of time.Month")
flags.Bool(TimeLayoutFlag, false, "suggest the use of time.Layout")
flags.Bool(CryptoHashFlag, false, "suggest the use of crypto.Hash")
flags.Bool(DefaultRPCPathFlag, false, "suggest the use of rpc.DefaultXXPath")
return *flags
}
func run(pass *analysis.Pass) (interface{}, error) {
insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
filter := []ast.Node{
(*ast.BasicLit)(nil),
(*ast.CallExpr)(nil),
(*ast.CompositeLit)(nil),
}
insp.Preorder(filter, func(node ast.Node) {
switch n := node.(type) {
case *ast.CallExpr:
selectorExpr, ok := n.Fun.(*ast.SelectorExpr)
if !ok {
return
}
switch selectorExpr.Sel.Name {
case "WriteHeader":
if !lookupFlag(pass, HTTPStatusCodeFlag) {
return
}
if basicLit := getBasicLitFromArgs(n.Args, 1, 0, token.INT); basicLit != nil {
checkHTTPStatusCode(pass, basicLit)
}
case "NewRequest":
if !lookupFlag(pass, HTTPMethodFlag) {
return
}
if basicLit := getBasicLitFromArgs(n.Args, 3, 0, token.STRING); basicLit != nil {
checkHTTPMethod(pass, basicLit)
}
case "NewRequestWithContext":
if !lookupFlag(pass, HTTPMethodFlag) {
return
}
if basicLit := getBasicLitFromArgs(n.Args, 4, 1, token.STRING); basicLit != nil {
checkHTTPMethod(pass, basicLit)
}
}
case *ast.BasicLit:
currentVal := getBasicLitValue(n)
if lookupFlag(pass, TimeWeekdayFlag) {
checkTimeWeekday(pass, n.Pos(), currentVal)
}
if lookupFlag(pass, TimeMonthFlag) {
checkTimeMonth(pass, n.Pos(), currentVal)
}
if lookupFlag(pass, TimeLayoutFlag) {
checkTimeLayout(pass, n.Pos(), currentVal)
}
if lookupFlag(pass, CryptoHashFlag) {
checkCryptoHash(pass, n.Pos(), currentVal)
}
if lookupFlag(pass, DefaultRPCPathFlag) {
checkDefaultRPCPath(pass, n.Pos(), currentVal)
}
case *ast.CompositeLit:
selectorExpr, ok := n.Type.(*ast.SelectorExpr)
if !ok {
return
}
ident, ok := selectorExpr.X.(*ast.Ident)
if !ok {
return
}
if ident.Name == "http" {
switch selectorExpr.Sel.Name {
case "Request":
if basicLit := getBasicLitFromElts(n.Elts, "Method"); basicLit != nil {
checkHTTPMethod(pass, basicLit)
}
case "Response":
if basicLit := getBasicLitFromElts(n.Elts, "StatusCode"); basicLit != nil {
checkHTTPStatusCode(pass, basicLit)
}
}
}
}
})
return nil, nil
}
func lookupFlag(pass *analysis.Pass, name string) bool {
return pass.Analyzer.Flags.Lookup(name).Value.(flag.Getter).Get().(bool)
}
func checkHTTPMethod(pass *analysis.Pass, basicLit *ast.BasicLit) {
currentVal := getBasicLitValue(basicLit)
newVal, ok := httpMethod[currentVal]
if ok {
report(pass, basicLit.Pos(), newVal, currentVal)
}
}
func checkHTTPStatusCode(pass *analysis.Pass, basicLit *ast.BasicLit) {
currentVal := getBasicLitValue(basicLit)
newVal, ok := httpStatusCode[currentVal]
if ok {
report(pass, basicLit.Pos(), newVal, currentVal)
}
}
func checkTimeWeekday(pass *analysis.Pass, pos token.Pos, currentVal string) {
newVal, ok := timeWeekday[currentVal]
if ok {
report(pass, pos, newVal, currentVal)
}
}
func checkTimeMonth(pass *analysis.Pass, pos token.Pos, currentVal string) {
newVal, ok := timeMonth[currentVal]
if ok {
report(pass, pos, newVal, currentVal)
}
}
func checkTimeLayout(pass *analysis.Pass, pos token.Pos, currentVal string) {
newVal, ok := timeLayout[currentVal]
if ok {
report(pass, pos, newVal, currentVal)
}
}
func checkCryptoHash(pass *analysis.Pass, pos token.Pos, currentVal string) {
newVal, ok := cryptoHash[currentVal]
if ok {
report(pass, pos, newVal, currentVal)
}
}
func checkDefaultRPCPath(pass *analysis.Pass, pos token.Pos, currentVal string) {
newVal, ok := defaultRPCPath[currentVal]
if ok {
report(pass, pos, newVal, currentVal)
}
}
// getBasicLitFromArgs gets the *ast.BasicLit of a function argument.
//
// - count: expected number of argument in function
// - idx: index of the argument to get the *ast.BasicLit
// - typ: argument type
func getBasicLitFromArgs(args []ast.Expr, count, idx int, typ token.Token) *ast.BasicLit {
if len(args) != count {
return nil
}
basicLit, ok := args[idx].(*ast.BasicLit)
if !ok {
return nil
}
if basicLit.Kind != typ {
return nil
}
return basicLit
}
// getBasicLitFromElts gets the *ast.BasicLit of a struct elements.
//
// - key: name of key in struct
func getBasicLitFromElts(elts []ast.Expr, key string) *ast.BasicLit {
for _, e := range elts {
expr, ok := e.(*ast.KeyValueExpr)
if !ok {
continue
}
i, ok := expr.Key.(*ast.Ident)
if !ok {
continue
}
if i.Name != key {
continue
}
basicLit, ok := expr.Value.(*ast.BasicLit)
if !ok {
continue
}
return basicLit
}
return nil
}
func getBasicLitValue(basicLit *ast.BasicLit) string {
return strings.Trim(basicLit.Value, "\"")
}
func report(pass *analysis.Pass, pos token.Pos, newVal, currentVal string) {
pass.Reportf(pos, `%q can be replaced by %s`, currentVal, newVal)
}

View File

@ -0,0 +1,163 @@
package analyzer
import (
"crypto"
"net/http"
"net/rpc"
"strconv"
"time"
)
var cryptoHash = map[string]string{
crypto.MD4.String(): "crypto.MD4.String()",
crypto.MD5.String(): "crypto.MD5.String()",
crypto.SHA1.String(): "crypto.SHA1.String()",
crypto.SHA224.String(): "crypto.SHA224.String()",
crypto.SHA256.String(): "crypto.SHA256.String()",
crypto.SHA384.String(): "crypto.SHA384.String()",
crypto.SHA512.String(): "crypto.SHA512.String()",
crypto.MD5SHA1.String(): "crypto.MD5SHA1.String()",
crypto.RIPEMD160.String(): "crypto.RIPEMD160.String()",
crypto.SHA3_224.String(): "crypto.SHA3_224.String()",
crypto.SHA3_256.String(): "crypto.SHA3_256.String()",
crypto.SHA3_384.String(): "crypto.SHA3_384.String()",
crypto.SHA3_512.String(): "crypto.SHA3_512.String()",
crypto.SHA512_224.String(): "crypto.SHA512_224.String()",
crypto.SHA512_256.String(): "crypto.SHA512_256.String()",
crypto.BLAKE2s_256.String(): "crypto.BLAKE2s_256.String()",
crypto.BLAKE2b_256.String(): "crypto.BLAKE2b_256.String()",
crypto.BLAKE2b_384.String(): "crypto.BLAKE2b_384.String()",
crypto.BLAKE2b_512.String(): "crypto.BLAKE2b_512.String()",
}
var (
httpMethod = map[string]string{
http.MethodGet: "http.MethodGet",
http.MethodHead: "http.MethodHead",
http.MethodPost: "http.MethodPost",
http.MethodPut: "http.MethodPut",
http.MethodPatch: "http.MethodPatch",
http.MethodDelete: "http.MethodDelete",
http.MethodConnect: "http.MethodConnect",
http.MethodOptions: "http.MethodOptions",
http.MethodTrace: "http.MethodTrace",
}
httpStatusCode = map[string]string{
strconv.Itoa(http.StatusContinue): "http.StatusContinue",
strconv.Itoa(http.StatusSwitchingProtocols): "http.StatusSwitchingProtocols",
strconv.Itoa(http.StatusProcessing): "http.StatusProcessing",
strconv.Itoa(http.StatusEarlyHints): "http.StatusEarlyHints",
strconv.Itoa(http.StatusOK): "http.StatusOK",
strconv.Itoa(http.StatusCreated): "http.StatusCreated",
strconv.Itoa(http.StatusAccepted): "http.StatusAccepted",
strconv.Itoa(http.StatusNonAuthoritativeInfo): "http.StatusNonAuthoritativeInfo",
strconv.Itoa(http.StatusNoContent): "http.StatusNoContent",
strconv.Itoa(http.StatusResetContent): "http.StatusResetContent",
strconv.Itoa(http.StatusPartialContent): "http.StatusPartialContent",
strconv.Itoa(http.StatusMultiStatus): "http.StatusMultiStatus",
strconv.Itoa(http.StatusAlreadyReported): "http.StatusAlreadyReported",
strconv.Itoa(http.StatusIMUsed): "http.StatusIMUsed",
strconv.Itoa(http.StatusMultipleChoices): "http.StatusMultipleChoices",
strconv.Itoa(http.StatusMovedPermanently): "http.StatusMovedPermanently",
strconv.Itoa(http.StatusFound): "http.StatusFound",
strconv.Itoa(http.StatusSeeOther): "http.StatusSeeOther",
strconv.Itoa(http.StatusNotModified): "http.StatusNotModified",
strconv.Itoa(http.StatusUseProxy): "http.StatusUseProxy",
strconv.Itoa(http.StatusTemporaryRedirect): "http.StatusTemporaryRedirect",
strconv.Itoa(http.StatusPermanentRedirect): "http.StatusPermanentRedirect",
strconv.Itoa(http.StatusBadRequest): "http.StatusBadRequest",
strconv.Itoa(http.StatusUnauthorized): "http.StatusUnauthorized",
strconv.Itoa(http.StatusPaymentRequired): "http.StatusPaymentRequired",
strconv.Itoa(http.StatusForbidden): "http.StatusForbidden",
strconv.Itoa(http.StatusNotFound): "http.StatusNotFound",
strconv.Itoa(http.StatusMethodNotAllowed): "http.StatusMethodNotAllowed",
strconv.Itoa(http.StatusNotAcceptable): "http.StatusNotAcceptable",
strconv.Itoa(http.StatusProxyAuthRequired): "http.StatusProxyAuthRequired",
strconv.Itoa(http.StatusRequestTimeout): "http.StatusRequestTimeout",
strconv.Itoa(http.StatusConflict): "http.StatusConflict",
strconv.Itoa(http.StatusGone): "http.StatusGone",
strconv.Itoa(http.StatusLengthRequired): "http.StatusLengthRequired",
strconv.Itoa(http.StatusPreconditionFailed): "http.StatusPreconditionFailed",
strconv.Itoa(http.StatusRequestEntityTooLarge): "http.StatusRequestEntityTooLarge",
strconv.Itoa(http.StatusRequestURITooLong): "http.StatusRequestURITooLong",
strconv.Itoa(http.StatusUnsupportedMediaType): "http.StatusUnsupportedMediaType",
strconv.Itoa(http.StatusRequestedRangeNotSatisfiable): "http.StatusRequestedRangeNotSatisfiable",
strconv.Itoa(http.StatusExpectationFailed): "http.StatusExpectationFailed",
strconv.Itoa(http.StatusTeapot): "http.StatusTeapot",
strconv.Itoa(http.StatusMisdirectedRequest): "http.StatusMisdirectedRequest",
strconv.Itoa(http.StatusUnprocessableEntity): "http.StatusUnprocessableEntity",
strconv.Itoa(http.StatusLocked): "http.StatusLocked",
strconv.Itoa(http.StatusFailedDependency): "http.StatusFailedDependency",
strconv.Itoa(http.StatusTooEarly): "http.StatusTooEarly",
strconv.Itoa(http.StatusUpgradeRequired): "http.StatusUpgradeRequired",
strconv.Itoa(http.StatusPreconditionRequired): "http.StatusPreconditionRequired",
strconv.Itoa(http.StatusTooManyRequests): "http.StatusTooManyRequests",
strconv.Itoa(http.StatusRequestHeaderFieldsTooLarge): "http.StatusRequestHeaderFieldsTooLarge",
strconv.Itoa(http.StatusUnavailableForLegalReasons): "http.StatusUnavailableForLegalReasons",
strconv.Itoa(http.StatusInternalServerError): "http.StatusInternalServerError",
strconv.Itoa(http.StatusNotImplemented): "http.StatusNotImplemented",
strconv.Itoa(http.StatusBadGateway): "http.StatusBadGateway",
strconv.Itoa(http.StatusServiceUnavailable): "http.StatusServiceUnavailable",
strconv.Itoa(http.StatusGatewayTimeout): "http.StatusGatewayTimeout",
strconv.Itoa(http.StatusHTTPVersionNotSupported): "http.StatusHTTPVersionNotSupported",
strconv.Itoa(http.StatusVariantAlsoNegotiates): "http.StatusVariantAlsoNegotiates",
strconv.Itoa(http.StatusInsufficientStorage): "http.StatusInsufficientStorage",
strconv.Itoa(http.StatusLoopDetected): "http.StatusLoopDetected",
strconv.Itoa(http.StatusNotExtended): "http.StatusNotExtended",
strconv.Itoa(http.StatusNetworkAuthenticationRequired): "http.StatusNetworkAuthenticationRequired",
}
)
var defaultRPCPath = map[string]string{
rpc.DefaultRPCPath: "rpc.DefaultRPCPath",
rpc.DefaultDebugPath: "rpc.DefaultDebugPath",
}
var (
timeWeekday = map[string]string{
time.Sunday.String(): "time.Sunday.String()",
time.Monday.String(): "time.Monday.String()",
time.Tuesday.String(): "time.Tuesday.String()",
time.Wednesday.String(): "time.Wednesday.String()",
time.Thursday.String(): "time.Thursday.String()",
time.Friday.String(): "time.Friday.String()",
time.Saturday.String(): "time.Saturday.String()",
}
timeMonth = map[string]string{
time.January.String(): "time.January.String()",
time.February.String(): "time.February.String()",
time.March.String(): "time.March.String()",
time.April.String(): "time.April.String()",
time.May.String(): "time.May.String()",
time.June.String(): "time.June.String()",
time.July.String(): "time.July.String()",
time.August.String(): "time.August.String()",
time.September.String(): "time.September.String()",
time.October.String(): "time.October.String()",
time.November.String(): "time.November.String()",
time.December.String(): "time.December.String()",
}
)
var timeLayout = map[string]string{
time.Layout: "time.Layout",
time.ANSIC: "time.ANSIC",
time.UnixDate: "time.UnixDate",
time.RubyDate: "time.RubyDate",
time.RFC822: "time.RFC822",
time.RFC822Z: "time.RFC822Z",
time.RFC850: "time.RFC850",
time.RFC1123: "time.RFC1123",
time.RFC1123Z: "time.RFC1123Z",
time.RFC3339: "time.RFC3339",
time.RFC3339Nano: "time.RFC3339Nano",
time.Kitchen: "time.Kitchen",
time.Stamp: "time.Stamp",
time.StampMilli: "time.StampMilli",
time.StampMicro: "time.StampMicro",
time.StampNano: "time.StampNano",
}

View File

@ -49,7 +49,7 @@ github.com/chavacava/garif
## explicit
github.com/cpuguy83/go-md2man/v2
github.com/cpuguy83/go-md2man/v2/md2man
# github.com/daixiang0/gci v0.5.0
# github.com/daixiang0/gci v0.6.2
github.com/daixiang0/gci/pkg/config
github.com/daixiang0/gci/pkg/format
github.com/daixiang0/gci/pkg/gci
@ -133,7 +133,7 @@ github.com/golangci/go-misc/deadcode
# github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a
github.com/golangci/gofmt/gofmt
github.com/golangci/gofmt/goimports
# github.com/golangci/golangci-lint v1.47.3
# github.com/golangci/golangci-lint v1.48.0
## explicit
github.com/golangci/golangci-lint/cmd/golangci-lint
github.com/golangci/golangci-lint/internal/cache
@ -167,7 +167,7 @@ github.com/golangci/lint-1
github.com/golangci/maligned
# github.com/golangci/misspell v0.3.5
github.com/golangci/misspell
# github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2
# github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6
github.com/golangci/revgrep
# github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4
github.com/golangci/unconvert
@ -219,7 +219,7 @@ github.com/jingyugao/rowserrcheck/passes/rowserr
github.com/jirfag/go-printf-func-name/pkg/analyzer
# github.com/julz/importas v0.1.0
github.com/julz/importas
# github.com/kisielk/errcheck v1.6.1
# github.com/kisielk/errcheck v1.6.2
github.com/kisielk/errcheck/errcheck
# github.com/kisielk/gotool v1.0.0
github.com/kisielk/gotool
@ -379,6 +379,8 @@ github.com/ryancurrah/gomodguard
github.com/ryanrolds/sqlclosecheck/pkg/analyzer
# github.com/sanposhiho/wastedassign/v2 v2.0.6
github.com/sanposhiho/wastedassign/v2
# github.com/sashamelentyev/usestdlibvars v1.8.0
github.com/sashamelentyev/usestdlibvars/pkg/analyzer
# github.com/securego/gosec/v2 v2.12.0
github.com/securego/gosec/v2
github.com/securego/gosec/v2/cwe