go-cogscore
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.
Features
- 🧠 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
Installation
go install github.com/BaseMax/go-cogscore/cmd/go-cogscore@latest
Or build from source:
git clone https://github.com/BaseMax/go-cogscore
cd go-cogscore
go build -o go-cogscore ./cmd/go-cogscore
Usage
Basic Analysis
Analyze current directory:
go-cogscore
Analyze specific files or directories:
go-cogscore ./pkg ./cmd
go-cogscore main.go utils.go
Simple text report (default):
go-cogscore -format text
Detailed report with line-by-line breakdown:
go-cogscore -format detailed
JSON output for programmatic consumption:
go-cogscore -format json > complexity.json
CI-friendly format with exit codes:
go-cogscore -format ci
Filtering Results
Show only high-complexity functions (score > 15):
go-cogscore -min 15
Show only moderate complexity (score between 5 and 10):
go-cogscore -min 5 -max 10
Understanding Cognitive Complexity
Cognitive complexity differs from cyclomatic complexity by focusing on how hard code is to understand:
Scoring Rules
- 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):
goto and labeled break/continue
Examples
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
}
Risk Levels
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 |
CI Integration
Exit Codes
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+)
GitHub Actions Example
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 15
GitLab CI Example
complexity-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.json
Output Examples
Text Format
Cognitive 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
Library Usage
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)
}
Why Cognitive Complexity?
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.
Future Enhancements
- 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
Contributing
Contributions are welcome! Please feel free to submit issues or pull requests.
License
This project is licensed under the GPL-3.0 License - see the LICENSE file for details.
References
Author
Developed by BaseMax