A Go static analysis tool that computes cognitive complexity scores for Go source code. Unlike cyclomatic complexity, cognitive complexity measures how difficult code is to understand by humans, taking into account nesting depth and control flow interruptions.
- đź§ Cognitive Complexity Analysis: Measures code understandability, not just paths
- 📊 Multiple Output Formats: Text, detailed, JSON, and CI-friendly formats
- 🎯 Nesting Detection: Identifies deeply nested logic with penalty scoring
- 🔍 Readability Risk Assessment: Categorizes functions by risk levels
- 🚀 CI Integration: Exit codes and key-value output for automated pipelines
- 📝 Annotated Reports: Line-by-line breakdown of complexity contributors
- đź”§ Flexible Filtering: Filter results by minimum/maximum complexity scores
go install github.com/BaseMax/go-cogscore/cmd/go-cogscore@latestOr build from source:
git clone https://github.com/BaseMax/go-cogscore
cd go-cogscore
go build -o go-cogscore ./cmd/go-cogscoreAnalyze current directory:
go-cogscoreAnalyze specific files or directories:
go-cogscore ./pkg ./cmd
go-cogscore main.go utils.goSimple text report (default):
go-cogscore -format textDetailed report with line-by-line breakdown:
go-cogscore -format detailedJSON output for programmatic consumption:
go-cogscore -format json > complexity.jsonCI-friendly format with exit codes:
go-cogscore -format ciShow only high-complexity functions (score > 15):
go-cogscore -min 15Show only moderate complexity (score between 5 and 10):
go-cogscore -min 5 -max 10Cognitive complexity differs from cyclomatic complexity by focusing on how hard code is to understand:
- Base Increment (+1): Control flow structures like
if,for,switch,select - Nesting Penalty (+n): Each level of nesting adds to the score
- Logical Operators (+1): Each
&&and||in conditions - Jump Statements (+1):
gotoand labeledbreak/continue
Simple function (Score: 0):
func add(a, b int) int {
return a + b
}Single if statement (Score: 1):
func max(a, b int) int {
if a > b { // +1
return a
}
return b
}Nested conditions (Score: 3):
func process(x, y int) {
if x > 0 { // +1
if y > 0 { // +2 (1 base + 1 nesting)
println("both positive")
}
}
}Complex logic (Score: 6):
func analyze(items []int) int {
sum := 0
for _, item := range items { // +1
if item > 0 { // +2 (nesting level 1)
if item < 100 { // +3 (nesting level 2)
sum += item
}
}
}
return sum
}Functions are categorized by cognitive complexity score:
| Score | Risk Level | Recommendation |
|---|---|---|
| 1-5 | LOW | Simple, easy to understand |
| 6-10 | MODERATE | Slightly complex, acceptable |
| 11-15 | HIGH | Complex, consider refactoring |
| 16-20 | VERY HIGH | Very complex, should refactor |
| 21+ | CRITICAL | Extremely complex, must refactor |
When using -format ci, the tool exits with:
0: OK (no high-risk functions)1: WARNING (functions with score 16-20)2: CRITICAL (functions with score 21+)
name: Code Complexity Check
on: [push, pull_request]
jobs:
complexity:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Install go-cogscore
run: go install github.com/BaseMax/go-cogscore/cmd/go-cogscore@latest
- name: Check cognitive complexity
run: |
go-cogscore -format ci
go-cogscore -format detailed -min 15complexity-check:
stage: test
image: golang:1.21
script:
- go install github.com/BaseMax/go-cogscore/cmd/go-cogscore@latest
- go-cogscore -format ci
- go-cogscore -format json > complexity.json
artifacts:
reports:
complexity: complexity.jsonCognitive Complexity Report
===========================
File: example.go (Total: 12)
processData (line 10): 8 [MODERATE]
validateInput (line 25): 4 [LOW]
Summary
-------
Total Files: 1
Total Functions: 2
Total Score: 12
Average Score: 6.00
Highest Score: 8 (processData in example.go)
Detailed Cognitive Complexity Report
====================================
File: example.go
----------------
Function: processData (line 10)
Cognitive Complexity: 8 [MODERATE]
Complexity Details:
Line 11: +1 for if statement
Line 12: +2 for if statement (nesting: 1)
Line 15: +2 for loop (nesting: 1)
Line 16: +3 for if statement (nesting: 2)
{
"Files": [
{
"Filename": "example.go",
"Functions": [
{
"Name": "processData",
"Score": 8,
"Line": 10,
"Column": 1,
"Nesting": 0,
"Details": [
{
"Line": 11,
"Column": 2,
"Reason": "if statement",
"Increment": 1,
"Nesting": 0
}
]
}
],
"TotalScore": 8
}
],
"Summary": {
"TotalFiles": 1,
"TotalFunctions": 1,
"TotalScore": 8,
"AverageScore": 8.0
}
}cognitive_complexity_total=12
cognitive_complexity_average=6.00
cognitive_complexity_highest=8
functions_high_risk=0
functions_very_high_risk=0
status=OK
You can also use go-cogscore as a library in your Go programs:
package main
import (
"fmt"
"os"
"github.com/BaseMax/go-cogscore"
)
func main() {
// Analyze a single file
result, err := cogscore.AnalyzeFile("myfile.go")
if err != nil {
panic(err)
}
fmt.Printf("Total complexity: %d\n", result.TotalScore)
for _, fn := range result.Functions {
fmt.Printf("%s: %d\n", fn.Name, fn.Score)
}
// Or analyze multiple files
analyzer := cogscore.NewAnalyzer(cogscore.AnalyzerOptions{
Paths: []string{"./pkg", "./cmd"},
MinScore: 10,
})
report, err := analyzer.Analyze()
if err != nil {
panic(err)
}
report.WriteReport(os.Stdout, cogscore.FormatDetailed)
}Cyclomatic complexity counts the number of linearly independent paths through code, but this doesn't always correlate with understandability. Cognitive complexity addresses this by:
- Ignoring "shortcut" structures that don't increase understandability (like
else) - Penalizing nesting because nested code is harder to understand
- Recognizing that breaks in control flow make code harder to follow
This results in scores that better reflect actual code readability.
- Support for analyzing other languages (JavaScript, Python, etc.)
- Integration with popular linters (golangci-lint)
- HTML report generation with syntax highlighting
- Trend analysis over time
- Configurable thresholds and rules
Contributions are welcome! Please feel free to submit issues or pull requests.
This project is licensed under the GPL-3.0 License - see the LICENSE file for details.
- Cognitive Complexity: A new way of measuring understandability - SonarSource whitepaper
- Go AST Documentation
Developed by BaseMax