cogscore

package module
v0.0.0-...-7319202 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 20, 2025 License: MIT Imports: 10 Imported by: 0

README

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
Output Formats

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
  1. Base Increment (+1): Control flow structures like if, for, switch, select
  2. Nesting Penalty (+n): Each level of nesting adds to the score
  3. Logical Operators (+1): Each && and || in conditions
  4. 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 Format
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)
JSON Format
{
  "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
  }
}
CI Format
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:

  1. Ignoring "shortcut" structures that don't increase understandability (like else)
  2. Penalizing nesting because nested code is harder to understand
  3. 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

Documentation

Index

Constants

View Source
const (
	RiskLowThreshold      = 5
	RiskModerateThreshold = 10
	RiskHighThreshold     = 15
	RiskVeryHighThreshold = 20
)

Risk level thresholds for cognitive complexity

Variables

This section is empty.

Functions

This section is empty.

Types

type Analyzer

type Analyzer struct {
	// contains filtered or unexported fields
}

Analyzer analyzes source code files

func NewAnalyzer

func NewAnalyzer(options AnalyzerOptions) *Analyzer

NewAnalyzer creates a new analyzer with the given options

func (*Analyzer) Analyze

func (a *Analyzer) Analyze() (*Report, error)

Analyze analyzes all files and returns a report

type AnalyzerOptions

type AnalyzerOptions struct {
	Paths           []string
	IncludePatterns []string
	ExcludePatterns []string
	MinScore        int
	MaxScore        int
}

AnalyzerOptions contains options for the analyzer

type Complexity

type Complexity struct {
	Name    string
	Score   int
	Line    int
	Column  int
	Nesting int
	Details []ComplexityDetail
}

Complexity represents the cognitive complexity of a code element

type ComplexityDetail

type ComplexityDetail struct {
	Line      int
	Column    int
	Reason    string
	Increment int
	Nesting   int
}

ComplexityDetail represents a detail about why complexity was incremented

type FileComplexity

type FileComplexity struct {
	Filename   string
	Functions  []Complexity
	TotalScore int
}

FileComplexity represents the complexity analysis of an entire file

func AnalyzeFile

func AnalyzeFile(filename string) (*FileComplexity, error)

AnalyzeFile analyzes a Go source file and returns its cognitive complexity

type Report

type Report struct {
	Files      []FileComplexity
	TotalScore int
	Summary    Summary
}

Report represents a complete analysis report

func NewReport

func NewReport(files []FileComplexity) *Report

NewReport creates a new report from file complexities

func (*Report) WriteReport

func (r *Report) WriteReport(w io.Writer, format ReportFormat) error

WriteReport writes the report in the specified format

type ReportFormat

type ReportFormat string

ReportFormat defines the output format for reports

const (
	FormatText     ReportFormat = "text"
	FormatJSON     ReportFormat = "json"
	FormatDetailed ReportFormat = "detailed"
	FormatCI       ReportFormat = "ci"
)

type Summary

type Summary struct {
	TotalFiles       int
	TotalFunctions   int
	TotalScore       int
	AverageScore     float64
	HighestScore     int
	HighestScoreFunc string
	HighestScoreFile string
	FunctionsAbove10 int
	FunctionsAbove15 int
	FunctionsAbove20 int
}

Summary contains overall statistics

Directories

Path Synopsis
cmd
go-cogscore command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL