update gocyclo

This commit is contained in:
Shawn Smith
2021-11-28 12:05:18 +09:00
parent 749137a223
commit 87e76dbbd0
18 changed files with 602 additions and 270 deletions

View File

@@ -334,7 +334,12 @@ func GoTool(dir string, filenames, command []string) (float64, []FileSummary, er
params := command[1:]
params = addSkipDirs(params)
params = append(params, dir+"/...")
if strings.Contains(command[len(command)-1], "cyclo") {
params = append(params, dir)
} else {
params = append(params, dir+"/...")
}
cmd := exec.Command(command[0], params...)
stdout, err := cmd.StdoutPipe()

2
go.mod
View File

@@ -4,7 +4,6 @@ go 1.16
require (
github.com/DataDog/zstd v1.4.8 // indirect
github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214
github.com/alecthomas/gometalinter v1.0.3
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 // indirect
@@ -14,6 +13,7 @@ require (
github.com/dgraph-io/ristretto v0.0.3 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/dustin/go-humanize v1.0.0
github.com/fzipp/gocyclo v0.3.1
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.3 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect

12
go.sum
View File

@@ -5,8 +5,6 @@ github.com/DataDog/zstd v1.4.8 h1:Rpmta4xZ/MgZnriKNd24iZMhGpP5dvUcs/uqfBapKZY=
github.com/DataDog/zstd v1.4.8/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214 h1:YI/8G3uLbYyowJeOPVL6BMKe2wbL54h0FdEKmncU6lU=
github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214/go.mod h1:Ef5UOtJdJ5rVFObdOVsrNgKV/Wf4I+daTCSk8GTrHIk=
github.com/alecthomas/gometalinter v1.0.3 h1:Y5sxwml3eb93scdwfdOOh5VDULOtOEuCMrOnRpRwn1w=
github.com/alecthomas/gometalinter v1.0.3/go.mod h1:qfIpQGGz3d+NmgyPBqv+LSh50emm1pt72EtcX2vKYQk=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
@@ -38,6 +36,8 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fzipp/gocyclo v0.3.1 h1:A9UeX3HJSXTBzvHzhqoYVuE0eAhe+aM8XBCCwsPMZOc=
github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
@@ -50,8 +50,6 @@ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/gordonklaus/ineffassign v0.0.0-20210522101830-0589229737b2 h1:hC4RAQwLzbDbHsa+CwwGBm1uG2oX9o3Frx9G73duPi8=
github.com/gordonklaus/ineffassign v0.0.0-20210522101830-0589229737b2/go.mod h1:M9mZEtGIsR1oDaZagNPNG9iq9n2HrhZ17dsXk73V3Lw=
github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 h1:PVRE9d4AQKmbelZ7emNig1+NT27DUmKZn5qXxfio54U=
github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
@@ -106,14 +104,12 @@ golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -131,8 +127,6 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ=
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211015200801-69063c4bb744 h1:KzbpndAYEM+4oHRp9JmB2ewj0NHHxO3Z0g7Gus2O1kk=
golang.org/x/sys v0.0.0-20211015200801-69063c4bb744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -144,8 +138,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.3 h1:L69ShwSZEyCsLKoAxDKeMvLDZkumEe8gXUZAjab0tX8=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=

View File

@@ -3,6 +3,6 @@
go install ./vendor/github.com/alecthomas/gometalinter
go install ./vendor/golang.org/x/lint/golint
go install ./vendor/github.com/alecthomas/gocyclo
go install ./vendor/github.com/fzipp/gocyclo
go install ./vendor/github.com/gordonklaus/ineffassign
go install ./vendor/github.com/client9/misspell

View File

@@ -4,9 +4,9 @@
package tools
import (
_ "github.com/alecthomas/gocyclo"
_ "github.com/alecthomas/gometalinter"
_ "github.com/client9/misspell/cmd/misspell"
_ "github.com/fzipp/gocyclo/cmd/gocyclo"
_ "github.com/gordonklaus/ineffassign"
_ "golang.org/x/lint/golint"
_ "honnef.co/go/tools/cmd/staticcheck"

View File

@@ -1,31 +0,0 @@
Gocyclo calculates cyclomatic complexities of functions in Go source code.
The cyclomatic complexity of a function is calculated according to the
following rules:
1 is the base complexity of a function
+1 for each 'if', 'for', 'case', '&&' or '||'
To install, run
$ go get github.com/fzipp/gocyclo
and put the resulting binary in one of your PATH directories if
`$GOPATH/bin` isn't already in your PATH.
Usage:
$ gocyclo [<flag> ...] <Go file or directory> ...
Examples:
$ gocyclo .
$ gocyclo main.go
$ gocyclo -top 10 src/
$ gocyclo -over 25 docker
$ gocyclo -avg .
The output fields for each line are:
<complexity> <package> <function> <file:row:column>

View File

@@ -1,222 +0,0 @@
// Copyright 2013 Frederik Zipp. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Gocyclo calculates the cyclomatic complexities of functions and
// methods in Go source code.
//
// Usage:
// gocyclo [<flag> ...] <Go file or directory> ...
//
// Flags
// -over N show functions with complexity > N only and
// return exit code 1 if the output is non-empty
// -top N show the top N most complex functions only
// -avg show the average complexity
//
// The output fields for each line are:
// <complexity> <package> <function> <file:row:column>
package main
import (
"flag"
"fmt"
"go/ast"
"go/parser"
"go/token"
"io"
"os"
"path/filepath"
"sort"
)
const usageDoc = `Calculate cyclomatic complexities of Go functions.
usage:
gocyclo [<flag> ...] <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>
`
func usage() {
fmt.Fprintf(os.Stderr, usageDoc)
os.Exit(2)
}
var (
over = flag.Int("over", 0, "show functions with complexity > N only")
top = flag.Int("top", -1, "show the top N most complex functions only")
avg = flag.Bool("avg", false, "show the average complexity")
)
func main() {
flag.Usage = usage
flag.Parse()
args := flag.Args()
if len(args) == 0 {
usage()
}
stats := analyze(args)
sort.Sort(byComplexity(stats))
written := writeStats(os.Stdout, stats)
if *avg {
showAverage(stats)
}
if *over > 0 && written > 0 {
os.Exit(1)
}
}
func analyze(paths []string) []stat {
stats := make([]stat, 0)
for _, path := range paths {
if isDir(path) {
stats = analyzeDir(path, stats)
} else {
stats = analyzeFile(path, stats)
}
}
return stats
}
func isDir(filename string) bool {
fi, err := os.Stat(filename)
return err == nil && fi.IsDir()
}
func analyzeFile(fname string, stats []stat) []stat {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, fname, nil, 0)
if err != nil {
exitError(err)
}
return buildStats(f, fset, stats)
}
func analyzeDir(dirname string, stats []stat) []stat {
files, _ := filepath.Glob(filepath.Join(dirname, "*.go"))
for _, file := range files {
stats = analyzeFile(file, stats)
}
return stats
}
func exitError(err error) {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
func writeStats(w io.Writer, sortedStats []stat) int {
for i, stat := range sortedStats {
if i == *top {
return i
}
if stat.Complexity <= *over {
return i
}
fmt.Fprintln(w, stat)
}
return len(sortedStats)
}
func showAverage(stats []stat) {
fmt.Printf("Average: %.3g\n", average(stats))
}
func average(stats []stat) float64 {
total := 0
for _, s := range stats {
total += s.Complexity
}
return float64(total) / float64(len(stats))
}
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)
}
type byComplexity []stat
func (s byComplexity) Len() int { return len(s) }
func (s byComplexity) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s byComplexity) Less(i, j int) bool {
return s[i].Complexity >= s[j].Complexity
}
func buildStats(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 {
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 cyclomatic complexity of a function.
func complexity(fn *ast.FuncDecl) int {
v := complexityVisitor{}
ast.Walk(&v, fn)
return v.Complexity
}
type complexityVisitor struct {
// Complexity is the cyclomatic complexity
Complexity int
}
// Visit implements the ast.Visitor interface.
func (v *complexityVisitor) Visit(n ast.Node) ast.Visitor {
switch n := n.(type) {
case *ast.FuncDecl, *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt, *ast.CaseClause, *ast.CommClause:
v.Complexity++
case *ast.BinaryExpr:
if n.Op == token.LAND || n.Op == token.LOR {
v.Complexity++
}
}
return v
}

38
vendor/github.com/fzipp/gocyclo/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,38 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.3.1]
### Added
- Test coverage
### Fixed
- Fix cyclomatic complexity for function literals (base complexity of 1 was missing)
## [0.3.0] - 2020-10-17
### Added
- New `-avg-short` and `-total-short` options for printing average and total cyclomatic complexities without label
- Export the `AnalyzeASTFile` function in package API
- Doc comments for exported functions and types
### Fixed
- Ignore `default` cases
## [0.2.0] - 2020-10-17
### Added
- Support for gocyclo as a package
- Support for ignoring of individual functions via a new `gocyclo:ignore` directive
- New `-total` option to compute total cyclomatic complexity
- New `-ignore` option to ignore files matching a regular expression
- Analysis of function literals at declaration level
### Changed
- Breaking: installation changed to `go get github.com/fzipp/gocyclo/cmd/gocyclo`
## [0.1.0] - 2020-10-17
### Added
- `go.mod` file; beginning of versioning

7
vendor/github.com/fzipp/gocyclo/CONTRIBUTORS generated vendored Normal file
View File

@@ -0,0 +1,7 @@
# Names should be added to this file like so:
# Name <email address>
# Please keep the list sorted.
Frederik Zipp <fzipp@gmx.de>
Harshavardhana <harsha@harshavardhana.net>

107
vendor/github.com/fzipp/gocyclo/README.md generated vendored Normal file
View File

@@ -0,0 +1,107 @@
# gocyclo
[![PkgGoDev](https://pkg.go.dev/badge/github.com/fzipp/gocyclo)](https://pkg.go.dev/github.com/fzipp/gocyclo)
[![Go Report Card](https://goreportcard.com/badge/github.com/fzipp/gocyclo)](https://goreportcard.com/report/github.com/fzipp/gocyclo)
Gocyclo calculates
[cyclomatic complexities](https://en.wikipedia.org/wiki/Cyclomatic_complexity)
of functions in Go source code.
Cyclomatic complexity is a
[code quality metric](https://en.wikipedia.org/wiki/Software_metric)
which can be used to identify code that needs refactoring.
It measures the number of linearly independent paths through a function's
source code.
The cyclomatic complexity of a function is calculated according to the
following rules:
```
1 is the base complexity of a function
+1 for each 'if', 'for', 'case', '&&' or '||'
```
A function with a higher cyclomatic complexity requires more test cases to
cover all possible paths and is potentially harder to understand. The
complexity can be reduced by applying common refactoring techniques that lead
to smaller functions.
## Installation
To install the `gocyclo` command, run
```
$ go get github.com/fzipp/gocyclo/cmd/gocyclo
```
and put the resulting binary in one of your PATH directories if
`$GOPATH/bin` isn't already in your PATH.
## Usage
```
Calculate cyclomatic complexities of Go functions.
Usage:
gocyclo [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, -avg-short show the average complexity over all functions;
the short option prints the value without a label
-total, -total-short show the total complexity for all functions;
the short option prints the value without a label
-ignore REGEX exclude files matching the given regular expression
The output fields for each line are:
<complexity> <package> <function> <file:line:column>
```
## Examples
```
$ gocyclo .
$ gocyclo main.go
$ gocyclo -top 10 src/
$ gocyclo -over 25 docker
$ gocyclo -avg .
$ gocyclo -top 20 -ignore "_test|Godeps|vendor/" .
$ gocyclo -over 3 -avg gocyclo/
```
Example output:
```
9 gocyclo (*complexityVisitor).Visit complexity.go:30:1
8 main main cmd/gocyclo/main.go:53:1
7 gocyclo (*fileAnalyzer).analyzeDecl analyze.go:96:1
4 gocyclo Analyze analyze.go:24:1
4 gocyclo parseDirectives directives.go:27:1
4 gocyclo (Stats).SortAndFilter stats.go:52:1
Average: 2.72
```
Note that the average is calculated over all analyzed functions,
not just the printed ones.
### Ignoring individual functions
Individual functions can be ignored with a `gocyclo:ignore` directive:
```
//gocyclo:ignore
func f1() {
// ...
}
//gocyclo:ignore
var f2 = func() {
// ...
}
```
## License
This project is free and open source software licensed under the
[BSD 3-Clause License](LICENSE).

151
vendor/github.com/fzipp/gocyclo/analyze.go generated vendored Normal file
View File

@@ -0,0 +1,151 @@
// Copyright 2020 Frederik Zipp. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gocyclo
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"log"
"os"
"path/filepath"
"regexp"
"strings"
)
// Analyze calculates the cyclomatic complexities of the functions and methods
// in the Go source code files in the given paths. If a path is a directory
// all Go files under that directory are analyzed recursively.
// Files with paths matching the 'ignore' regular expressions are skipped.
// The 'ignore' parameter can be nil, meaning that no files are skipped.
func Analyze(paths []string, ignore *regexp.Regexp) Stats {
var stats Stats
for _, path := range paths {
info, err := os.Stat(path)
if err != nil {
log.Printf("could not get file info for path %q: %s\n", path, err)
continue
}
if info.IsDir() {
stats = analyzeDir(path, ignore, stats)
} else {
stats = analyzeFile(path, ignore, stats)
}
}
return stats
}
func analyzeDir(dirname string, ignore *regexp.Regexp, stats Stats) Stats {
filepath.Walk(dirname, func(path string, info os.FileInfo, err error) error {
if err == nil && isGoFile(info) {
stats = analyzeFile(path, ignore, stats)
}
return err
})
return stats
}
func isGoFile(f os.FileInfo) bool {
return !f.IsDir() && strings.HasSuffix(f.Name(), ".go")
}
func analyzeFile(path string, ignore *regexp.Regexp, stats Stats) Stats {
if isIgnored(path, ignore) {
return stats
}
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
if err != nil {
log.Fatal(err)
}
return AnalyzeASTFile(f, fset, stats)
}
func isIgnored(path string, ignore *regexp.Regexp) bool {
return ignore != nil && ignore.MatchString(path)
}
// AnalyzeASTFile calculates the cyclomatic complexities of the functions
// and methods in the abstract syntax tree (AST) of a parsed Go file and
// appends the results to the given Stats slice.
func AnalyzeASTFile(f *ast.File, fs *token.FileSet, s Stats) Stats {
analyzer := &fileAnalyzer{
file: f,
fileSet: fs,
stats: s,
}
return analyzer.analyze()
}
type fileAnalyzer struct {
file *ast.File
fileSet *token.FileSet
stats Stats
}
func (a *fileAnalyzer) analyze() Stats {
for _, decl := range a.file.Decls {
a.analyzeDecl(decl)
}
return a.stats
}
func (a *fileAnalyzer) analyzeDecl(d ast.Decl) {
switch decl := d.(type) {
case *ast.FuncDecl:
a.addStatIfNotIgnored(decl, funcName(decl), decl.Doc)
case *ast.GenDecl:
for _, spec := range decl.Specs {
valueSpec, ok := spec.(*ast.ValueSpec)
if !ok {
continue
}
for _, value := range valueSpec.Values {
funcLit, ok := value.(*ast.FuncLit)
if !ok {
continue
}
a.addStatIfNotIgnored(funcLit, valueSpec.Names[0].Name, decl.Doc)
}
}
}
}
func (a *fileAnalyzer) addStatIfNotIgnored(node ast.Node, funcName string, doc *ast.CommentGroup) {
if parseDirectives(doc).HasIgnore() {
return
}
a.stats = append(a.stats, Stat{
PkgName: a.file.Name.Name,
FuncName: funcName,
Complexity: Complexity(node),
Pos: a.fileSet.Position(node.Pos()),
})
}
// 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"
}

121
vendor/github.com/fzipp/gocyclo/cmd/gocyclo/main.go generated vendored Normal file
View File

@@ -0,0 +1,121 @@
// Copyright 2013 Frederik Zipp. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Gocyclo calculates the cyclomatic complexities of functions and
// methods in Go source code.
//
// Usage:
// gocyclo [<flag> ...] <Go file or directory> ...
//
// Flags:
// -over N show functions with complexity > N only and
// return exit code 1 if the output is non-empty
// -top N show the top N most complex functions only
// -avg, -avg-short show the average complexity;
// the short option prints the value without a label
// -total, -total-short show the total complexity;
// the short option prints the value without a label
// -ignore REGEX exclude files matching the given regular expression
//
// The output fields for each line are:
// <complexity> <package> <function> <file:line:column>
package main
import (
"flag"
"fmt"
"log"
"os"
"regexp"
"github.com/fzipp/gocyclo"
)
const usageDoc = `Calculate cyclomatic complexities of Go functions.
Usage:
gocyclo [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, -avg-short show the average complexity over all functions;
the short option prints the value without a label
-total, -total-short show the total complexity for all functions;
the short option prints the value without a label
-ignore REGEX exclude files matching the given regular expression
The output fields for each line are:
<complexity> <package> <function> <file:line:column>
`
func main() {
over := flag.Int("over", 0, "show functions with complexity > N only")
top := flag.Int("top", -1, "show the top N most complex functions only")
avg := flag.Bool("avg", false, "show the average complexity")
avgShort := flag.Bool("avg-short", false, "show the average complexity without a label")
total := flag.Bool("total", false, "show the total complexity")
totalShort := flag.Bool("total-short", false, "show the total complexity without a label")
ignore := flag.String("ignore", "", "exclude files matching the given regular expression")
log.SetFlags(0)
log.SetPrefix("gocyclo: ")
flag.Usage = usage
flag.Parse()
paths := flag.Args()
if len(paths) == 0 {
usage()
}
allStats := gocyclo.Analyze(paths, regex(*ignore))
shownStats := allStats.SortAndFilter(*top, *over)
printStats(shownStats)
if *avg || *avgShort {
printAverage(allStats, *avgShort)
}
if *total || *totalShort {
printTotal(allStats, *totalShort)
}
if *over > 0 && len(shownStats) > 0 {
os.Exit(1)
}
}
func regex(expr string) *regexp.Regexp {
if expr == "" {
return nil
}
re, err := regexp.Compile(expr)
if err != nil {
log.Fatal(err)
}
return re
}
func printStats(s gocyclo.Stats) {
for _, stat := range s {
fmt.Println(stat)
}
}
func printAverage(s gocyclo.Stats, short bool) {
if !short {
fmt.Print("Average: ")
}
fmt.Printf("%.3g\n", s.AverageComplexity())
}
func printTotal(s gocyclo.Stats, short bool) {
if !short {
fmt.Print("Total: ")
}
fmt.Printf("%d\n", s.TotalComplexity())
}
func usage() {
_, _ = fmt.Fprintf(os.Stderr, usageDoc)
os.Exit(2)
}

48
vendor/github.com/fzipp/gocyclo/complexity.go generated vendored Normal file
View File

@@ -0,0 +1,48 @@
// Copyright 2020 Frederik Zipp. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package gocyclo calculates the cyclomatic complexities of functions and
// methods in Go source code.
package gocyclo
import (
"go/ast"
"go/token"
)
// Complexity calculates the cyclomatic complexity of a function.
// The 'fn' node is either a *ast.FuncDecl or a *ast.FuncLit.
func Complexity(fn ast.Node) int {
v := complexityVisitor{
complexity: 1,
}
ast.Walk(&v, fn)
return v.complexity
}
type complexityVisitor struct {
// complexity is the cyclomatic complexity
complexity int
}
// Visit implements the ast.Visitor interface.
func (v *complexityVisitor) Visit(n ast.Node) ast.Visitor {
switch n := n.(type) {
case *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt:
v.complexity++
case *ast.CaseClause:
if n.List != nil { // ignore default case
v.complexity++
}
case *ast.CommClause:
if n.Comm != nil { // ignore default case
v.complexity++
}
case *ast.BinaryExpr:
if n.Op == token.LAND || n.Op == token.LOR {
v.complexity++
}
}
return v
}

39
vendor/github.com/fzipp/gocyclo/directives.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
// Copyright 2020 Frederik Zipp. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gocyclo
import (
"go/ast"
"strings"
)
type directives []string
func (ds directives) HasIgnore() bool {
return ds.isPresent("ignore")
}
func (ds directives) isPresent(name string) bool {
for _, d := range ds {
if d == name {
return true
}
}
return false
}
func parseDirectives(doc *ast.CommentGroup) directives {
if doc == nil {
return directives{}
}
const prefix = "//gocyclo:"
var ds directives
for _, comment := range doc.List {
if strings.HasPrefix(comment.Text, prefix) {
ds = append(ds, strings.TrimSpace(strings.TrimPrefix(comment.Text, prefix)))
}
}
return ds
}

3
vendor/github.com/fzipp/gocyclo/go.mod generated vendored Normal file
View File

@@ -0,0 +1,3 @@
module github.com/fzipp/gocyclo
go 1.15

73
vendor/github.com/fzipp/gocyclo/stats.go generated vendored Normal file
View File

@@ -0,0 +1,73 @@
// Copyright 2020 Frederik Zipp. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gocyclo
import (
"fmt"
"go/token"
"sort"
)
// Stat holds the cyclomatic complexity of a function, along with its package
// and and function name and its position in the source code.
type Stat struct {
PkgName string
FuncName string
Complexity int
Pos token.Position
}
// String formats the cyclomatic complexity information of a function in
// the following format: "<complexity> <package> <function> <file:line:column>"
func (s Stat) String() string {
return fmt.Sprintf("%d %s %s %s", s.Complexity, s.PkgName, s.FuncName, s.Pos)
}
// Stats hold the cyclomatic complexities of many functions.
type Stats []Stat
// AverageComplexity calculates the average cyclomatic complexity of the
// cyclomatic complexities in s.
func (s Stats) AverageComplexity() float64 {
return float64(s.TotalComplexity()) / float64(len(s))
}
// TotalComplexity calculates the total sum of all cyclomatic
// complexities in s.
func (s Stats) TotalComplexity() uint64 {
total := uint64(0)
for _, stat := range s {
total += uint64(stat.Complexity)
}
return total
}
// SortAndFilter sorts the cyclomatic complexities in s in descending order
// and returns a slice of s limited to the 'top' N entries with a cyclomatic
// complexity greater than 'over'. If 'top' is negative, i.e. -1, it does
// not limit the result. If 'over' is <= 0 it does not limit the result either,
// because a function has a base cyclomatic complexity of at least 1.
func (s Stats) SortAndFilter(top, over int) Stats {
result := make(Stats, len(s))
copy(result, s)
sort.Sort(byComplexityDesc(result))
for i, stat := range result {
if i == top {
return result[:i]
}
if stat.Complexity <= over {
return result[:i]
}
}
return result
}
type byComplexityDesc Stats
func (s byComplexityDesc) Len() int { return len(s) }
func (s byComplexityDesc) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s byComplexityDesc) Less(i, j int) bool {
return s[i].Complexity >= s[j].Complexity
}

7
vendor/modules.txt vendored
View File

@@ -3,9 +3,6 @@ github.com/BurntSushi/toml
# github.com/DataDog/zstd v1.4.8
## explicit
github.com/DataDog/zstd
# github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214
## explicit
github.com/alecthomas/gocyclo
# github.com/alecthomas/gometalinter v1.0.3
## explicit
github.com/alecthomas/gometalinter
@@ -44,6 +41,10 @@ github.com/dgryski/go-farm
# github.com/dustin/go-humanize v1.0.0
## explicit
github.com/dustin/go-humanize
# github.com/fzipp/gocyclo v0.3.1
## explicit
github.com/fzipp/gocyclo
github.com/fzipp/gocyclo/cmd/gocyclo
# github.com/golang/protobuf v1.5.2
## explicit
github.com/golang/protobuf/proto