Skip to content

Commit 2881c26

Browse files
authored
Merge pull request #39 from uudashr/tracing
Add diagnostic capability
2 parents 8b1a11f + 1f9335e commit 2881c26

File tree

4 files changed

+325
-71
lines changed

4 files changed

+325
-71
lines changed

.github/workflows/test.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
name: Checks
2+
23
on:
3-
[pull_request]
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
branches:
9+
- master
410

511
jobs:
612
test:
@@ -11,7 +17,7 @@ jobs:
1117
matrix:
1218
os: [ubuntu-latest]
1319
os-version: ['stable']
14-
go-version: ['1.19', '1.20', '1.21', '1.22']
20+
go-version: ['1.19', '1.20', '1.21', '1.22', '1.23']
1521

1622
steps:
1723
- name: Checkout

README.md

Lines changed: 99 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -169,14 +169,17 @@ Usage:
169169
170170
Flags:
171171
172-
-over N show functions with complexity > N only
173-
and return exit code 1 if the output is non-empty
174-
-top N show the top N most complex functions only
175-
-avg show the average complexity over all functions,
176-
not depending on whether -over or -top are set
177-
-json encode the output as JSON
178-
-f format string the format to use
179-
(default "{{.PkgName}}.{{.FuncName}}:{{.Complexity}}:{{.Pos}}")
172+
-over N show functions with complexity > N only
173+
and return exit code 1 if the output is non-empty
174+
-top N show the top N most complex functions only
175+
-avg show the average complexity over all functions,
176+
not depending on whether -over or -top are set
177+
-test indicates whether test files should be included
178+
-json encode the output as JSON
179+
-d enable diagnostic output
180+
-f format string the format to use
181+
(default "{{.Complexity}} {{.PkgName}} {{.FuncName}} {{.Pos}}")
182+
-ignore expr ignore files matching the given regexp
180183
181184
The (default) output fields for each line are:
182185
@@ -191,10 +194,24 @@ or equal to <complexity> <package> <function> <file:row:column>
191194
The struct being passed to the template is:
192195
193196
type Stat struct {
194-
PkgName string
195-
FuncName string
196-
Complexity int
197-
Pos token.Position
197+
PkgName string
198+
FuncName string
199+
Complexity int
200+
Pos token.Position
201+
Diagnostics []Diagnostics
202+
}
203+
204+
type Diagnostic struct {
205+
Inc string
206+
Nesting int
207+
Text string
208+
Pos DiagnosticPosition
209+
}
210+
211+
type DiagnosticPosition struct {
212+
Offset int
213+
Line int
214+
Column int
198215
}
199216
```
200217

@@ -223,6 +240,76 @@ func IgnoreMe() {
223240
}
224241
```
225242

243+
## Diagnostic
244+
To understand how the complexity are calculated, we can enable the diagnostic by using `-d` flag.
245+
246+
Example:
247+
```shell
248+
$ gocognit -json -d .
249+
```
250+
251+
It will show the diagnostic output in JSON format
252+
<details>
253+
254+
<summary>JSON Output</summary>
255+
256+
```json
257+
[
258+
{
259+
"PkgName": "prime",
260+
"FuncName": "SumOfPrimes",
261+
"Complexity": 7,
262+
"Pos": {
263+
"Filename": "prime.go",
264+
"Offset": 15,
265+
"Line": 3,
266+
"Column": 1
267+
},
268+
"Diagnostics": [
269+
{
270+
"Inc": 1,
271+
"Text": "for",
272+
"Pos": {
273+
"Offset": 69,
274+
"Line": 7,
275+
"Column": 2
276+
}
277+
},
278+
{
279+
"Inc": 2,
280+
"Nesting": 1,
281+
"Text": "for",
282+
"Pos": {
283+
"Offset": 104,
284+
"Line": 8,
285+
"Column": 3
286+
}
287+
},
288+
{
289+
"Inc": 3,
290+
"Nesting": 2,
291+
"Text": "if",
292+
"Pos": {
293+
"Offset": 152,
294+
"Line": 9,
295+
"Column": 4
296+
}
297+
},
298+
{
299+
"Inc": 1,
300+
"Text": "continue",
301+
"Pos": {
302+
"Offset": 190,
303+
"Line": 10,
304+
"Column": 5
305+
}
306+
}
307+
]
308+
}
309+
]
310+
```
311+
</details>
312+
226313
## Related project
227314
- [Gocyclo](https://github.com/fzipp/gocyclo) where the code are based on.
228315
- [Cognitive Complexity: A new way of measuring understandability](https://www.sonarsource.com/docs/CognitiveComplexity.pdf) white paper by G. Ann Campbell.

cmd/gocognit/main.go

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
// -over N show functions with complexity > N only and return exit code 1 if the output is non-empty
1111
// -top N show the top N most complex functions only
1212
// -avg show the average complexity over all functions, not depending on whether -over or -top are set
13+
// -test indicates whether test files should be included
1314
// -json encode the output as JSON
14-
// -f format string the format to use (default "{{.PkgName}}.{{.FuncName}}:{{.Complexity}}:{{.Pos}}")
15+
// -d enable diagnostic output
16+
// -f format string the format to use (default "{{.Complexity}} {{.PkgName}} {{.FuncName}} {{.Pos}}")
1517
//
1618
// The (default) output fields for each line are:
1719
//
@@ -29,8 +31,22 @@
2931
// PkgName string
3032
// FuncName string
3133
// Complexity int
34+
// Diagnostics []Diagnostic
3235
// Pos token.Position
3336
// }
37+
//
38+
// type Diagnostic struct {
39+
// Inc string
40+
// Nesting int
41+
// Text string
42+
// Pos DiagnosticPosition
43+
// }
44+
//
45+
// type DiagnosticPosition struct {
46+
// Offset int
47+
// Line int
48+
// Column int
49+
// }
3450
package main
3551

3652
import (
@@ -59,15 +75,17 @@ Usage:
5975
6076
Flags:
6177
62-
-over N show functions with complexity > N only
63-
and return exit code 1 if the output is non-empty
64-
-top N show the top N most complex functions only
65-
-avg show the average complexity over all functions,
66-
not depending on whether -over or -top are set
67-
-test indicates whether test files should be included
68-
-json encode the output as JSON
69-
-f format string the format to use
70-
(default "{{.PkgName}}.{{.FuncName}}:{{.Complexity}}:{{.Pos}}")
78+
-over N show functions with complexity > N only
79+
and return exit code 1 if the output is non-empty
80+
-top N show the top N most complex functions only
81+
-avg show the average complexity over all functions,
82+
not depending on whether -over or -top are set
83+
-test indicates whether test files should be included
84+
-json encode the output as JSON
85+
-d enable diagnostic output
86+
-f format string the format to use
87+
(default "{{.Complexity}} {{.PkgName}} {{.FuncName}} {{.Pos}}")
88+
-ignore expr ignore files matching the given regexp
7189
7290
The (default) output fields for each line are:
7391
@@ -82,10 +100,24 @@ or equal to <complexity> <package> <function> <file:row:column>
82100
The struct being passed to the template is:
83101
84102
type Stat struct {
85-
PkgName string
86-
FuncName string
87-
Complexity int
88-
Pos token.Position
103+
PkgName string
104+
FuncName string
105+
Complexity int
106+
Pos token.Position
107+
Diagnostics []Diagnostics
108+
}
109+
110+
type Diagnostic struct {
111+
Inc string
112+
Nesting int
113+
Text string
114+
Pos DiagnosticPosition
115+
}
116+
117+
type DiagnosticPosition struct {
118+
Offset int
119+
Line int
120+
Column int
89121
}
90122
`
91123

@@ -103,13 +135,14 @@ func usage() {
103135

104136
func main() {
105137
var (
106-
over int
107-
top int
108-
avg bool
109-
includeTests bool
110-
format string
111-
jsonEncode bool
112-
ignoreExpr string
138+
over int
139+
top int
140+
avg bool
141+
includeTests bool
142+
format string
143+
jsonEncode bool
144+
enableDiagnostics bool
145+
ignoreExpr string
113146
)
114147

115148
flag.IntVar(&over, "over", defaultOverFlagVal, "show functions with complexity > N only")
@@ -118,6 +151,7 @@ func main() {
118151
flag.BoolVar(&includeTests, "test", true, "indicates whether test files should be included")
119152
flag.StringVar(&format, "f", defaultFormat, "the format to use")
120153
flag.BoolVar(&jsonEncode, "json", false, "encode the output as JSON")
154+
flag.BoolVar(&enableDiagnostics, "d", false, "enable diagnostic output")
121155
flag.StringVar(&ignoreExpr, "ignore", "", "ignore files matching the given regexp")
122156

123157
log.SetFlags(0)
@@ -136,7 +170,7 @@ func main() {
136170
log.Fatal(err)
137171
}
138172

139-
stats, err := analyze(args, includeTests)
173+
stats, err := analyze(args, includeTests, enableDiagnostics)
140174
if err != nil {
141175
log.Fatal(err)
142176
}
@@ -170,19 +204,19 @@ func main() {
170204
}
171205
}
172206

173-
func analyzePath(path string, includeTests bool) ([]gocognit.Stat, error) {
207+
func analyzePath(path string, includeTests bool, includeDiagnostic bool) ([]gocognit.Stat, error) {
174208
if isDir(path) {
175-
return analyzeDir(path, includeTests, nil)
209+
return analyzeDir(path, includeTests, nil, includeDiagnostic)
176210
}
177211

178-
return analyzeFile(path, nil)
212+
return analyzeFile(path, nil, includeDiagnostic)
179213
}
180214

181-
func analyze(paths []string, includeTests bool) (stats []gocognit.Stat, err error) {
215+
func analyze(paths []string, includeTests bool, includeDiagnostic bool) (stats []gocognit.Stat, err error) {
182216
var out []gocognit.Stat
183217

184218
for _, path := range paths {
185-
stats, err := analyzePath(path, includeTests)
219+
stats, err := analyzePath(path, includeTests, includeDiagnostic)
186220
if err != nil {
187221
return nil, err
188222
}
@@ -199,18 +233,18 @@ func isDir(filename string) bool {
199233
return err == nil && fi.IsDir()
200234
}
201235

202-
func analyzeFile(fname string, stats []gocognit.Stat) ([]gocognit.Stat, error) {
236+
func analyzeFile(fname string, stats []gocognit.Stat, includeDiagnostic bool) ([]gocognit.Stat, error) {
203237
fset := token.NewFileSet()
204238

205239
f, err := parser.ParseFile(fset, fname, nil, parser.ParseComments)
206240
if err != nil {
207241
return nil, err
208242
}
209243

210-
return gocognit.ComplexityStats(f, fset, stats), nil
244+
return gocognit.ComplexityStatsWithDiagnostic(f, fset, stats, includeDiagnostic), nil
211245
}
212246

213-
func analyzeDir(dirname string, includeTests bool, stats []gocognit.Stat) ([]gocognit.Stat, error) {
247+
func analyzeDir(dirname string, includeTests bool, stats []gocognit.Stat, trace bool) ([]gocognit.Stat, error) {
214248
err := filepath.Walk(dirname, func(path string, info os.FileInfo, err error) error {
215249
if err != nil {
216250
return err
@@ -228,7 +262,7 @@ func analyzeDir(dirname string, includeTests bool, stats []gocognit.Stat) ([]goc
228262
return nil
229263
}
230264

231-
stats, err = analyzeFile(path, stats)
265+
stats, err = analyzeFile(path, stats, trace)
232266
if err != nil {
233267
return err
234268
}

0 commit comments

Comments
 (0)