aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mgechev/revive/internal
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2023-12-05 15:10:03 +0100
committerTaras Madan <tarasmadan@google.com>2023-12-06 11:31:44 +0000
commit2ab72b4feef2c97f22f90cfbf9e45a6cfcd08bda (patch)
treea6d19b94b6399fcc00a6cfa430885cd349dd1533 /vendor/github.com/mgechev/revive/internal
parente08e8f492d31d672cc245944c185f8aadf2ee695 (diff)
vendor: updates
Diffstat (limited to 'vendor/github.com/mgechev/revive/internal')
-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
8 files changed, 402 insertions, 0 deletions
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")
+ }
+}