aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/uudashr
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-07-04 11:12:55 +0200
committerDmitry Vyukov <dvyukov@google.com>2020-07-04 15:05:30 +0200
commitc7d7f10bdff703e4a3c0414e8a33d4e45c91eb35 (patch)
tree0dff0ee1f98dbfa3ad8776112053a450d176592b /vendor/github.com/uudashr
parent9573094ce235bd9afe88f5da27a47dd6bcc1e13b (diff)
go.mod: vendor golangci-lint
Diffstat (limited to 'vendor/github.com/uudashr')
-rw-r--r--vendor/github.com/uudashr/gocognit/LICENSE21
-rw-r--r--vendor/github.com/uudashr/gocognit/README.md185
-rw-r--r--vendor/github.com/uudashr/gocognit/go.mod3
-rw-r--r--vendor/github.com/uudashr/gocognit/go.sum0
-rw-r--r--vendor/github.com/uudashr/gocognit/gocognit.go313
5 files changed, 522 insertions, 0 deletions
diff --git a/vendor/github.com/uudashr/gocognit/LICENSE b/vendor/github.com/uudashr/gocognit/LICENSE
new file mode 100644
index 000000000..75d4b9c98
--- /dev/null
+++ b/vendor/github.com/uudashr/gocognit/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Nuruddin Ashr
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/uudashr/gocognit/README.md b/vendor/github.com/uudashr/gocognit/README.md
new file mode 100644
index 000000000..4a8846907
--- /dev/null
+++ b/vendor/github.com/uudashr/gocognit/README.md
@@ -0,0 +1,185 @@
+[![GoDoc](https://godoc.org/github.com/uudashr/gocognit?status.svg)](https://godoc.org/github.com/uudashr/gocognit)
+# Gocognit
+Gocognit calculates cognitive complexities of functions in Go source code. A measurement of how hard does the code is intuitively to understand.
+
+## Understanding the complexity
+
+Given code using `if` statement,
+```go
+func GetWords(number int) string {
+ if number == 1 { // +1
+ return "one"
+ } else if number == 2 { // +1
+ return "a couple"
+ } else if number == 3 { // +1
+ return "a few"
+ } else { // +1
+ return "lots"
+ }
+} // Cognitive complexity = 4
+```
+
+Above code can be refactored using `switch` statement,
+```go
+func GetWords(number int) string {
+ switch number { // +1
+ case 1:
+ return "one"
+ case 2:
+ return "a couple"
+ case 3:
+ return "a few"
+ default:
+ return "lots"
+ }
+} // Cognitive complexity = 1
+```
+
+As you see above codes are the same, but the second code are easier to understand, that is why the cognitive complexity score are lower compare to the first one.
+
+## Comparison with cyclometic complexity
+
+### Example 1
+#### Cyclometic complexity
+```go
+func GetWords(number int) string { // +1
+ switch number {
+ case 1: // +1
+ return "one"
+ case 2: // +1
+ return "a couple"
+ case 3: // +1
+ return "a few"
+ default:
+ return "lots"
+ }
+} // Cyclomatic complexity = 4
+```
+
+#### Cognitive complexity
+```go
+func GetWords(number int) string {
+ switch number { // +1
+ case 1:
+ return "one"
+ case 2:
+ return "a couple"
+ case 3:
+ return "a few"
+ default:
+ return "lots"
+ }
+} // Cognitive complexity = 1
+```
+
+Cognitive complexity give lower score compare to cyclomatic complexity.
+
+### Example 2
+#### Cyclomatic complexity
+```go
+func SumOfPrimes(max int) int { // +1
+ var total int
+
+OUT:
+ for i := 1; i < max; i++ { // +1
+ for j := 2; j < i; j++ { // +1
+ if i%j == 0 { // +1
+ continue OUT
+ }
+ }
+ total += i
+ }
+
+ return total
+} // Cyclomatic complexity = 4
+```
+
+#### Cognitive complexity
+```go
+func SumOfPrimes(max int) int {
+ var total int
+
+OUT:
+ for i := 1; i < max; i++ { // +1
+ for j := 2; j < i; j++ { // +2 (nesting = 1)
+ if i%j == 0 { // +3 (nesting = 2)
+ continue OUT // +1
+ }
+ }
+ total += i
+ }
+
+ return total
+} // Cognitive complexity = 7
+```
+
+Cognitive complexity give higher score compare to cyclomatic complexity.
+
+## Rules
+
+The cognitive complexity of a function is calculated according to the
+following rules:
+> Note: these rules are specific for Go, please see the [original whitepaper](https://www.sonarsource.com/docs/CognitiveComplexity.pdf) for more complete reference.
+
+### Increments
+There is an increment for each of the following:
+1. `if`, `else if`, `else`
+2. `switch`, `select`
+3. `for`
+4. `goto` LABEL, `break` LABEL, `continue` LABEL
+5. sequence of binary logical operators
+6. each method in a recursion cycle
+
+### Nesting level
+The following structures increment the nesting level:
+1. `if`, `else if`, `else`
+2. `switch`, `select`
+3. `for`
+4. function literal or lambda
+
+### Nesting increments
+The following structures receive a nesting increment commensurate with their nested depth inside nesting structures:
+1. `if`
+2. `switch`, `select`
+3. `for`
+
+## Installation
+```
+$ go get github.com/uudashr/gocognit/cmd/gocognit
+```
+
+## Usage
+
+```
+$ gocognit
+Calculate cognitive complexities of Go functions.
+Usage:
+ gocognit [flags] <Go file or directory> ...
+Flags:
+ -over N show functions with complexity > N only and
+ return exit code 1 if the set is non-empty
+ -top N show the top N most complex functions only
+ -avg show the average complexity over all functions,
+ not depending on whether -over or -top are set
+The output fields for each line are:
+<complexity> <package> <function> <file:row:column>
+```
+
+Examples:
+
+```
+$ gocognit .
+$ gocognit main.go
+$ gocognit -top 10 src/
+$ gocognit -over 25 docker
+$ gocognit -avg .
+```
+
+The output fields for each line are:
+```
+<complexity> <package> <function> <file:row:column>
+```
+
+## Related project
+- [Gocyclo](https://github.com/fzipp/gocyclo) where the code are based on.
+- [Cognitive Complexity: A new way of measuring understandability](https://www.sonarsource.com/docs/CognitiveComplexity.pdf) white paper by G. Ann Campbell. \ No newline at end of file
diff --git a/vendor/github.com/uudashr/gocognit/go.mod b/vendor/github.com/uudashr/gocognit/go.mod
new file mode 100644
index 000000000..1a68d3880
--- /dev/null
+++ b/vendor/github.com/uudashr/gocognit/go.mod
@@ -0,0 +1,3 @@
+module github.com/uudashr/gocognit
+
+go 1.13
diff --git a/vendor/github.com/uudashr/gocognit/go.sum b/vendor/github.com/uudashr/gocognit/go.sum
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/github.com/uudashr/gocognit/go.sum
diff --git a/vendor/github.com/uudashr/gocognit/gocognit.go b/vendor/github.com/uudashr/gocognit/gocognit.go
new file mode 100644
index 000000000..11d5ee527
--- /dev/null
+++ b/vendor/github.com/uudashr/gocognit/gocognit.go
@@ -0,0 +1,313 @@
+package gocognit
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+)
+
+// Stat is statistic of the complexity.
+type Stat struct {
+ PkgName string
+ FuncName string
+ Complexity int
+ Pos token.Position
+}
+
+func (s Stat) String() string {
+ return fmt.Sprintf("%d %s %s %s", s.Complexity, s.PkgName, s.FuncName, s.Pos)
+}
+
+// ComplexityStats builds the complexity statistics.
+func ComplexityStats(f *ast.File, fset *token.FileSet, stats []Stat) []Stat {
+ for _, decl := range f.Decls {
+ if fn, ok := decl.(*ast.FuncDecl); ok {
+ stats = append(stats, Stat{
+ PkgName: f.Name.Name,
+ FuncName: funcName(fn),
+ Complexity: Complexity(fn),
+ Pos: fset.Position(fn.Pos()),
+ })
+ }
+ }
+ return stats
+}
+
+// funcName returns the name representation of a function or method:
+// "(Type).Name" for methods or simply "Name" for functions.
+func funcName(fn *ast.FuncDecl) string {
+ if fn.Recv != nil {
+ if fn.Recv.NumFields() > 0 {
+ typ := fn.Recv.List[0].Type
+ return fmt.Sprintf("(%s).%s", recvString(typ), fn.Name)
+ }
+ }
+ return fn.Name.Name
+}
+
+// recvString returns a string representation of recv of the
+// form "T", "*T", or "BADRECV" (if not a proper receiver type).
+func recvString(recv ast.Expr) string {
+ switch t := recv.(type) {
+ case *ast.Ident:
+ return t.Name
+ case *ast.StarExpr:
+ return "*" + recvString(t.X)
+ }
+ return "BADRECV"
+}
+
+// Complexity calculates the cognitive complexity of a function.
+func Complexity(fn *ast.FuncDecl) int {
+ v := complexityVisitor{
+ name: fn.Name,
+ }
+ ast.Walk(&v, fn)
+ return v.complexity
+}
+
+type complexityVisitor struct {
+ name *ast.Ident
+ complexity int
+ nesting int
+ elseNodes map[ast.Node]bool
+ calculatedExprs map[ast.Expr]bool
+}
+
+func (v *complexityVisitor) incNesting() {
+ v.nesting++
+}
+
+func (v *complexityVisitor) decNesting() {
+ v.nesting--
+}
+
+func (v *complexityVisitor) incComplexity() {
+ v.complexity++
+}
+
+func (v *complexityVisitor) nestIncComplexity() {
+ v.complexity += (v.nesting + 1)
+}
+
+func (v *complexityVisitor) markAsElseNode(n ast.Node) {
+ if v.elseNodes == nil {
+ v.elseNodes = make(map[ast.Node]bool)
+ }
+
+ v.elseNodes[n] = true
+}
+
+func (v *complexityVisitor) markedAsElseNode(n ast.Node) bool {
+ if v.elseNodes == nil {
+ return false
+ }
+
+ return v.elseNodes[n]
+}
+
+func (v *complexityVisitor) markCalculated(e ast.Expr) {
+ if v.calculatedExprs == nil {
+ v.calculatedExprs = make(map[ast.Expr]bool)
+ }
+
+ v.calculatedExprs[e] = true
+}
+
+func (v *complexityVisitor) isCalculated(e ast.Expr) bool {
+ if v.calculatedExprs == nil {
+ return false
+ }
+
+ return v.calculatedExprs[e]
+}
+
+// Visit implements the ast.Visitor interface.
+func (v *complexityVisitor) Visit(n ast.Node) ast.Visitor {
+ switch n := n.(type) {
+ case *ast.IfStmt:
+ return v.visitIfStmt(n)
+ case *ast.SwitchStmt:
+ return v.visitSwitchStmt(n)
+ case *ast.SelectStmt:
+ return v.visitSelectStmt(n)
+ case *ast.ForStmt:
+ return v.visitForStmt(n)
+ case *ast.RangeStmt:
+ return v.visitRangeStmt(n)
+ case *ast.FuncLit:
+ return v.visitFuncLit(n)
+ case *ast.BranchStmt:
+ return v.visitBranchStmt(n)
+ case *ast.BinaryExpr:
+ return v.visitBinaryExpr(n)
+ case *ast.CallExpr:
+ return v.visitCallExpr(n)
+ }
+ return v
+}
+
+func (v *complexityVisitor) visitIfStmt(n *ast.IfStmt) ast.Visitor {
+ v.incIfComplexity(n)
+
+ if n.Init != nil {
+ ast.Walk(v, n.Init)
+ }
+
+ ast.Walk(v, n.Cond)
+
+ v.incNesting()
+ ast.Walk(v, n.Body)
+ v.decNesting()
+
+ if _, ok := n.Else.(*ast.BlockStmt); ok {
+ v.incComplexity()
+
+ v.incNesting()
+ ast.Walk(v, n.Else)
+ v.decNesting()
+ } else if _, ok := n.Else.(*ast.IfStmt); ok {
+ v.markAsElseNode(n.Else)
+ ast.Walk(v, n.Else)
+ }
+ return nil
+}
+
+func (v *complexityVisitor) visitSwitchStmt(n *ast.SwitchStmt) ast.Visitor {
+ v.nestIncComplexity()
+
+ if n.Init != nil {
+ ast.Walk(v, n.Init)
+ }
+
+ if n.Tag != nil {
+ ast.Walk(v, n.Tag)
+ }
+
+ v.incNesting()
+ ast.Walk(v, n.Body)
+ v.decNesting()
+ return nil
+}
+
+func (v *complexityVisitor) visitSelectStmt(n *ast.SelectStmt) ast.Visitor {
+ v.nestIncComplexity()
+
+ v.incNesting()
+ ast.Walk(v, n.Body)
+ v.decNesting()
+ return nil
+}
+
+func (v *complexityVisitor) visitForStmt(n *ast.ForStmt) ast.Visitor {
+ v.nestIncComplexity()
+
+ if n.Init != nil {
+ ast.Walk(v, n.Init)
+ }
+
+ if n.Cond != nil {
+ ast.Walk(v, n.Cond)
+ }
+
+ if n.Post != nil {
+ ast.Walk(v, n.Post)
+ }
+
+ v.incNesting()
+ ast.Walk(v, n.Body)
+ v.decNesting()
+ return nil
+}
+
+func (v *complexityVisitor) visitRangeStmt(n *ast.RangeStmt) ast.Visitor {
+ v.nestIncComplexity()
+
+ if n.Key != nil {
+ ast.Walk(v, n.Key)
+ }
+
+ if n.Value != nil {
+ ast.Walk(v, n.Value)
+ }
+
+ ast.Walk(v, n.X)
+
+ v.incNesting()
+ ast.Walk(v, n.Body)
+ v.decNesting()
+ return nil
+}
+
+func (v *complexityVisitor) visitFuncLit(n *ast.FuncLit) ast.Visitor {
+ ast.Walk(v, n.Type)
+
+ v.incNesting()
+ ast.Walk(v, n.Body)
+ v.decNesting()
+ return nil
+}
+
+func (v *complexityVisitor) visitBranchStmt(n *ast.BranchStmt) ast.Visitor {
+ if n.Label != nil {
+ v.incComplexity()
+ }
+ return v
+}
+
+func (v *complexityVisitor) visitBinaryExpr(n *ast.BinaryExpr) ast.Visitor {
+ if (n.Op == token.LAND || n.Op == token.LOR) && !v.isCalculated(n) {
+ ops := v.collectBinaryOps(n)
+
+ var lastOp token.Token
+ for _, op := range ops {
+ if lastOp != op {
+ v.incComplexity()
+ lastOp = op
+ }
+ }
+ }
+ return v
+}
+
+func (v *complexityVisitor) visitCallExpr(n *ast.CallExpr) ast.Visitor {
+ if name, ok := n.Fun.(*ast.Ident); ok {
+ if name.Obj == v.name.Obj && name.Name == v.name.Name {
+ v.incComplexity()
+ }
+ }
+ return v
+}
+
+func (v *complexityVisitor) collectBinaryOps(exp ast.Expr) []token.Token {
+ v.markCalculated(exp)
+ switch exp := exp.(type) {
+ case *ast.BinaryExpr:
+ return mergeBinaryOps(v.collectBinaryOps(exp.X), exp.Op, v.collectBinaryOps(exp.Y))
+ case *ast.ParenExpr:
+ // interest only on what inside paranthese
+ return v.collectBinaryOps(exp.X)
+ default:
+ return []token.Token{}
+ }
+}
+
+func (v *complexityVisitor) incIfComplexity(n *ast.IfStmt) {
+ if v.markedAsElseNode(n) {
+ v.incComplexity()
+ } else {
+ v.nestIncComplexity()
+ }
+}
+
+func mergeBinaryOps(x []token.Token, op token.Token, y []token.Token) []token.Token {
+ var out []token.Token
+ if len(x) != 0 {
+ out = append(out, x...)
+ }
+ out = append(out, op)
+ if len(y) != 0 {
+ out = append(out, y...)
+ }
+ return out
+}