Skip to content

Commit 92ec1a1

Browse files
uudashrjirfag
authored andcommitted
Add gocognit linter (#756)
* Add gocognit linter * Remove gocognit to the golangci config * Make changes on README.md * Remove gocognit from megacheck benchtest * Remove command line flags * Comply with new style
1 parent dbf0231 commit 92ec1a1

File tree

14 files changed

+620
-0
lines changed

14 files changed

+620
-0
lines changed

.golangci.example.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ linters-settings:
116116
gocyclo:
117117
# minimal code complexity to report, 30 by default (but we recommend 10-20)
118118
min-complexity: 10
119+
gocognit:
120+
# minimal code complexity to report, 30 by default (but we recommend 10-20)
121+
min-complexity: 10
119122
maligned:
120123
# print struct with more effective memory layout or not, false by default
121124
suggest-new: true

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ dupl: Tool for code clone detection [fast: true, auto-fix: false]
201201
funlen: Tool for detection of long functions [fast: true, auto-fix: false]
202202
gochecknoglobals: Checks that no globals are present in Go code [fast: true, auto-fix: false]
203203
gochecknoinits: Checks that no init functions are present in Go code [fast: true, auto-fix: false]
204+
gocognit: Computes and checks the cognitive complexity of functions [fast: true, auto-fix: false]
204205
goconst: Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false]
205206
gocritic: The most opinionated Go source code linter [fast: true, auto-fix: false]
206207
gocyclo: Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false]
@@ -449,6 +450,7 @@ golangci-lint help linters
449450
- [dupl](https://github.com/mibk/dupl) - Tool for code clone detection
450451
- [goconst](https://github.com/jgautheron/goconst) - Finds repeated strings that could be replaced by a constant
451452
- [gocyclo](https://github.com/alecthomas/gocyclo) - Computes and checks the cyclomatic complexity of functions
453+
- [gocognit](https://github.com/uudashr/gocognit) - Computes and checks the cognitive complexity of functions
452454
- [gofmt](https://golang.org/cmd/gofmt/) - Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
453455
- [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports) - Goimports does everything that gofmt does. Additionally it checks unused imports
454456
- [maligned](https://github.com/mdempsky/maligned) - Tool to detect Go structs that would take less memory if their fields were sorted
@@ -703,6 +705,9 @@ linters-settings:
703705
gocyclo:
704706
# minimal code complexity to report, 30 by default (but we recommend 10-20)
705707
min-complexity: 10
708+
gocognit:
709+
# minimal code complexity to report, 30 by default (but we recommend 10-20)
710+
min-complexity: 10
706711
maligned:
707712
# print struct with more effective memory layout or not, false by default
708713
suggest-new: true
@@ -1108,6 +1113,7 @@ Thanks to developers and authors of used linters:
11081113
- [jgautheron](https://github.com/jgautheron)
11091114
- [remyoudompheng](https://github.com/remyoudompheng)
11101115
- [alecthomas](https://github.com/alecthomas)
1116+
- [uudashr](https://github.com/uudashr)
11111117
- [OpenPeeDeeP](https://github.com/OpenPeeDeeP)
11121118
- [client9](https://github.com/client9)
11131119
- [walle](https://github.com/walle)

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ require (
3737
github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e
3838
github.com/ultraware/funlen v0.0.2
3939
github.com/ultraware/whitespace v0.0.3
40+
github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517
4041
github.com/valyala/quicktemplate v1.2.0
4142
golang.org/x/tools v0.0.0-20190912215617-3720d1ec3678
4243
gopkg.in/yaml.v2 v2.2.2

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ github.com/ultraware/funlen v0.0.2 h1:Av96YVBwwNSe4MLR7iI/BIa3VyI7/djnto/pK3Uxbd
234234
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
235235
github.com/ultraware/whitespace v0.0.3 h1:S5BCRRB5sttNy0bSOhbpw+0mb+cHiCmWfrvxpEzuUk0=
236236
github.com/ultraware/whitespace v0.0.3/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
237+
github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517 h1:ChMKTho2hWKpks/nD/FL2KqM1wuVt62oJeiE8+eFpGs=
238+
github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
237239
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
238240
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
239241
github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=

pkg/config/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ type LintersSettings struct {
138138
Gocyclo struct {
139139
MinComplexity int `mapstructure:"min-complexity"`
140140
}
141+
Gocognit struct {
142+
MinComplexity int `mapstructure:"min-complexity"`
143+
}
141144
Varcheck struct {
142145
CheckExportedFields bool `mapstructure:"exported-fields"`
143146
}

pkg/golinters/gocognit.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// nolint:dupl
2+
package golinters
3+
4+
import (
5+
"fmt"
6+
"sort"
7+
"sync"
8+
9+
"github.com/uudashr/gocognit"
10+
"golang.org/x/tools/go/analysis"
11+
12+
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
13+
"github.com/golangci/golangci-lint/pkg/lint/linter"
14+
"github.com/golangci/golangci-lint/pkg/result"
15+
)
16+
17+
const gocognitName = "gocognit"
18+
19+
func NewGocognit() *goanalysis.Linter {
20+
var mu sync.Mutex
21+
var resIssues []result.Issue
22+
23+
analyzer := &analysis.Analyzer{
24+
Name: goanalysis.TheOnlyAnalyzerName,
25+
Doc: goanalysis.TheOnlyanalyzerDoc,
26+
}
27+
return goanalysis.NewLinter(
28+
gocognitName,
29+
"Computes and checks the cognitive complexity of functions",
30+
[]*analysis.Analyzer{analyzer},
31+
nil,
32+
).WithContextSetter(func(lintCtx *linter.Context) {
33+
analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
34+
var stats []gocognit.Stat
35+
for _, f := range pass.Files {
36+
stats = gocognit.ComplexityStats(f, pass.Fset, stats)
37+
}
38+
if len(stats) == 0 {
39+
return nil, nil
40+
}
41+
42+
sort.Slice(stats, func(i, j int) bool {
43+
return stats[i].Complexity > stats[j].Complexity
44+
})
45+
46+
res := make([]result.Issue, 0, len(stats))
47+
for _, s := range stats {
48+
if s.Complexity <= lintCtx.Settings().Gocognit.MinComplexity {
49+
break // Break as the stats is already sorted from greatest to least
50+
}
51+
52+
res = append(res, result.Issue{
53+
Pos: s.Pos,
54+
Text: fmt.Sprintf("cognitive complexity %d of func %s is high (> %d)",
55+
s.Complexity, formatCode(s.FuncName, lintCtx.Cfg), lintCtx.Settings().Gocognit.MinComplexity),
56+
FromLinter: gocognitName,
57+
})
58+
}
59+
60+
mu.Lock()
61+
resIssues = append(resIssues, res...)
62+
mu.Unlock()
63+
64+
return nil, nil
65+
}
66+
}).WithIssuesReporter(func(*linter.Context) []result.Issue {
67+
return resIssues
68+
}).WithLoadMode(goanalysis.LoadModeSyntax)
69+
}

pkg/golinters/gocyclo.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// nolint:dupl
12
package golinters
23

34
import (

pkg/lint/lintersdb/manager.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
137137
linter.NewConfig(golinters.NewGocyclo()).
138138
WithPresets(linter.PresetComplexity).
139139
WithURL("https://github.com/alecthomas/gocyclo"),
140+
linter.NewConfig(golinters.NewGocognit()).
141+
WithPresets(linter.PresetComplexity).
142+
WithURL("https://github.com/uudashr/gocognit"),
140143
linter.NewConfig(golinters.NewTypecheck()).
141144
WithLoadForGoAnalysis().
142145
WithPresets(linter.PresetBugs).

test/testdata/gocognit.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//args: -Egocognit
2+
//config: linters-settings.gocognit.min-complexity=2
3+
package testdata
4+
5+
func GocognitGetWords(number int) string { // ERROR "cognitive complexity 4 of func .* is high .*"
6+
if number == 1 { // +1
7+
return "one"
8+
} else if number == 2 { // +1
9+
return "a couple"
10+
} else if number == 3 { // +1
11+
return "a few"
12+
} else { // +1
13+
return "lots"
14+
}
15+
} // total complexity = 4
16+
17+
func GoCognitFact(n int) int { // ERROR "cognitive complexity 3 of func .* is high .*"
18+
if n <= 1 { // +1
19+
return 1
20+
} else { // +1
21+
return n + GoCognitFact(n-1) // +1
22+
}
23+
} // total complexity = 3

vendor/github.com/uudashr/gocognit/LICENSE

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/uudashr/gocognit/README.md

Lines changed: 185 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/uudashr/gocognit/go.mod

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)