diff options
| author | Taras Madan <tarasmadan@google.com> | 2023-12-05 15:10:03 +0100 |
|---|---|---|
| committer | Taras Madan <tarasmadan@google.com> | 2023-12-06 11:31:44 +0000 |
| commit | 2ab72b4feef2c97f22f90cfbf9e45a6cfcd08bda (patch) | |
| tree | a6d19b94b6399fcc00a6cfa430885cd349dd1533 /vendor/github.com/mgechev/revive/internal | |
| parent | e08e8f492d31d672cc245944c185f8aadf2ee695 (diff) | |
vendor: updates
Diffstat (limited to 'vendor/github.com/mgechev/revive/internal')
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") + } +} |
