aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mgechev
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mgechev')
-rw-r--r--vendor/github.com/mgechev/revive/config/config.go14
-rw-r--r--vendor/github.com/mgechev/revive/formatter/sarif.go2
-rw-r--r--vendor/github.com/mgechev/revive/internal/ifelse/args.go11
-rw-r--r--vendor/github.com/mgechev/revive/internal/ifelse/branch.go93
-rw-r--r--vendor/github.com/mgechev/revive/internal/ifelse/branch_kind.go101
-rw-r--r--vendor/github.com/mgechev/revive/internal/ifelse/chain.go10
-rw-r--r--vendor/github.com/mgechev/revive/internal/ifelse/doc.go6
-rw-r--r--vendor/github.com/mgechev/revive/internal/ifelse/func.go51
-rw-r--r--vendor/github.com/mgechev/revive/internal/ifelse/rule.go105
-rw-r--r--vendor/github.com/mgechev/revive/internal/ifelse/target.go25
-rw-r--r--vendor/github.com/mgechev/revive/lint/config.go28
-rw-r--r--vendor/github.com/mgechev/revive/lint/file.go3
-rw-r--r--vendor/github.com/mgechev/revive/lint/filefilter.go128
-rw-r--r--vendor/github.com/mgechev/revive/rule/argument-limit.go9
-rw-r--r--vendor/github.com/mgechev/revive/rule/banned-characters.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/cognitive-complexity.go10
-rw-r--r--vendor/github.com/mgechev/revive/rule/confusing-naming.go11
-rw-r--r--vendor/github.com/mgechev/revive/rule/cyclomatic.go9
-rw-r--r--vendor/github.com/mgechev/revive/rule/defer.go15
-rw-r--r--vendor/github.com/mgechev/revive/rule/dot-imports.go5
-rw-r--r--vendor/github.com/mgechev/revive/rule/early-return.go165
-rw-r--r--vendor/github.com/mgechev/revive/rule/enforce-map-style.go164
-rw-r--r--vendor/github.com/mgechev/revive/rule/file-header.go13
-rw-r--r--vendor/github.com/mgechev/revive/rule/function-length.go9
-rw-r--r--vendor/github.com/mgechev/revive/rule/function-result-limit.go10
-rw-r--r--vendor/github.com/mgechev/revive/rule/import-alias-naming.go79
-rw-r--r--vendor/github.com/mgechev/revive/rule/import-shadowing.go11
-rw-r--r--vendor/github.com/mgechev/revive/rule/imports-blacklist.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/indent-error-flow.go79
-rw-r--r--vendor/github.com/mgechev/revive/rule/line-length-limit.go9
-rw-r--r--vendor/github.com/mgechev/revive/rule/max-public-structs.go9
-rw-r--r--vendor/github.com/mgechev/revive/rule/redundant-import-alias.go52
-rw-r--r--vendor/github.com/mgechev/revive/rule/string-format.go10
-rw-r--r--vendor/github.com/mgechev/revive/rule/superfluous-else.go110
-rw-r--r--vendor/github.com/mgechev/revive/rule/time-equal.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/unchecked-type-assertion.go194
-rw-r--r--vendor/github.com/mgechev/revive/rule/unused-param.go67
-rw-r--r--vendor/github.com/mgechev/revive/rule/unused-receiver.go66
-rw-r--r--vendor/github.com/mgechev/revive/rule/var-naming.go111
39 files changed, 1416 insertions, 390 deletions
diff --git a/vendor/github.com/mgechev/revive/config/config.go b/vendor/github.com/mgechev/revive/config/config.go
index 04cd21404..abd554a9f 100644
--- a/vendor/github.com/mgechev/revive/config/config.go
+++ b/vendor/github.com/mgechev/revive/config/config.go
@@ -31,7 +31,6 @@ var defaultRules = []lint.Rule{
&rule.TimeNamingRule{},
&rule.ContextKeysType{},
&rule.ContextAsArgumentRule{},
- &rule.IfReturnRule{},
&rule.EmptyBlockRule{},
&rule.SuperfluousElseRule{},
&rule.UnusedParamRule{},
@@ -81,12 +80,17 @@ var allRules = append([]lint.Rule{
&rule.FunctionLength{},
&rule.NestedStructs{},
&rule.UselessBreak{},
+ &rule.UncheckedTypeAssertionRule{},
&rule.TimeEqualRule{},
&rule.BannedCharsRule{},
&rule.OptimizeOperandsOrderRule{},
&rule.UseAnyRule{},
&rule.DataRaceRule{},
&rule.CommentSpacingsRule{},
+ &rule.IfReturnRule{},
+ &rule.RedundantImportAlias{},
+ &rule.ImportAliasNamingRule{},
+ &rule.EnforceMapStyleRule{},
}, defaultRules...)
var allFormatters = []lint.Formatter{
@@ -148,6 +152,14 @@ func parseConfig(path string, config *lint.Config) error {
if err != nil {
return fmt.Errorf("cannot parse the config file: %v", err)
}
+ for k, r := range config.Rules {
+ err := r.Initialize()
+ if err != nil {
+ return fmt.Errorf("error in config of rule [%s] : [%v]", k, err)
+ }
+ config.Rules[k] = r
+ }
+
return nil
}
diff --git a/vendor/github.com/mgechev/revive/formatter/sarif.go b/vendor/github.com/mgechev/revive/formatter/sarif.go
index c6288db76..c42da73eb 100644
--- a/vendor/github.com/mgechev/revive/formatter/sarif.go
+++ b/vendor/github.com/mgechev/revive/formatter/sarif.go
@@ -88,7 +88,7 @@ func (l *reviveRunLog) AddResult(failure lint.Failure) {
location := garif.NewLocation().WithURI(filename).WithLineColumn(line, column)
result.Locations = append(result.Locations, location)
result.RuleId = failure.RuleName
- result.Level = l.rules[failure.RuleName].Severity
+ result.Level = garif.ResultLevel(l.rules[failure.RuleName].Severity)
l.run.Results = append(l.run.Results, result)
}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/args.go b/vendor/github.com/mgechev/revive/internal/ifelse/args.go
new file mode 100644
index 000000000..c6e647e69
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/args.go
@@ -0,0 +1,11 @@
+package ifelse
+
+// PreserveScope is a configuration argument that prevents suggestions
+// that would enlarge variable scope
+const PreserveScope = "preserveScope"
+
+// Args contains arguments common to the early-return, indent-error-flow
+// and superfluous-else rules (currently just preserveScope)
+type Args struct {
+ PreserveScope bool
+}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/branch.go b/vendor/github.com/mgechev/revive/internal/ifelse/branch.go
new file mode 100644
index 000000000..6e6036b89
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/branch.go
@@ -0,0 +1,93 @@
+package ifelse
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+)
+
+// Branch contains information about a branch within an if-else chain.
+type Branch struct {
+ BranchKind
+ Call // The function called at the end for kind Panic or Exit.
+ HasDecls bool // The branch has one or more declarations (at the top level block)
+}
+
+// BlockBranch gets the Branch of an ast.BlockStmt.
+func BlockBranch(block *ast.BlockStmt) Branch {
+ blockLen := len(block.List)
+ if blockLen == 0 {
+ return Empty.Branch()
+ }
+
+ branch := StmtBranch(block.List[blockLen-1])
+ branch.HasDecls = hasDecls(block)
+ return branch
+}
+
+// StmtBranch gets the Branch of an ast.Stmt.
+func StmtBranch(stmt ast.Stmt) Branch {
+ switch stmt := stmt.(type) {
+ case *ast.ReturnStmt:
+ return Return.Branch()
+ case *ast.BlockStmt:
+ return BlockBranch(stmt)
+ case *ast.BranchStmt:
+ switch stmt.Tok {
+ case token.BREAK:
+ return Break.Branch()
+ case token.CONTINUE:
+ return Continue.Branch()
+ case token.GOTO:
+ return Goto.Branch()
+ }
+ case *ast.ExprStmt:
+ fn, ok := ExprCall(stmt)
+ if !ok {
+ break
+ }
+ kind, ok := DeviatingFuncs[fn]
+ if ok {
+ return Branch{BranchKind: kind, Call: fn}
+ }
+ case *ast.EmptyStmt:
+ return Empty.Branch()
+ case *ast.LabeledStmt:
+ return StmtBranch(stmt.Stmt)
+ }
+ return Regular.Branch()
+}
+
+// String returns a brief string representation
+func (b Branch) String() string {
+ switch b.BranchKind {
+ case Panic, Exit:
+ return fmt.Sprintf("... %v()", b.Call)
+ default:
+ return b.BranchKind.String()
+ }
+}
+
+// LongString returns a longer form string representation
+func (b Branch) LongString() string {
+ switch b.BranchKind {
+ case Panic, Exit:
+ return fmt.Sprintf("call to %v function", b.Call)
+ default:
+ return b.BranchKind.LongString()
+ }
+}
+
+func hasDecls(block *ast.BlockStmt) bool {
+ for _, stmt := range block.List {
+ switch stmt := stmt.(type) {
+ case *ast.DeclStmt:
+ return true
+ case *ast.AssignStmt:
+ if stmt.Tok == token.DEFINE {
+ return true
+ }
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/branch_kind.go b/vendor/github.com/mgechev/revive/internal/ifelse/branch_kind.go
new file mode 100644
index 000000000..41601d1e1
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/branch_kind.go
@@ -0,0 +1,101 @@
+package ifelse
+
+// BranchKind is a classifier for if-else branches. It says whether the branch is empty,
+// and whether the branch ends with a statement that deviates control flow.
+type BranchKind int
+
+const (
+ // Empty branches do nothing
+ Empty BranchKind = iota
+
+ // Return branches return from the current function
+ Return
+
+ // Continue branches continue a surrounding "for" loop
+ Continue
+
+ // Break branches break a surrounding "for" loop
+ Break
+
+ // Goto branches conclude with a "goto" statement
+ Goto
+
+ // Panic branches panic the current function
+ Panic
+
+ // Exit branches end the program
+ Exit
+
+ // Regular branches do not fit any category above
+ Regular
+)
+
+// IsEmpty tests if the branch is empty
+func (k BranchKind) IsEmpty() bool { return k == Empty }
+
+// Returns tests if the branch returns from the current function
+func (k BranchKind) Returns() bool { return k == Return }
+
+// Deviates tests if the control does not flow to the first
+// statement following the if-else chain.
+func (k BranchKind) Deviates() bool {
+ switch k {
+ case Empty, Regular:
+ return false
+ case Return, Continue, Break, Goto, Panic, Exit:
+ return true
+ default:
+ panic("invalid kind")
+ }
+}
+
+// Branch returns a Branch with the given kind
+func (k BranchKind) Branch() Branch { return Branch{BranchKind: k} }
+
+// String returns a brief string representation
+func (k BranchKind) String() string {
+ switch k {
+ case Empty:
+ return ""
+ case Regular:
+ return "..."
+ case Return:
+ return "... return"
+ case Continue:
+ return "... continue"
+ case Break:
+ return "... break"
+ case Goto:
+ return "... goto"
+ case Panic:
+ return "... panic()"
+ case Exit:
+ return "... os.Exit()"
+ default:
+ panic("invalid kind")
+ }
+}
+
+// LongString returns a longer form string representation
+func (k BranchKind) LongString() string {
+ switch k {
+ case Empty:
+ return "an empty block"
+ case Regular:
+ return "a regular statement"
+ case Return:
+ return "a return statement"
+ case Continue:
+ return "a continue statement"
+ case Break:
+ return "a break statement"
+ case Goto:
+ return "a goto statement"
+ case Panic:
+ return "a function call that panics"
+ case Exit:
+ return "a function call that exits the program"
+ default:
+ panic("invalid kind")
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/chain.go b/vendor/github.com/mgechev/revive/internal/ifelse/chain.go
new file mode 100644
index 000000000..9891635ee
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/chain.go
@@ -0,0 +1,10 @@
+package ifelse
+
+// Chain contains information about an if-else chain.
+type Chain struct {
+ If Branch // what happens at the end of the "if" block
+ Else Branch // what happens at the end of the "else" block
+ HasInitializer bool // is there an "if"-initializer somewhere in the chain?
+ HasPriorNonDeviating bool // is there a prior "if" block that does NOT deviate control flow?
+ AtBlockEnd bool // whether the chain is placed at the end of the surrounding block
+}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/doc.go b/vendor/github.com/mgechev/revive/internal/ifelse/doc.go
new file mode 100644
index 000000000..0aa2c9817
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/doc.go
@@ -0,0 +1,6 @@
+// Package ifelse provides helpers for analysing the control flow in if-else chains,
+// presently used by the following rules:
+// - early-return
+// - indent-error-flow
+// - superfluous-else
+package ifelse
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/func.go b/vendor/github.com/mgechev/revive/internal/ifelse/func.go
new file mode 100644
index 000000000..7ba351918
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/func.go
@@ -0,0 +1,51 @@
+package ifelse
+
+import (
+ "fmt"
+ "go/ast"
+)
+
+// Call contains the name of a function that deviates control flow.
+type Call struct {
+ Pkg string // The package qualifier of the function, if not built-in.
+ Name string // The function name.
+}
+
+// DeviatingFuncs lists known control flow deviating function calls.
+var DeviatingFuncs = map[Call]BranchKind{
+ {"os", "Exit"}: Exit,
+ {"log", "Fatal"}: Exit,
+ {"log", "Fatalf"}: Exit,
+ {"log", "Fatalln"}: Exit,
+ {"", "panic"}: Panic,
+ {"log", "Panic"}: Panic,
+ {"log", "Panicf"}: Panic,
+ {"log", "Panicln"}: Panic,
+}
+
+// ExprCall gets the Call of an ExprStmt, if any.
+func ExprCall(expr *ast.ExprStmt) (Call, bool) {
+ call, ok := expr.X.(*ast.CallExpr)
+ if !ok {
+ return Call{}, false
+ }
+ switch v := call.Fun.(type) {
+ case *ast.Ident:
+ return Call{Name: v.Name}, true
+ case *ast.SelectorExpr:
+ if ident, ok := v.X.(*ast.Ident); ok {
+ return Call{Name: v.Sel.Name, Pkg: ident.Name}, true
+ }
+ }
+ return Call{}, false
+}
+
+// String returns the function name with package qualifier (if any)
+func (f Call) String() string {
+ switch {
+ case f.Pkg != "":
+ return fmt.Sprintf("%s.%s", f.Pkg, f.Name)
+ default:
+ return f.Name
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/rule.go b/vendor/github.com/mgechev/revive/internal/ifelse/rule.go
new file mode 100644
index 000000000..07ad456b6
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/rule.go
@@ -0,0 +1,105 @@
+package ifelse
+
+import (
+ "go/ast"
+ "go/token"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// Rule is an interface for linters operating on if-else chains
+type Rule interface {
+ CheckIfElse(chain Chain, args Args) (failMsg string)
+}
+
+// Apply evaluates the given Rule on if-else chains found within the given AST,
+// and returns the failures.
+//
+// Note that in if-else chain with multiple "if" blocks, only the *last* one is checked,
+// that is to say, given:
+//
+// if foo {
+// ...
+// } else if bar {
+// ...
+// } else {
+// ...
+// }
+//
+// Only the block following "bar" is linted. This is because the rules that use this function
+// do not presently have anything to say about earlier blocks in the chain.
+func Apply(rule Rule, node ast.Node, target Target, args lint.Arguments) []lint.Failure {
+ v := &visitor{rule: rule, target: target}
+ for _, arg := range args {
+ if arg == PreserveScope {
+ v.args.PreserveScope = true
+ }
+ }
+ ast.Walk(v, node)
+ return v.failures
+}
+
+type visitor struct {
+ failures []lint.Failure
+ target Target
+ rule Rule
+ args Args
+}
+
+func (v *visitor) Visit(node ast.Node) ast.Visitor {
+ block, ok := node.(*ast.BlockStmt)
+ if !ok {
+ return v
+ }
+
+ for i, stmt := range block.List {
+ if ifStmt, ok := stmt.(*ast.IfStmt); ok {
+ v.visitChain(ifStmt, Chain{AtBlockEnd: i == len(block.List)-1})
+ continue
+ }
+ ast.Walk(v, stmt)
+ }
+ return nil
+}
+
+func (v *visitor) visitChain(ifStmt *ast.IfStmt, chain Chain) {
+ // look for other if-else chains nested inside this if { } block
+ ast.Walk(v, ifStmt.Body)
+
+ if ifStmt.Else == nil {
+ // no else branch
+ return
+ }
+
+ if as, ok := ifStmt.Init.(*ast.AssignStmt); ok && as.Tok == token.DEFINE {
+ chain.HasInitializer = true
+ }
+ chain.If = BlockBranch(ifStmt.Body)
+
+ switch elseBlock := ifStmt.Else.(type) {
+ case *ast.IfStmt:
+ if !chain.If.Deviates() {
+ chain.HasPriorNonDeviating = true
+ }
+ v.visitChain(elseBlock, chain)
+ case *ast.BlockStmt:
+ // look for other if-else chains nested inside this else { } block
+ ast.Walk(v, elseBlock)
+
+ chain.Else = BlockBranch(elseBlock)
+ if failMsg := v.rule.CheckIfElse(chain, v.args); failMsg != "" {
+ if chain.HasInitializer {
+ // if statement has a := initializer, so we might need to move the assignment
+ // onto its own line in case the body references it
+ failMsg += " (move short variable declaration to its own line if necessary)"
+ }
+ v.failures = append(v.failures, lint.Failure{
+ Confidence: 1,
+ Node: v.target.node(ifStmt),
+ Failure: failMsg,
+ })
+ }
+ default:
+ panic("invalid node type for else")
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/target.go b/vendor/github.com/mgechev/revive/internal/ifelse/target.go
new file mode 100644
index 000000000..81ff1c303
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/target.go
@@ -0,0 +1,25 @@
+package ifelse
+
+import "go/ast"
+
+// Target decides what line/column should be indicated by the rule in question.
+type Target int
+
+const (
+ // TargetIf means the text refers to the "if"
+ TargetIf Target = iota
+
+ // TargetElse means the text refers to the "else"
+ TargetElse
+)
+
+func (t Target) node(ifStmt *ast.IfStmt) ast.Node {
+ switch t {
+ case TargetIf:
+ return ifStmt
+ case TargetElse:
+ return ifStmt.Else
+ default:
+ panic("bad target")
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/lint/config.go b/vendor/github.com/mgechev/revive/lint/config.go
index 276305804..9b26d5841 100644
--- a/vendor/github.com/mgechev/revive/lint/config.go
+++ b/vendor/github.com/mgechev/revive/lint/config.go
@@ -3,16 +3,44 @@ package lint
// Arguments is type used for the arguments of a rule.
type Arguments = []interface{}
+type FileFilters = []*FileFilter
+
// RuleConfig is type used for the rule configuration.
type RuleConfig struct {
Arguments Arguments
Severity Severity
Disabled bool
+ // Exclude - rule-level file excludes, TOML related (strings)
+ Exclude []string
+ // excludeFilters - regex-based file filters, initialized from Exclude
+ excludeFilters []*FileFilter
+}
+
+// Initialize - should be called after reading from TOML file
+func (rc *RuleConfig) Initialize() error {
+ for _, f := range rc.Exclude {
+ ff, err := ParseFileFilter(f)
+ if err != nil {
+ return err
+ }
+ rc.excludeFilters = append(rc.excludeFilters, ff)
+ }
+ return nil
}
// RulesConfig defines the config for all rules.
type RulesConfig = map[string]RuleConfig
+// MustExclude - checks if given filename `name` must be excluded
+func (rcfg *RuleConfig) MustExclude(name string) bool {
+ for _, exclude := range rcfg.excludeFilters {
+ if exclude.MatchFileName(name) {
+ return true
+ }
+ }
+ return false
+}
+
// DirectiveConfig is type used for the linter directive configuration.
type DirectiveConfig struct {
Severity Severity
diff --git a/vendor/github.com/mgechev/revive/lint/file.go b/vendor/github.com/mgechev/revive/lint/file.go
index dcf0e608f..23255304c 100644
--- a/vendor/github.com/mgechev/revive/lint/file.go
+++ b/vendor/github.com/mgechev/revive/lint/file.go
@@ -102,6 +102,9 @@ func (f *File) lint(rules []Rule, config Config, failures chan Failure) {
disabledIntervals := f.disabledIntervals(rules, mustSpecifyDisableReason, failures)
for _, currentRule := range rules {
ruleConfig := rulesConfig[currentRule.Name()]
+ if ruleConfig.MustExclude(f.Name) {
+ continue
+ }
currentFailures := currentRule.Apply(f, ruleConfig.Arguments)
for idx, failure := range currentFailures {
if failure.RuleName == "" {
diff --git a/vendor/github.com/mgechev/revive/lint/filefilter.go b/vendor/github.com/mgechev/revive/lint/filefilter.go
new file mode 100644
index 000000000..8da090b9c
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/lint/filefilter.go
@@ -0,0 +1,128 @@
+package lint
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+)
+
+// FileFilter - file filter to exclude some files for rule
+// supports whole
+// 1. file/dir names : pkg/mypkg/my.go,
+// 2. globs: **/*.pb.go,
+// 3. regexes (~ prefix) ~-tmp\.\d+\.go
+// 4. special test marker `TEST` - treats as `~_test\.go`
+type FileFilter struct {
+ // raw definition of filter inside config
+ raw string
+ // don't care what was at start, will use regexes inside
+ rx *regexp.Regexp
+ // marks filter as matching everything
+ matchesAll bool
+ // marks filter as matching nothing
+ matchesNothing bool
+}
+
+// ParseFileFilter - creates [FileFilter] for given raw filter
+// if empty string, it matches nothing
+// if `*`, or `~`, it matches everything
+// while regexp could be invalid, it could return it's compilation error
+func ParseFileFilter(rawFilter string) (*FileFilter, error) {
+ rawFilter = strings.TrimSpace(rawFilter)
+ result := new(FileFilter)
+ result.raw = rawFilter
+ result.matchesNothing = len(result.raw) == 0
+ result.matchesAll = result.raw == "*" || result.raw == "~"
+ if !result.matchesAll && !result.matchesNothing {
+ if err := result.prepareRegexp(); err != nil {
+ return nil, err
+ }
+ }
+ return result, nil
+}
+
+func (ff *FileFilter) String() string { return ff.raw }
+
+// MatchFileName - checks if file name matches filter
+func (ff *FileFilter) MatchFileName(name string) bool {
+ if ff.matchesAll {
+ return true
+ }
+ if ff.matchesNothing {
+ return false
+ }
+ name = strings.ReplaceAll(name, "\\", "/")
+ return ff.rx.MatchString(name)
+}
+
+var fileFilterInvalidGlobRegexp = regexp.MustCompile(`[^/]\*\*[^/]`)
+var escapeRegexSymbols = ".+{}()[]^$"
+
+func (ff *FileFilter) prepareRegexp() error {
+ var err error
+ var src = ff.raw
+ if src == "TEST" {
+ src = "~_test\\.go"
+ }
+ if strings.HasPrefix(src, "~") {
+ ff.rx, err = regexp.Compile(src[1:])
+ if err != nil {
+ return fmt.Errorf("invalid file filter [%s], regexp compile error: [%v]", ff.raw, err)
+ }
+ return nil
+ }
+ /* globs */
+ if strings.Contains(src, "*") {
+ if fileFilterInvalidGlobRegexp.MatchString(src) {
+ return fmt.Errorf("invalid file filter [%s], invalid glob pattern", ff.raw)
+ }
+ var rxBuild strings.Builder
+ rxBuild.WriteByte('^')
+ wasStar := false
+ justDirGlob := false
+ for _, c := range src {
+ if c == '*' {
+ if wasStar {
+ rxBuild.WriteString(`[\s\S]*`)
+ wasStar = false
+ justDirGlob = true
+ continue
+ }
+ wasStar = true
+ continue
+ }
+ if wasStar {
+ rxBuild.WriteString("[^/]*")
+ wasStar = false
+ }
+ if strings.ContainsRune(escapeRegexSymbols, c) {
+ rxBuild.WriteByte('\\')
+ }
+ rxBuild.WriteRune(c)
+ if c == '/' && justDirGlob {
+ rxBuild.WriteRune('?')
+ }
+ justDirGlob = false
+ }
+ if wasStar {
+ rxBuild.WriteString("[^/]*")
+ }
+ rxBuild.WriteByte('$')
+ ff.rx, err = regexp.Compile(rxBuild.String())
+ if err != nil {
+ return fmt.Errorf("invalid file filter [%s], regexp compile error after glob expand: [%v]", ff.raw, err)
+ }
+ return nil
+ }
+
+ // it's whole file mask, just escape dots and normilze separators
+ fillRx := src
+ fillRx = strings.ReplaceAll(fillRx, "\\", "/")
+ fillRx = strings.ReplaceAll(fillRx, ".", `\.`)
+ fillRx = "^" + fillRx + "$"
+ ff.rx, err = regexp.Compile(fillRx)
+ if err != nil {
+ return fmt.Errorf("invalid file filter [%s], regexp compile full path: [%v]", ff.raw, err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/mgechev/revive/rule/argument-limit.go b/vendor/github.com/mgechev/revive/rule/argument-limit.go
index 8042da15e..8120288fd 100644
--- a/vendor/github.com/mgechev/revive/rule/argument-limit.go
+++ b/vendor/github.com/mgechev/revive/rule/argument-limit.go
@@ -14,10 +14,16 @@ type ArgumentsLimitRule struct {
sync.Mutex
}
+const defaultArgumentsLimit = 8
+
func (r *ArgumentsLimitRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.total == 0 {
- checkNumberOfArguments(1, arguments, r.Name())
+ if len(arguments) < 1 {
+ r.total = defaultArgumentsLimit
+ return
+ }
total, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
@@ -25,7 +31,6 @@ func (r *ArgumentsLimitRule) configure(arguments lint.Arguments) {
}
r.total = int(total)
}
- r.Unlock()
}
// Apply applies the rule to given file.
diff --git a/vendor/github.com/mgechev/revive/rule/banned-characters.go b/vendor/github.com/mgechev/revive/rule/banned-characters.go
index 76fa2235a..12997bae1 100644
--- a/vendor/github.com/mgechev/revive/rule/banned-characters.go
+++ b/vendor/github.com/mgechev/revive/rule/banned-characters.go
@@ -19,11 +19,11 @@ const bannedCharsRuleName = "banned-characters"
func (r *BannedCharsRule) configure(arguments lint.Arguments) {
r.Lock()
- if r.bannedCharList == nil {
+ defer r.Unlock()
+ if r.bannedCharList == nil && len(arguments) > 0 {
checkNumberOfArguments(1, arguments, bannedCharsRuleName)
r.bannedCharList = r.getBannedCharsList(arguments)
}
- r.Unlock()
}
// Apply applied the rule to the given file.
diff --git a/vendor/github.com/mgechev/revive/rule/cognitive-complexity.go b/vendor/github.com/mgechev/revive/rule/cognitive-complexity.go
index a9c11a7d0..1973faef8 100644
--- a/vendor/github.com/mgechev/revive/rule/cognitive-complexity.go
+++ b/vendor/github.com/mgechev/revive/rule/cognitive-complexity.go
@@ -16,10 +16,17 @@ type CognitiveComplexityRule struct {
sync.Mutex
}
+const defaultMaxCognitiveComplexity = 7
+
func (r *CognitiveComplexityRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.maxComplexity == 0 {
- checkNumberOfArguments(1, arguments, r.Name())
+
+ if len(arguments) < 1 {
+ r.maxComplexity = defaultMaxCognitiveComplexity
+ return
+ }
complexity, ok := arguments[0].(int64)
if !ok {
@@ -27,7 +34,6 @@ func (r *CognitiveComplexityRule) configure(arguments lint.Arguments) {
}
r.maxComplexity = int(complexity)
}
- r.Unlock()
}
// Apply applies the rule to given file.
diff --git a/vendor/github.com/mgechev/revive/rule/confusing-naming.go b/vendor/github.com/mgechev/revive/rule/confusing-naming.go
index 34cdb907a..8b1c3eac4 100644
--- a/vendor/github.com/mgechev/revive/rule/confusing-naming.go
+++ b/vendor/github.com/mgechev/revive/rule/confusing-naming.go
@@ -27,10 +27,10 @@ type packages struct {
func (ps *packages) methodNames(lp *lint.Package) pkgMethods {
ps.mu.Lock()
+ defer ps.mu.Unlock()
for _, pkg := range ps.pkgs {
if pkg.pkg == lp {
- ps.mu.Unlock()
return pkg
}
}
@@ -38,7 +38,6 @@ func (ps *packages) methodNames(lp *lint.Package) pkgMethods {
pkgm := pkgMethods{pkg: lp, methods: make(map[string]map[string]*referenceMethod), mu: &sync.Mutex{}}
ps.pkgs = append(ps.pkgs, pkgm)
- ps.mu.Unlock()
return pkgm
}
@@ -72,6 +71,7 @@ func (*ConfusingNamingRule) Name() string {
// checkMethodName checks if a given method/function name is similar (just case differences) to other method/function of the same struct/file.
func checkMethodName(holder string, id *ast.Ident, w *lintConfusingNames) {
+
if id.Name == "init" && holder == defaultStructName {
// ignore init functions
return
@@ -137,8 +137,11 @@ func getStructName(r *ast.FieldList) string {
t := r.List[0].Type
- if p, _ := t.(*ast.StarExpr); p != nil { // if a pointer receiver => dereference pointer receiver types
- t = p.X
+ switch v := t.(type) {
+ case *ast.StarExpr:
+ t = v.X
+ case *ast.IndexExpr:
+ t = v.X
}
if p, _ := t.(*ast.Ident); p != nil {
diff --git a/vendor/github.com/mgechev/revive/rule/cyclomatic.go b/vendor/github.com/mgechev/revive/rule/cyclomatic.go
index afd41818b..9f6d50043 100644
--- a/vendor/github.com/mgechev/revive/rule/cyclomatic.go
+++ b/vendor/github.com/mgechev/revive/rule/cyclomatic.go
@@ -17,10 +17,16 @@ type CyclomaticRule struct {
sync.Mutex
}
+const defaultMaxCyclomaticComplexity = 10
+
func (r *CyclomaticRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.maxComplexity == 0 {
- checkNumberOfArguments(1, arguments, r.Name())
+ if len(arguments) < 1 {
+ r.maxComplexity = defaultMaxCyclomaticComplexity
+ return
+ }
complexity, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
@@ -28,7 +34,6 @@ func (r *CyclomaticRule) configure(arguments lint.Arguments) {
}
r.maxComplexity = int(complexity)
}
- r.Unlock()
}
// Apply applies the rule to given file.
diff --git a/vendor/github.com/mgechev/revive/rule/defer.go b/vendor/github.com/mgechev/revive/rule/defer.go
index f8224fd4d..f3ea17920 100644
--- a/vendor/github.com/mgechev/revive/rule/defer.go
+++ b/vendor/github.com/mgechev/revive/rule/defer.go
@@ -97,18 +97,21 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
w.newFailure("return in a defer function has no effect", n, 1.0, "logic", "return")
}
case *ast.CallExpr:
- if !w.inADefer && isIdent(n.Fun, "recover") {
+ isCallToRecover := isIdent(n.Fun, "recover")
+ switch {
+ case !w.inADefer && isCallToRecover:
// func fn() { recover() }
//
// confidence is not 1 because recover can be in a function that is deferred elsewhere
w.newFailure("recover must be called inside a deferred function", n, 0.8, "logic", "recover")
- } else if w.inADefer && !w.inAFuncLit && isIdent(n.Fun, "recover") {
+ case w.inADefer && !w.inAFuncLit && isCallToRecover:
// defer helper(recover())
//
// confidence is not truly 1 because this could be in a correctly-deferred func,
// but it is very likely to be a misunderstanding of defer's behavior around arguments.
w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, "logic", "immediate-recover")
}
+
case *ast.DeferStmt:
if isIdent(n.Call.Fun, "recover") {
// defer recover()
@@ -119,7 +122,12 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
}
w.visitSubtree(n.Call.Fun, true, false, false)
for _, a := range n.Call.Args {
- w.visitSubtree(a, true, false, false) // check arguments, they should not contain recover()
+ switch a.(type) {
+ case *ast.FuncLit:
+ continue // too hard to analyze deferred calls with func literals args
+ default:
+ w.visitSubtree(a, true, false, false) // check arguments, they should not contain recover()
+ }
}
if w.inALoop {
@@ -136,6 +144,7 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
w.newFailure("be careful when deferring calls to methods without pointer receiver", fn, 0.8, "bad practice", "method-call")
}
}
+
}
return nil
}
diff --git a/vendor/github.com/mgechev/revive/rule/dot-imports.go b/vendor/github.com/mgechev/revive/rule/dot-imports.go
index 25ff526cb..db78f1957 100644
--- a/vendor/github.com/mgechev/revive/rule/dot-imports.go
+++ b/vendor/github.com/mgechev/revive/rule/dot-imports.go
@@ -39,9 +39,8 @@ type lintImports struct {
}
func (w lintImports) Visit(_ ast.Node) ast.Visitor {
- for i, is := range w.fileAst.Imports {
- _ = i
- if is.Name != nil && is.Name.Name == "." && !w.file.IsTest() {
+ for _, is := range w.fileAst.Imports {
+ if is.Name != nil && is.Name.Name == "." {
w.onFailure(lint.Failure{
Confidence: 1,
Failure: "should not use dot imports",
diff --git a/vendor/github.com/mgechev/revive/rule/early-return.go b/vendor/github.com/mgechev/revive/rule/early-return.go
index ed0fcfae4..90a0acc55 100644
--- a/vendor/github.com/mgechev/revive/rule/early-return.go
+++ b/vendor/github.com/mgechev/revive/rule/early-return.go
@@ -2,9 +2,8 @@ package rule
import (
"fmt"
- "go/ast"
- "go/token"
+ "github.com/mgechev/revive/internal/ifelse"
"github.com/mgechev/revive/lint"
)
@@ -13,16 +12,8 @@ import (
type EarlyReturnRule struct{}
// Apply applies the rule to given file.
-func (*EarlyReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
- var failures []lint.Failure
-
- onFailure := func(failure lint.Failure) {
- failures = append(failures, failure)
- }
-
- w := lintEarlyReturnRule{onFailure: onFailure}
- ast.Walk(w, file.AST)
- return failures
+func (e *EarlyReturnRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ return ifelse.Apply(e, file.AST, ifelse.TargetIf, args)
}
// Name returns the rule name.
@@ -30,147 +21,31 @@ func (*EarlyReturnRule) Name() string {
return "early-return"
}
-type lintEarlyReturnRule struct {
- onFailure func(lint.Failure)
-}
-
-func (w lintEarlyReturnRule) Visit(node ast.Node) ast.Visitor {
- ifStmt, ok := node.(*ast.IfStmt)
- if !ok {
- return w
- }
-
- w.visitIf(ifStmt, false, false)
- return nil
-}
-
-func (w lintEarlyReturnRule) visitIf(ifStmt *ast.IfStmt, hasNonReturnBranch, hasIfInitializer bool) {
- // look for other if-else chains nested inside this if { } block
- ast.Walk(w, ifStmt.Body)
-
- if ifStmt.Else == nil {
- // no else branch
+// CheckIfElse evaluates the rule against an ifelse.Chain.
+func (e *EarlyReturnRule) CheckIfElse(chain ifelse.Chain, args ifelse.Args) (failMsg string) {
+ if !chain.Else.Deviates() {
+ // this rule only applies if the else-block deviates control flow
return
}
- if as, ok := ifStmt.Init.(*ast.AssignStmt); ok && as.Tok == token.DEFINE {
- hasIfInitializer = true
- }
- bodyFlow := w.branchFlow(ifStmt.Body)
-
- switch elseBlock := ifStmt.Else.(type) {
- case *ast.IfStmt:
- if bodyFlow.canFlowIntoNext() {
- hasNonReturnBranch = true
- }
- w.visitIf(elseBlock, hasNonReturnBranch, hasIfInitializer)
-
- case *ast.BlockStmt:
- // look for other if-else chains nested inside this else { } block
- ast.Walk(w, elseBlock)
-
- if hasNonReturnBranch && bodyFlow != branchFlowEmpty {
- // if we de-indent this block then a previous branch
- // might flow into it, affecting program behaviour
- return
- }
-
- if !bodyFlow.canFlowIntoNext() {
- // avoid overlapping with superfluous-else
- return
- }
-
- elseFlow := w.branchFlow(elseBlock)
- if !elseFlow.canFlowIntoNext() {
- failMsg := fmt.Sprintf("if c {%[1]s } else {%[2]s } can be simplified to if !c {%[2]s }%[1]s",
- bodyFlow, elseFlow)
-
- if hasIfInitializer {
- // if statement has a := initializer, so we might need to move the assignment
- // onto its own line in case the body references it
- failMsg += " (move short variable declaration to its own line if necessary)"
- }
-
- w.onFailure(lint.Failure{
- Confidence: 1,
- Node: ifStmt,
- Failure: failMsg,
- })
- }
-
- default:
- panic("invalid node type for else")
- }
-}
-
-type branchFlowKind int
-
-const (
- branchFlowEmpty branchFlowKind = iota
- branchFlowReturn
- branchFlowPanic
- branchFlowContinue
- branchFlowBreak
- branchFlowGoto
- branchFlowRegular
-)
-
-func (w lintEarlyReturnRule) branchFlow(block *ast.BlockStmt) branchFlowKind {
- blockLen := len(block.List)
- if blockLen == 0 {
- return branchFlowEmpty
+ if chain.HasPriorNonDeviating && !chain.If.IsEmpty() {
+ // if we de-indent this block then a previous branch
+ // might flow into it, affecting program behaviour
+ return
}
- switch stmt := block.List[blockLen-1].(type) {
- case *ast.ReturnStmt:
- return branchFlowReturn
- case *ast.BlockStmt:
- return w.branchFlow(stmt)
- case *ast.BranchStmt:
- switch stmt.Tok {
- case token.BREAK:
- return branchFlowBreak
- case token.CONTINUE:
- return branchFlowContinue
- case token.GOTO:
- return branchFlowGoto
- }
- case *ast.ExprStmt:
- if call, ok := stmt.X.(*ast.CallExpr); ok && isIdent(call.Fun, "panic") {
- return branchFlowPanic
- }
+ if chain.If.Deviates() {
+ // avoid overlapping with superfluous-else
+ return
}
- return branchFlowRegular
-}
-
-// Whether this branch's control can flow into the next statement following the if-else chain
-func (k branchFlowKind) canFlowIntoNext() bool {
- switch k {
- case branchFlowReturn, branchFlowPanic, branchFlowContinue, branchFlowBreak, branchFlowGoto:
- return false
- default:
- return true
+ if args.PreserveScope && !chain.AtBlockEnd && (chain.HasInitializer || chain.If.HasDecls) {
+ // avoid increasing variable scope
+ return
}
-}
-func (k branchFlowKind) String() string {
- switch k {
- case branchFlowEmpty:
- return ""
- case branchFlowReturn:
- return " ... return"
- case branchFlowPanic:
- return " ... panic()"
- case branchFlowContinue:
- return " ... continue"
- case branchFlowBreak:
- return " ... break"
- case branchFlowGoto:
- return " ... goto"
- case branchFlowRegular:
- return " ..."
- default:
- panic("invalid kind")
+ if chain.If.IsEmpty() {
+ return fmt.Sprintf("if c { } else { %[1]v } can be simplified to if !c { %[1]v }", chain.Else)
}
+ return fmt.Sprintf("if c { ... } else { %[1]v } can be simplified to if !c { %[1]v } ...", chain.Else)
}
diff --git a/vendor/github.com/mgechev/revive/rule/enforce-map-style.go b/vendor/github.com/mgechev/revive/rule/enforce-map-style.go
new file mode 100644
index 000000000..ae27b654f
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/enforce-map-style.go
@@ -0,0 +1,164 @@
+package rule
+
+import (
+ "fmt"
+ "go/ast"
+ "sync"
+
+ "github.com/mgechev/revive/lint"
+)
+
+type enforceMapStyleType string
+
+const (
+ enforceMapStyleTypeAny enforceMapStyleType = "any"
+ enforceMapStyleTypeMake enforceMapStyleType = "make"
+ enforceMapStyleTypeLiteral enforceMapStyleType = "literal"
+)
+
+func mapStyleFromString(s string) (enforceMapStyleType, error) {
+ switch s {
+ case string(enforceMapStyleTypeAny), "":
+ return enforceMapStyleTypeAny, nil
+ case string(enforceMapStyleTypeMake):
+ return enforceMapStyleTypeMake, nil
+ case string(enforceMapStyleTypeLiteral):
+ return enforceMapStyleTypeLiteral, nil
+ default:
+ return enforceMapStyleTypeAny, fmt.Errorf(
+ "invalid map style: %s (expecting one of %v)",
+ s,
+ []enforceMapStyleType{
+ enforceMapStyleTypeAny,
+ enforceMapStyleTypeMake,
+ enforceMapStyleTypeLiteral,
+ },
+ )
+ }
+}
+
+// EnforceMapStyleRule implements a rule to enforce `make(map[type]type)` over `map[type]type{}`.
+type EnforceMapStyleRule struct {
+ configured bool
+ enforceMapStyle enforceMapStyleType
+ sync.Mutex
+}
+
+func (r *EnforceMapStyleRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ defer r.Unlock()
+
+ if r.configured {
+ return
+ }
+ r.configured = true
+
+ if len(arguments) < 1 {
+ r.enforceMapStyle = enforceMapStyleTypeAny
+ return
+ }
+
+ enforceMapStyle, ok := arguments[0].(string)
+ if !ok {
+ panic(fmt.Sprintf("Invalid argument '%v' for 'enforce-map-style' rule. Expecting string, got %T", arguments[0], arguments[0]))
+ }
+
+ var err error
+ r.enforceMapStyle, err = mapStyleFromString(enforceMapStyle)
+
+ if err != nil {
+ panic(fmt.Sprintf("Invalid argument to the enforce-map-style rule: %v", err))
+ }
+}
+
+// Apply applies the rule to given file.
+func (r *EnforceMapStyleRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
+
+ if r.enforceMapStyle == enforceMapStyleTypeAny {
+ // this linter is not configured
+ return nil
+ }
+
+ var failures []lint.Failure
+
+ astFile := file.AST
+ ast.Inspect(astFile, func(n ast.Node) bool {
+ switch v := n.(type) {
+ case *ast.CompositeLit:
+ if r.enforceMapStyle != enforceMapStyleTypeMake {
+ return true
+ }
+
+ if !r.isMapType(v.Type) {
+ return true
+ }
+
+ if len(v.Elts) > 0 {
+ // not an empty map
+ return true
+ }
+
+ failures = append(failures, lint.Failure{
+ Confidence: 1,
+ Node: v,
+ Category: "style",
+ Failure: "use make(map[type]type) instead of map[type]type{}",
+ })
+ case *ast.CallExpr:
+ if r.enforceMapStyle != enforceMapStyleTypeLiteral {
+ // skip any function calls, even if it's make(map[type]type)
+ // we don't want to report it if literals are not enforced
+ return true
+ }
+
+ ident, ok := v.Fun.(*ast.Ident)
+ if !ok || ident.Name != "make" {
+ return true
+ }
+
+ if len(v.Args) != 1 {
+ // skip make(map[type]type, size) and invalid empty declarations
+ return true
+ }
+
+ if !r.isMapType(v.Args[0]) {
+ // not a map type
+ return true
+ }
+
+ failures = append(failures, lint.Failure{
+ Confidence: 1,
+ Node: v.Args[0],
+ Category: "style",
+ Failure: "use map[type]type{} instead of make(map[type]type)",
+ })
+ }
+ return true
+ })
+
+ return failures
+}
+
+// Name returns the rule name.
+func (r *EnforceMapStyleRule) Name() string {
+ return "enforce-map-style"
+}
+
+func (r *EnforceMapStyleRule) isMapType(v ast.Expr) bool {
+ switch t := v.(type) {
+ case *ast.MapType:
+ return true
+ case *ast.Ident:
+ if t.Obj == nil {
+ return false
+ }
+ typeSpec, ok := t.Obj.Decl.(*ast.TypeSpec)
+ if !ok {
+ return false
+ }
+ return r.isMapType(typeSpec.Type)
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/rule/file-header.go b/vendor/github.com/mgechev/revive/rule/file-header.go
index 76f548f51..a7d69ff2b 100644
--- a/vendor/github.com/mgechev/revive/rule/file-header.go
+++ b/vendor/github.com/mgechev/revive/rule/file-header.go
@@ -21,21 +21,28 @@ var (
func (r *FileHeaderRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.header == "" {
- checkNumberOfArguments(1, arguments, r.Name())
+ if len(arguments) < 1 {
+ return
+ }
+
var ok bool
r.header, ok = arguments[0].(string)
if !ok {
- panic(fmt.Sprintf("invalid argument for \"file-header\" rule: first argument should be a string, got %T", arguments[0]))
+ panic(fmt.Sprintf("invalid argument for \"file-header\" rule: argument should be a string, got %T", arguments[0]))
}
}
- r.Unlock()
}
// Apply applies the rule to given file.
func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
r.configure(arguments)
+ if r.header == "" {
+ return nil
+ }
+
failure := []lint.Failure{
{
Node: file.AST,
diff --git a/vendor/github.com/mgechev/revive/rule/function-length.go b/vendor/github.com/mgechev/revive/rule/function-length.go
index d600d7a2a..f7ab8b98e 100644
--- a/vendor/github.com/mgechev/revive/rule/function-length.go
+++ b/vendor/github.com/mgechev/revive/rule/function-length.go
@@ -19,13 +19,13 @@ type FunctionLength struct {
func (r *FunctionLength) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if !r.configured {
maxStmt, maxLines := r.parseArguments(arguments)
r.maxStmt = int(maxStmt)
r.maxLines = int(maxLines)
r.configured = true
}
- r.Unlock()
}
// Apply applies the rule to given file.
@@ -53,7 +53,14 @@ func (*FunctionLength) Name() string {
return "function-length"
}
+const defaultFuncStmtsLimit = 50
+const defaultFuncLinesLimit = 75
+
func (*FunctionLength) parseArguments(arguments lint.Arguments) (maxStmt, maxLines int64) {
+ if len(arguments) == 0 {
+ return defaultFuncStmtsLimit, defaultFuncLinesLimit
+ }
+
if len(arguments) != 2 {
panic(fmt.Sprintf(`invalid configuration for "function-length" rule, expected 2 arguments but got %d`, len(arguments)))
}
diff --git a/vendor/github.com/mgechev/revive/rule/function-result-limit.go b/vendor/github.com/mgechev/revive/rule/function-result-limit.go
index 5d2b87316..6a0748011 100644
--- a/vendor/github.com/mgechev/revive/rule/function-result-limit.go
+++ b/vendor/github.com/mgechev/revive/rule/function-result-limit.go
@@ -14,11 +14,16 @@ type FunctionResultsLimitRule struct {
sync.Mutex
}
+const defaultResultsLimit = 3
+
func (r *FunctionResultsLimitRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.max == 0 {
- checkNumberOfArguments(1, arguments, r.Name())
-
+ if len(arguments) < 1 {
+ r.max = defaultResultsLimit
+ return
+ }
max, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
panic(fmt.Sprintf(`invalid value passed as return results number to the "function-result-limit" rule; need int64 but got %T`, arguments[0]))
@@ -28,7 +33,6 @@ func (r *FunctionResultsLimitRule) configure(arguments lint.Arguments) {
}
r.max = int(max)
}
- r.Unlock()
}
// Apply applies the rule to given file.
diff --git a/vendor/github.com/mgechev/revive/rule/import-alias-naming.go b/vendor/github.com/mgechev/revive/rule/import-alias-naming.go
new file mode 100644
index 000000000..292392b5d
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/import-alias-naming.go
@@ -0,0 +1,79 @@
+package rule
+
+import (
+ "fmt"
+ "regexp"
+ "sync"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// ImportAliasNamingRule lints import alias naming.
+type ImportAliasNamingRule struct {
+ configured bool
+ namingRuleRegexp *regexp.Regexp
+ sync.Mutex
+}
+
+const defaultNamingRule = "^[a-z][a-z0-9]{0,}$"
+
+var defaultNamingRuleRegexp = regexp.MustCompile(defaultNamingRule)
+
+func (r *ImportAliasNamingRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ defer r.Unlock()
+ if r.configured {
+ return
+ }
+
+ if len(arguments) < 1 {
+ r.namingRuleRegexp = defaultNamingRuleRegexp
+ return
+ }
+
+ namingRule, ok := arguments[0].(string) // Alt. non panicking version
+ if !ok {
+ panic(fmt.Sprintf("Invalid argument '%v' for 'import-alias-naming' rule. Expecting string, got %T", arguments[0], arguments[0]))
+ }
+
+ var err error
+ r.namingRuleRegexp, err = regexp.Compile(namingRule)
+ if err != nil {
+ panic(fmt.Sprintf("Invalid argument to the import-alias-naming rule. Expecting %q to be a valid regular expression, got: %v", namingRule, err))
+ }
+}
+
+// Apply applies the rule to given file.
+func (r *ImportAliasNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
+
+ var failures []lint.Failure
+
+ for _, is := range file.AST.Imports {
+ path := is.Path
+ if path == nil {
+ continue
+ }
+
+ alias := is.Name
+ if alias == nil || alias.Name == "_" {
+ continue
+ }
+
+ if !r.namingRuleRegexp.MatchString(alias.Name) {
+ failures = append(failures, lint.Failure{
+ Confidence: 1,
+ Failure: fmt.Sprintf("import name (%s) must match the regular expression: %s", alias.Name, r.namingRuleRegexp.String()),
+ Node: alias,
+ Category: "imports",
+ })
+ }
+ }
+
+ return failures
+}
+
+// Name returns the rule name.
+func (*ImportAliasNamingRule) Name() string {
+ return "import-alias-naming"
+}
diff --git a/vendor/github.com/mgechev/revive/rule/import-shadowing.go b/vendor/github.com/mgechev/revive/rule/import-shadowing.go
index 2bab704d0..046aeb688 100644
--- a/vendor/github.com/mgechev/revive/rule/import-shadowing.go
+++ b/vendor/github.com/mgechev/revive/rule/import-shadowing.go
@@ -29,6 +29,7 @@ func (*ImportShadowingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fail
failures = append(failures, failure)
},
alreadySeen: map[*ast.Object]struct{}{},
+ skipIdents: map[*ast.Ident]struct{}{},
}
ast.Walk(walker, fileAst)
@@ -62,6 +63,7 @@ type importShadowing struct {
importNames map[string]struct{}
onFailure func(lint.Failure)
alreadySeen map[*ast.Object]struct{}
+ skipIdents map[*ast.Ident]struct{}
}
// Visit visits AST nodes and checks if id nodes (ast.Ident) shadow an import name
@@ -80,6 +82,10 @@ func (w importShadowing) Visit(n ast.Node) ast.Visitor {
*ast.SelectorExpr, // skip analysis of selector expressions (anId.otherId): because if anId shadows an import name, it was already detected, and otherId does not shadows the import name
*ast.StructType: // skip analysis of struct type because struct fields can not shadow an import name
return nil
+ case *ast.FuncDecl:
+ if n.Recv != nil {
+ w.skipIdents[n.Name] = struct{}{}
+ }
case *ast.Ident:
if n == w.packageNameIdent {
return nil // skip the ident corresponding to the package name of this file
@@ -92,11 +98,12 @@ func (w importShadowing) Visit(n ast.Node) ast.Visitor {
_, isImportName := w.importNames[id]
_, alreadySeen := w.alreadySeen[n.Obj]
- if isImportName && !alreadySeen {
+ _, skipIdent := w.skipIdents[n]
+ if isImportName && !alreadySeen && !skipIdent {
w.onFailure(lint.Failure{
Confidence: 1,
Node: n,
- Category: "namming",
+ Category: "naming",
Failure: fmt.Sprintf("The name '%s' shadows an import name", id),
})
diff --git a/vendor/github.com/mgechev/revive/rule/imports-blacklist.go b/vendor/github.com/mgechev/revive/rule/imports-blacklist.go
index 710662815..bb8262cae 100644
--- a/vendor/github.com/mgechev/revive/rule/imports-blacklist.go
+++ b/vendor/github.com/mgechev/revive/rule/imports-blacklist.go
@@ -52,10 +52,6 @@ func (r *ImportsBlacklistRule) Apply(file *lint.File, arguments lint.Arguments)
var failures []lint.Failure
- if file.IsTest() {
- return failures // skip, test file
- }
-
for _, is := range file.AST.Imports {
path := is.Path
if path != nil && r.isBlacklisted(path.Value) {
diff --git a/vendor/github.com/mgechev/revive/rule/indent-error-flow.go b/vendor/github.com/mgechev/revive/rule/indent-error-flow.go
index e455801c4..b80e6486c 100644
--- a/vendor/github.com/mgechev/revive/rule/indent-error-flow.go
+++ b/vendor/github.com/mgechev/revive/rule/indent-error-flow.go
@@ -1,9 +1,7 @@
package rule
import (
- "go/ast"
- "go/token"
-
+ "github.com/mgechev/revive/internal/ifelse"
"github.com/mgechev/revive/lint"
)
@@ -11,16 +9,8 @@ import (
type IndentErrorFlowRule struct{}
// Apply applies the rule to given file.
-func (*IndentErrorFlowRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
- var failures []lint.Failure
-
- onFailure := func(failure lint.Failure) {
- failures = append(failures, failure)
- }
-
- w := lintElse{make(map[*ast.IfStmt]bool), onFailure}
- ast.Walk(w, file.AST)
- return failures
+func (e *IndentErrorFlowRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ return ifelse.Apply(e, file.AST, ifelse.TargetElse, args)
}
// Name returns the rule name.
@@ -28,51 +18,28 @@ func (*IndentErrorFlowRule) Name() string {
return "indent-error-flow"
}
-type lintElse struct {
- ignore map[*ast.IfStmt]bool
- onFailure func(lint.Failure)
-}
-
-func (w lintElse) Visit(node ast.Node) ast.Visitor {
- ifStmt, ok := node.(*ast.IfStmt)
- if !ok || ifStmt.Else == nil {
- return w
- }
- if w.ignore[ifStmt] {
- if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok {
- w.ignore[elseif] = true
- }
- return w
+// CheckIfElse evaluates the rule against an ifelse.Chain.
+func (e *IndentErrorFlowRule) CheckIfElse(chain ifelse.Chain, args ifelse.Args) (failMsg string) {
+ if !chain.If.Deviates() {
+ // this rule only applies if the if-block deviates control flow
+ return
}
- if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok {
- w.ignore[elseif] = true
- return w
- }
- if _, ok := ifStmt.Else.(*ast.BlockStmt); !ok {
- // only care about elses without conditions
- return w
- }
- if len(ifStmt.Body.List) == 0 {
- return w
+
+ if chain.HasPriorNonDeviating {
+ // if we de-indent the "else" block then a previous branch
+ // might flow into it, affecting program behaviour
+ return
}
- shortDecl := false // does the if statement have a ":=" initialization statement?
- if ifStmt.Init != nil {
- if as, ok := ifStmt.Init.(*ast.AssignStmt); ok && as.Tok == token.DEFINE {
- shortDecl = true
- }
+
+ if !chain.If.Returns() {
+ // avoid overlapping with superfluous-else
+ return
}
- lastStmt := ifStmt.Body.List[len(ifStmt.Body.List)-1]
- if _, ok := lastStmt.(*ast.ReturnStmt); ok {
- extra := ""
- if shortDecl {
- extra = " (move short variable declaration to its own line if necessary)"
- }
- w.onFailure(lint.Failure{
- Confidence: 1,
- Node: ifStmt.Else,
- Category: "indent",
- Failure: "if block ends with a return statement, so drop this else and outdent its block" + extra,
- })
+
+ if args.PreserveScope && !chain.AtBlockEnd && (chain.HasInitializer || chain.Else.HasDecls) {
+ // avoid increasing variable scope
+ return
}
- return w
+
+ return "if block ends with a return statement, so drop this else and outdent its block"
}
diff --git a/vendor/github.com/mgechev/revive/rule/line-length-limit.go b/vendor/github.com/mgechev/revive/rule/line-length-limit.go
index 9e512c1c2..1a414f691 100644
--- a/vendor/github.com/mgechev/revive/rule/line-length-limit.go
+++ b/vendor/github.com/mgechev/revive/rule/line-length-limit.go
@@ -18,10 +18,16 @@ type LineLengthLimitRule struct {
sync.Mutex
}
+const defaultLineLengthLimit = 80
+
func (r *LineLengthLimitRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.max == 0 {
- checkNumberOfArguments(1, arguments, r.Name())
+ if len(arguments) < 1 {
+ r.max = defaultLineLengthLimit
+ return
+ }
max, ok := arguments[0].(int64) // Alt. non panicking version
if !ok || max < 0 {
@@ -30,7 +36,6 @@ func (r *LineLengthLimitRule) configure(arguments lint.Arguments) {
r.max = int(max)
}
- r.Unlock()
}
// Apply applies the rule to given file.
diff --git a/vendor/github.com/mgechev/revive/rule/max-public-structs.go b/vendor/github.com/mgechev/revive/rule/max-public-structs.go
index e39f49c69..25be3e676 100644
--- a/vendor/github.com/mgechev/revive/rule/max-public-structs.go
+++ b/vendor/github.com/mgechev/revive/rule/max-public-structs.go
@@ -14,9 +14,17 @@ type MaxPublicStructsRule struct {
sync.Mutex
}
+const defaultMaxPublicStructs = 5
+
func (r *MaxPublicStructsRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.max < 1 {
+ if len(arguments) < 1 {
+ r.max = defaultMaxPublicStructs
+ return
+ }
+
checkNumberOfArguments(1, arguments, r.Name())
max, ok := arguments[0].(int64) // Alt. non panicking version
@@ -25,7 +33,6 @@ func (r *MaxPublicStructsRule) configure(arguments lint.Arguments) {
}
r.max = max
}
- r.Unlock()
}
// Apply applies the rule to given file.
diff --git a/vendor/github.com/mgechev/revive/rule/redundant-import-alias.go b/vendor/github.com/mgechev/revive/rule/redundant-import-alias.go
new file mode 100644
index 000000000..fa5281f24
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/redundant-import-alias.go
@@ -0,0 +1,52 @@
+package rule
+
+import (
+ "fmt"
+ "go/ast"
+ "strings"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// RedundantImportAlias lints given else constructs.
+type RedundantImportAlias struct{}
+
+// Apply applies the rule to given file.
+func (*RedundantImportAlias) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+ var failures []lint.Failure
+
+ for _, imp := range file.AST.Imports {
+ if imp.Name == nil {
+ continue
+ }
+
+ if getImportPackageName(imp) == imp.Name.Name {
+ failures = append(failures, lint.Failure{
+ Confidence: 1,
+ Failure: fmt.Sprintf("Import alias \"%s\" is redundant", imp.Name.Name),
+ Node: imp,
+ Category: "imports",
+ })
+ }
+ }
+
+ return failures
+}
+
+// Name returns the rule name.
+func (*RedundantImportAlias) Name() string {
+ return "redundant-import-alias"
+}
+
+func getImportPackageName(imp *ast.ImportSpec) string {
+ const pathSep = "/"
+ const strDelim = `"`
+
+ path := imp.Path.Value
+ i := strings.LastIndex(path, pathSep)
+ if i == -1 {
+ return strings.Trim(path, strDelim)
+ }
+
+ return strings.Trim(path[i+1:], strDelim)
+}
diff --git a/vendor/github.com/mgechev/revive/rule/string-format.go b/vendor/github.com/mgechev/revive/rule/string-format.go
index 0e30ebf8b..3edd62477 100644
--- a/vendor/github.com/mgechev/revive/rule/string-format.go
+++ b/vendor/github.com/mgechev/revive/rule/string-format.go
@@ -211,10 +211,14 @@ func (lintStringFormatRule) getCallName(call *ast.CallExpr) (callName string, ok
if selector, ok := call.Fun.(*ast.SelectorExpr); ok {
// Scoped function call
scope, ok := selector.X.(*ast.Ident)
- if !ok {
- return "", false
+ if ok {
+ return scope.Name + "." + selector.Sel.Name, true
+ }
+ // Scoped function call inside structure
+ recv, ok := selector.X.(*ast.SelectorExpr)
+ if ok {
+ return recv.Sel.Name + "." + selector.Sel.Name, true
}
- return scope.Name + "." + selector.Sel.Name, true
}
return "", false
diff --git a/vendor/github.com/mgechev/revive/rule/superfluous-else.go b/vendor/github.com/mgechev/revive/rule/superfluous-else.go
index a9e4380c9..1ef67bf1a 100644
--- a/vendor/github.com/mgechev/revive/rule/superfluous-else.go
+++ b/vendor/github.com/mgechev/revive/rule/superfluous-else.go
@@ -2,9 +2,7 @@ package rule
import (
"fmt"
- "go/ast"
- "go/token"
-
+ "github.com/mgechev/revive/internal/ifelse"
"github.com/mgechev/revive/lint"
)
@@ -12,27 +10,8 @@ import (
type SuperfluousElseRule struct{}
// Apply applies the rule to given file.
-func (*SuperfluousElseRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
- var failures []lint.Failure
- onFailure := func(failure lint.Failure) {
- failures = append(failures, failure)
- }
-
- branchingFunctions := map[string]map[string]bool{
- "os": {"Exit": true},
- "log": {
- "Fatal": true,
- "Fatalf": true,
- "Fatalln": true,
- "Panic": true,
- "Panicf": true,
- "Panicln": true,
- },
- }
-
- w := lintSuperfluousElse{make(map[*ast.IfStmt]bool), onFailure, branchingFunctions}
- ast.Walk(w, file.AST)
- return failures
+func (e *SuperfluousElseRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ return ifelse.Apply(e, file.AST, ifelse.TargetElse, args)
}
// Name returns the rule name.
@@ -40,75 +19,28 @@ func (*SuperfluousElseRule) Name() string {
return "superfluous-else"
}
-type lintSuperfluousElse struct {
- ignore map[*ast.IfStmt]bool
- onFailure func(lint.Failure)
- branchingFunctions map[string]map[string]bool
-}
-
-func (w lintSuperfluousElse) Visit(node ast.Node) ast.Visitor {
- ifStmt, ok := node.(*ast.IfStmt)
- if !ok || ifStmt.Else == nil {
- return w
- }
- if w.ignore[ifStmt] {
- if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok {
- w.ignore[elseif] = true
- }
- return w
- }
- if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok {
- w.ignore[elseif] = true
- return w
- }
- if _, ok := ifStmt.Else.(*ast.BlockStmt); !ok {
- // only care about elses without conditions
- return w
- }
- if len(ifStmt.Body.List) == 0 {
- return w
- }
- shortDecl := false // does the if statement have a ":=" initialization statement?
- if ifStmt.Init != nil {
- if as, ok := ifStmt.Init.(*ast.AssignStmt); ok && as.Tok == token.DEFINE {
- shortDecl = true
- }
- }
- extra := ""
- if shortDecl {
- extra = " (move short variable declaration to its own line if necessary)"
+// CheckIfElse evaluates the rule against an ifelse.Chain.
+func (e *SuperfluousElseRule) CheckIfElse(chain ifelse.Chain, args ifelse.Args) (failMsg string) {
+ if !chain.If.Deviates() {
+ // this rule only applies if the if-block deviates control flow
+ return
}
- lastStmt := ifStmt.Body.List[len(ifStmt.Body.List)-1]
- switch stmt := lastStmt.(type) {
- case *ast.BranchStmt:
- tok := stmt.Tok.String()
- if tok != "fallthrough" {
- w.onFailure(newFailure(ifStmt.Else, "if block ends with a "+tok+" statement, so drop this else and outdent its block"+extra))
- }
- case *ast.ExprStmt:
- if ce, ok := stmt.X.(*ast.CallExpr); ok { // it's a function call
- if fc, ok := ce.Fun.(*ast.SelectorExpr); ok {
- if id, ok := fc.X.(*ast.Ident); ok {
- fn := fc.Sel.Name
- pkg := id.Name
- if w.branchingFunctions[pkg][fn] { // it's a call to a branching function
- w.onFailure(
- newFailure(ifStmt.Else, fmt.Sprintf("if block ends with call to %s.%s function, so drop this else and outdent its block%s", pkg, fn, extra)))
- }
- }
- }
- }
+ if chain.HasPriorNonDeviating {
+ // if we de-indent the "else" block then a previous branch
+ // might flow into it, affecting program behaviour
+ return
}
- return w
-}
+ if chain.If.Returns() {
+ // avoid overlapping with indent-error-flow
+ return
+ }
-func newFailure(node ast.Node, msg string) lint.Failure {
- return lint.Failure{
- Confidence: 1,
- Node: node,
- Category: "indent",
- Failure: msg,
+ if args.PreserveScope && !chain.AtBlockEnd && (chain.HasInitializer || chain.Else.HasDecls) {
+ // avoid increasing variable scope
+ return
}
+
+ return fmt.Sprintf("if block ends with %v, so drop this else and outdent its block", chain.If.LongString())
}
diff --git a/vendor/github.com/mgechev/revive/rule/time-equal.go b/vendor/github.com/mgechev/revive/rule/time-equal.go
index 72ecf26fe..3b85e18a8 100644
--- a/vendor/github.com/mgechev/revive/rule/time-equal.go
+++ b/vendor/github.com/mgechev/revive/rule/time-equal.go
@@ -60,9 +60,9 @@ func (l *lintTimeEqual) Visit(node ast.Node) ast.Visitor {
var failure string
switch expr.Op {
case token.EQL:
- failure = fmt.Sprintf("use %s.Equal(%s) instead of %q operator", expr.X, expr.Y, expr.Op)
+ failure = fmt.Sprintf("use %s.Equal(%s) instead of %q operator", gofmt(expr.X), gofmt(expr.Y), expr.Op)
case token.NEQ:
- failure = fmt.Sprintf("use !%s.Equal(%s) instead of %q operator", expr.X, expr.Y, expr.Op)
+ failure = fmt.Sprintf("use !%s.Equal(%s) instead of %q operator", gofmt(expr.X), gofmt(expr.Y), expr.Op)
}
l.onFailure(lint.Failure{
diff --git a/vendor/github.com/mgechev/revive/rule/unchecked-type-assertion.go b/vendor/github.com/mgechev/revive/rule/unchecked-type-assertion.go
new file mode 100644
index 000000000..df27743cb
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/unchecked-type-assertion.go
@@ -0,0 +1,194 @@
+package rule
+
+import (
+ "fmt"
+ "go/ast"
+ "sync"
+
+ "github.com/mgechev/revive/lint"
+)
+
+const (
+ ruleUTAMessagePanic = "type assertion will panic if not matched"
+ ruleUTAMessageIgnored = "type assertion result ignored"
+)
+
+// UncheckedTypeAssertionRule lints missing or ignored `ok`-value in danymic type casts.
+type UncheckedTypeAssertionRule struct {
+ sync.Mutex
+ acceptIgnoredAssertionResult bool
+ configured bool
+}
+
+func (u *UncheckedTypeAssertionRule) configure(arguments lint.Arguments) {
+ u.Lock()
+ defer u.Unlock()
+
+ if len(arguments) == 0 || u.configured {
+ return
+ }
+
+ u.configured = true
+
+ args, ok := arguments[0].(map[string]any)
+ if !ok {
+ panic("Unable to get arguments. Expected object of key-value-pairs.")
+ }
+
+ for k, v := range args {
+ switch k {
+ case "acceptIgnoredAssertionResult":
+ u.acceptIgnoredAssertionResult, ok = v.(bool)
+ if !ok {
+ panic(fmt.Sprintf("Unable to parse argument '%s'. Expected boolean.", k))
+ }
+ default:
+ panic(fmt.Sprintf("Unknown argument: %s", k))
+ }
+ }
+}
+
+// Apply applies the rule to given file.
+func (u *UncheckedTypeAssertionRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ u.configure(args)
+
+ var failures []lint.Failure
+
+ walker := &lintUnchekedTypeAssertion{
+ onFailure: func(failure lint.Failure) {
+ failures = append(failures, failure)
+ },
+ acceptIgnoredTypeAssertionResult: u.acceptIgnoredAssertionResult,
+ }
+
+ ast.Walk(walker, file.AST)
+
+ return failures
+}
+
+// Name returns the rule name.
+func (*UncheckedTypeAssertionRule) Name() string {
+ return "unchecked-type-assertion"
+}
+
+type lintUnchekedTypeAssertion struct {
+ onFailure func(lint.Failure)
+ acceptIgnoredTypeAssertionResult bool
+}
+
+func isIgnored(e ast.Expr) bool {
+ ident, ok := e.(*ast.Ident)
+ if !ok {
+ return false
+ }
+
+ return ident.Name == "_"
+}
+
+func isTypeSwitch(e *ast.TypeAssertExpr) bool {
+ return e.Type == nil
+}
+
+func (w *lintUnchekedTypeAssertion) requireNoTypeAssert(expr ast.Expr) {
+ e, ok := expr.(*ast.TypeAssertExpr)
+ if ok && !isTypeSwitch(e) {
+ w.addFailure(e, ruleUTAMessagePanic)
+ }
+}
+
+func (w *lintUnchekedTypeAssertion) handleIfStmt(n *ast.IfStmt) {
+ ifCondition, ok := n.Cond.(*ast.BinaryExpr)
+ if ok {
+ w.requireNoTypeAssert(ifCondition.X)
+ w.requireNoTypeAssert(ifCondition.Y)
+ }
+}
+
+func (w *lintUnchekedTypeAssertion) requireBinaryExpressionWithoutTypeAssertion(expr ast.Expr) {
+ binaryExpr, ok := expr.(*ast.BinaryExpr)
+ if ok {
+ w.requireNoTypeAssert(binaryExpr.X)
+ w.requireNoTypeAssert(binaryExpr.Y)
+ }
+}
+
+func (w *lintUnchekedTypeAssertion) handleCaseClause(n *ast.CaseClause) {
+ for _, expr := range n.List {
+ w.requireNoTypeAssert(expr)
+ w.requireBinaryExpressionWithoutTypeAssertion(expr)
+ }
+}
+
+func (w *lintUnchekedTypeAssertion) handleSwitch(n *ast.SwitchStmt) {
+ w.requireNoTypeAssert(n.Tag)
+ w.requireBinaryExpressionWithoutTypeAssertion(n.Tag)
+}
+
+func (w *lintUnchekedTypeAssertion) handleAssignment(n *ast.AssignStmt) {
+ if len(n.Rhs) == 0 {
+ return
+ }
+
+ e, ok := n.Rhs[0].(*ast.TypeAssertExpr)
+ if !ok || e == nil {
+ return
+ }
+
+ if isTypeSwitch(e) {
+ return
+ }
+
+ if len(n.Lhs) == 1 {
+ w.addFailure(e, ruleUTAMessagePanic)
+ }
+
+ if !w.acceptIgnoredTypeAssertionResult && len(n.Lhs) == 2 && isIgnored(n.Lhs[1]) {
+ w.addFailure(e, ruleUTAMessageIgnored)
+ }
+}
+
+// handles "return foo(.*bar)" - one of them is enough to fail as golang does not forward the type cast tuples in return statements
+func (w *lintUnchekedTypeAssertion) handleReturn(n *ast.ReturnStmt) {
+ for _, r := range n.Results {
+ w.requireNoTypeAssert(r)
+ }
+}
+
+func (w *lintUnchekedTypeAssertion) handleRange(n *ast.RangeStmt) {
+ w.requireNoTypeAssert(n.X)
+}
+
+func (w *lintUnchekedTypeAssertion) handleChannelSend(n *ast.SendStmt) {
+ w.requireNoTypeAssert(n.Value)
+}
+
+func (w *lintUnchekedTypeAssertion) Visit(node ast.Node) ast.Visitor {
+ switch n := node.(type) {
+ case *ast.RangeStmt:
+ w.handleRange(n)
+ case *ast.SwitchStmt:
+ w.handleSwitch(n)
+ case *ast.ReturnStmt:
+ w.handleReturn(n)
+ case *ast.AssignStmt:
+ w.handleAssignment(n)
+ case *ast.IfStmt:
+ w.handleIfStmt(n)
+ case *ast.CaseClause:
+ w.handleCaseClause(n)
+ case *ast.SendStmt:
+ w.handleChannelSend(n)
+ }
+
+ return w
+}
+
+func (w *lintUnchekedTypeAssertion) addFailure(n *ast.TypeAssertExpr, why string) {
+ s := fmt.Sprintf("type cast result is unchecked in %v - %s", gofmt(n), why)
+ w.onFailure(lint.Failure{
+ Category: "bad practice",
+ Confidence: 1,
+ Node: n,
+ Failure: s,
+ })
+}
diff --git a/vendor/github.com/mgechev/revive/rule/unused-param.go b/vendor/github.com/mgechev/revive/rule/unused-param.go
index ab3da453e..df6cd9af0 100644
--- a/vendor/github.com/mgechev/revive/rule/unused-param.go
+++ b/vendor/github.com/mgechev/revive/rule/unused-param.go
@@ -3,22 +3,72 @@ package rule
import (
"fmt"
"go/ast"
+ "regexp"
+ "sync"
"github.com/mgechev/revive/lint"
)
// UnusedParamRule lints unused params in functions.
-type UnusedParamRule struct{}
+type UnusedParamRule struct {
+ configured bool
+ // regex to check if some name is valid for unused parameter, "^_$" by default
+ allowRegex *regexp.Regexp
+ failureMsg string
+ sync.Mutex
+}
+
+func (r *UnusedParamRule) configure(args lint.Arguments) {
+ r.Lock()
+ defer r.Unlock()
+
+ if r.configured {
+ return
+ }
+ r.configured = true
+
+ // while by default args is an array, i think it's good to provide structures inside it by default, not arrays or primitives
+ // it's more compatible to JSON nature of configurations
+ var allowedRegexStr string
+ if len(args) == 0 {
+ allowedRegexStr = "^_$"
+ r.failureMsg = "parameter '%s' seems to be unused, consider removing or renaming it as _"
+ } else {
+ // Arguments = [{}]
+ options := args[0].(map[string]interface{})
+ // Arguments = [{allowedRegex="^_"}]
+
+ if allowedRegexParam, ok := options["allowRegex"]; ok {
+ allowedRegexStr, ok = allowedRegexParam.(string)
+ if !ok {
+ panic(fmt.Errorf("error configuring %s rule: allowedRegex is not string but [%T]", r.Name(), allowedRegexParam))
+ }
+ }
+ }
+ var err error
+ r.allowRegex, err = regexp.Compile(allowedRegexStr)
+ if err != nil {
+ panic(fmt.Errorf("error configuring %s rule: allowedRegex is not valid regex [%s]: %v", r.Name(), allowedRegexStr, err))
+ }
+
+ if r.failureMsg == "" {
+ r.failureMsg = "parameter '%s' seems to be unused, consider removing or renaming it to match " + r.allowRegex.String()
+ }
+}
// Apply applies the rule to given file.
-func (*UnusedParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (r *UnusedParamRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ r.configure(args)
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
-
- w := lintUnusedParamRule{onFailure: onFailure}
+ w := lintUnusedParamRule{
+ onFailure: onFailure,
+ allowRegex: r.allowRegex,
+ failureMsg: r.failureMsg,
+ }
ast.Walk(w, file.AST)
@@ -31,7 +81,9 @@ func (*UnusedParamRule) Name() string {
}
type lintUnusedParamRule struct {
- onFailure func(lint.Failure)
+ onFailure func(lint.Failure)
+ allowRegex *regexp.Regexp
+ failureMsg string
}
func (w lintUnusedParamRule) Visit(node ast.Node) ast.Visitor {
@@ -65,12 +117,15 @@ func (w lintUnusedParamRule) Visit(node ast.Node) ast.Visitor {
for _, p := range n.Type.Params.List {
for _, n := range p.Names {
+ if w.allowRegex.FindStringIndex(n.Name) != nil {
+ continue
+ }
if params[n.Obj] {
w.onFailure(lint.Failure{
Confidence: 1,
Node: n,
Category: "bad practice",
- Failure: fmt.Sprintf("parameter '%s' seems to be unused, consider removing or renaming it as _", n.Name),
+ Failure: fmt.Sprintf(w.failureMsg, n.Name),
})
}
}
diff --git a/vendor/github.com/mgechev/revive/rule/unused-receiver.go b/vendor/github.com/mgechev/revive/rule/unused-receiver.go
index 2289a517e..488572b7b 100644
--- a/vendor/github.com/mgechev/revive/rule/unused-receiver.go
+++ b/vendor/github.com/mgechev/revive/rule/unused-receiver.go
@@ -3,22 +3,72 @@ package rule
import (
"fmt"
"go/ast"
+ "regexp"
+ "sync"
"github.com/mgechev/revive/lint"
)
// UnusedReceiverRule lints unused params in functions.
-type UnusedReceiverRule struct{}
+type UnusedReceiverRule struct {
+ configured bool
+ // regex to check if some name is valid for unused parameter, "^_$" by default
+ allowRegex *regexp.Regexp
+ failureMsg string
+ sync.Mutex
+}
+
+func (r *UnusedReceiverRule) configure(args lint.Arguments) {
+ r.Lock()
+ defer r.Unlock()
+
+ if r.configured {
+ return
+ }
+ r.configured = true
+
+ // while by default args is an array, i think it's good to provide structures inside it by default, not arrays or primitives
+ // it's more compatible to JSON nature of configurations
+ var allowedRegexStr string
+ if len(args) == 0 {
+ allowedRegexStr = "^_$"
+ r.failureMsg = "method receiver '%s' is not referenced in method's body, consider removing or renaming it as _"
+ } else {
+ // Arguments = [{}]
+ options := args[0].(map[string]interface{})
+ // Arguments = [{allowedRegex="^_"}]
+
+ if allowedRegexParam, ok := options["allowRegex"]; ok {
+ allowedRegexStr, ok = allowedRegexParam.(string)
+ if !ok {
+ panic(fmt.Errorf("error configuring [unused-receiver] rule: allowedRegex is not string but [%T]", allowedRegexParam))
+ }
+ }
+ }
+ var err error
+ r.allowRegex, err = regexp.Compile(allowedRegexStr)
+ if err != nil {
+ panic(fmt.Errorf("error configuring [unused-receiver] rule: allowedRegex is not valid regex [%s]: %v", allowedRegexStr, err))
+ }
+ if r.failureMsg == "" {
+ r.failureMsg = "method receiver '%s' is not referenced in method's body, consider removing or renaming it to match " + r.allowRegex.String()
+ }
+}
// Apply applies the rule to given file.
-func (*UnusedReceiverRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (r *UnusedReceiverRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ r.configure(args)
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
- w := lintUnusedReceiverRule{onFailure: onFailure}
+ w := lintUnusedReceiverRule{
+ onFailure: onFailure,
+ allowRegex: r.allowRegex,
+ failureMsg: r.failureMsg,
+ }
ast.Walk(w, file.AST)
@@ -31,7 +81,9 @@ func (*UnusedReceiverRule) Name() string {
}
type lintUnusedReceiverRule struct {
- onFailure func(lint.Failure)
+ onFailure func(lint.Failure)
+ allowRegex *regexp.Regexp
+ failureMsg string
}
func (w lintUnusedReceiverRule) Visit(node ast.Node) ast.Visitor {
@@ -51,6 +103,10 @@ func (w lintUnusedReceiverRule) Visit(node ast.Node) ast.Visitor {
return nil // the receiver is already named _
}
+ if w.allowRegex != nil && w.allowRegex.FindStringIndex(recID.Name) != nil {
+ return nil
+ }
+
// inspect the func body looking for references to the receiver id
fselect := func(n ast.Node) bool {
ident, isAnID := n.(*ast.Ident)
@@ -67,7 +123,7 @@ func (w lintUnusedReceiverRule) Visit(node ast.Node) ast.Visitor {
Confidence: 1,
Node: recID,
Category: "bad practice",
- Failure: fmt.Sprintf("method receiver '%s' is not referenced in method's body, consider removing or renaming it as _", recID.Name),
+ Failure: fmt.Sprintf(w.failureMsg, recID.Name),
})
return nil // full method body already inspected
diff --git a/vendor/github.com/mgechev/revive/rule/var-naming.go b/vendor/github.com/mgechev/revive/rule/var-naming.go
index fa4a18864..286ff9d75 100644
--- a/vendor/github.com/mgechev/revive/rule/var-naming.go
+++ b/vendor/github.com/mgechev/revive/rule/var-naming.go
@@ -13,27 +13,50 @@ import (
var anyCapsRE = regexp.MustCompile(`[A-Z]`)
+// regexp for constant names like `SOME_CONST`, `SOME_CONST_2`, `X123_3`, `_SOME_PRIVATE_CONST` (#851, #865)
+var upperCaseConstRE = regexp.MustCompile(`^_?[A-Z][A-Z\d]*(_[A-Z\d]+)*$`)
+
// VarNamingRule lints given else constructs.
type VarNamingRule struct {
- configured bool
- whitelist []string
- blacklist []string
+ configured bool
+ whitelist []string
+ blacklist []string
+ upperCaseConst bool // if true - allows to use UPPER_SOME_NAMES for constants
sync.Mutex
}
func (r *VarNamingRule) configure(arguments lint.Arguments) {
r.Lock()
- if !r.configured {
- if len(arguments) >= 1 {
- r.whitelist = getList(arguments[0], "whitelist")
- }
+ defer r.Unlock()
+ if r.configured {
+ return
+ }
+
+ r.configured = true
+ if len(arguments) >= 1 {
+ r.whitelist = getList(arguments[0], "whitelist")
+ }
- if len(arguments) >= 2 {
- r.blacklist = getList(arguments[1], "blacklist")
+ if len(arguments) >= 2 {
+ r.blacklist = getList(arguments[1], "blacklist")
+ }
+
+ if len(arguments) >= 3 {
+ // not pretty code because should keep compatibility with TOML (no mixed array types) and new map parameters
+ thirdArgument := arguments[2]
+ asSlice, ok := thirdArgument.([]interface{})
+ if !ok {
+ panic(fmt.Sprintf("Invalid third argument to the var-naming rule. Expecting a %s of type slice, got %T", "options", arguments[2]))
+ }
+ if len(asSlice) != 1 {
+ panic(fmt.Sprintf("Invalid third argument to the var-naming rule. Expecting a %s of type slice, of len==1, but %d", "options", len(asSlice)))
}
- r.configured = true
+ args, ok := asSlice[0].(map[string]interface{})
+ if !ok {
+ panic(fmt.Sprintf("Invalid third argument to the var-naming rule. Expecting a %s of type slice, of len==1, with map, but %T", "options", asSlice[0]))
+ }
+ r.upperCaseConst = fmt.Sprint(args["upperCaseConst"]) == "true"
}
- r.Unlock()
}
// Apply applies the rule to given file.
@@ -52,6 +75,7 @@ func (r *VarNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
+ upperCaseConst: r.upperCaseConst,
}
// Package names need slightly different handling than other names.
@@ -82,18 +106,18 @@ func (*VarNamingRule) Name() string {
return "var-naming"
}
-func checkList(fl *ast.FieldList, thing string, w *lintNames) {
+func (w *lintNames) checkList(fl *ast.FieldList, thing string) {
if fl == nil {
return
}
for _, f := range fl.List {
for _, id := range f.Names {
- check(id, thing, w)
+ w.check(id, thing)
}
}
}
-func check(id *ast.Ident, thing string, w *lintNames) {
+func (w *lintNames) check(id *ast.Ident, thing string) {
if id.Name == "_" {
return
}
@@ -101,6 +125,12 @@ func check(id *ast.Ident, thing string, w *lintNames) {
return
}
+ // #851 upperCaseConst support
+ // if it's const
+ if thing == token.CONST.String() && w.upperCaseConst && upperCaseConstRE.Match([]byte(id.Name)) {
+ return
+ }
+
// Handle two common styles from other languages that don't belong in Go.
if len(id.Name) >= 5 && allCapsRE.MatchString(id.Name) && strings.Contains(id.Name, "_") {
w.onFailure(lint.Failure{
@@ -111,15 +141,6 @@ func check(id *ast.Ident, thing string, w *lintNames) {
})
return
}
- if len(id.Name) > 2 && id.Name[0] == 'k' && id.Name[1] >= 'A' && id.Name[1] <= 'Z' {
- should := string(id.Name[1]+'a'-'A') + id.Name[2:]
- w.onFailure(lint.Failure{
- Failure: fmt.Sprintf("don't use leading k in Go names; %s %s should be %s", thing, id.Name, should),
- Confidence: 0.8,
- Node: id,
- Category: "naming",
- })
- }
should := lint.Name(id.Name, w.whitelist, w.blacklist)
if id.Name == should {
@@ -144,11 +165,12 @@ func check(id *ast.Ident, thing string, w *lintNames) {
}
type lintNames struct {
- file *lint.File
- fileAst *ast.File
- onFailure func(lint.Failure)
- whitelist []string
- blacklist []string
+ file *lint.File
+ fileAst *ast.File
+ onFailure func(lint.Failure)
+ whitelist []string
+ blacklist []string
+ upperCaseConst bool
}
func (w *lintNames) Visit(n ast.Node) ast.Visitor {
@@ -159,7 +181,7 @@ func (w *lintNames) Visit(n ast.Node) ast.Visitor {
}
for _, exp := range v.Lhs {
if id, ok := exp.(*ast.Ident); ok {
- check(id, "var", w)
+ w.check(id, "var")
}
}
case *ast.FuncDecl:
@@ -181,31 +203,24 @@ func (w *lintNames) Visit(n ast.Node) ast.Visitor {
// not exported in the Go API.
// See https://github.com/golang/lint/issues/144.
if ast.IsExported(v.Name.Name) || !isCgoExported(v) {
- check(v.Name, thing, w)
+ w.check(v.Name, thing)
}
- checkList(v.Type.Params, thing+" parameter", w)
- checkList(v.Type.Results, thing+" result", w)
+ w.checkList(v.Type.Params, thing+" parameter")
+ w.checkList(v.Type.Results, thing+" result")
case *ast.GenDecl:
if v.Tok == token.IMPORT {
return w
}
- var thing string
- switch v.Tok {
- case token.CONST:
- thing = "const"
- case token.TYPE:
- thing = "type"
- case token.VAR:
- thing = "var"
- }
+
+ thing := v.Tok.String()
for _, spec := range v.Specs {
switch s := spec.(type) {
case *ast.TypeSpec:
- check(s.Name, thing, w)
+ w.check(s.Name, thing)
case *ast.ValueSpec:
for _, id := range s.Names {
- check(id, thing, w)
+ w.check(id, thing)
}
}
}
@@ -217,23 +232,23 @@ func (w *lintNames) Visit(n ast.Node) ast.Visitor {
if !ok { // might be an embedded interface name
continue
}
- checkList(ft.Params, "interface method parameter", w)
- checkList(ft.Results, "interface method result", w)
+ w.checkList(ft.Params, "interface method parameter")
+ w.checkList(ft.Results, "interface method result")
}
case *ast.RangeStmt:
if v.Tok == token.ASSIGN {
return w
}
if id, ok := v.Key.(*ast.Ident); ok {
- check(id, "range var", w)
+ w.check(id, "range var")
}
if id, ok := v.Value.(*ast.Ident); ok {
- check(id, "range var", w)
+ w.check(id, "range var")
}
case *ast.StructType:
for _, f := range v.Fields.List {
for _, id := range f.Names {
- check(id, "struct field", w)
+ w.check(id, "struct field")
}
}
}