A home for finding Go's lost code. Discover orphaned symbols with surgical precision using advanced reachability analysis.
Gorphanage uses reachability analysis to identify truly dead code in Go projects. Unlike simple grep-based tools, it traces execution paths from main() functions to find symbols that are genuinely unreachable.
- π― Precise Detection - Uses Go's type system and AST for analysis
- π Reachability Tracing - BFS algorithm starting from main package entry points
- π Smart Analysis - Handles complex dependency chains and indirect references
- π οΈ Professional CLI - Built with Cobra & Viper for excellent UX
- βοΈ Flexible Configuration - YAML config files, environment variables, and CLI flags
- π¨ Multiple Output Formats - Human-readable terminal output and JSON for tooling
- π Smart Exclusions - Exclude vendor code, generated files, and custom patterns
- β‘ Fast & Reliable - Leverages the same engine that powers
gopls
go install github.com/mirrir0/gorphanage@latestcurl -sSL https://raw.githubusercontent.com/mirrir0/gorphanage/main/install.sh | bashgit clone https://github.com/mirrir0/gorphanage.git
cd gorphanage
make installDownload the latest release for your platform from the releases page.
# Analyze current directory
gorphanage .
# Analyze specific project
gorphanage /path/to/your/go/project
# Verbose output with progress
gorphanage --verbose .
# JSON output for tooling integration
gorphanage --json . > orphans.json# Exclude specific packages
gorphanage --exclude "vendor/*,*.pb.go" .
# Include test files in analysis
gorphanage --include-tests .
# Multiple exclusion patterns
gorphanage -e vendor -e generated -e "*.pb.go" .
# Use custom config file
gorphanage --config ./custom-config.yaml .$ gorphanage .
π Analyzing project at: /home/user/myproject
π¦ Loaded 8 packages
π Found 147 symbols
π¦ Found 2 main package(s)
π Tracing reachability from main packages...
π Reachability analysis: 132/147 symbols reachable from main packages
β
No orphaned code found!
All symbols are reachable from main package entry points.$ gorphanage --verbose .
π Analyzing project at: /home/user/myproject
π¦ Loaded 8 packages
π Found 147 symbols
π¦ Found 2 main package(s)
github.com/user/myproject/cmd/server
github.com/user/myproject/cmd/client
π Tracing reachability from main packages...
π― Starting with 6 entry points
π Reachability analysis: 132/147 symbols reachable from main packages
ποΈ ORPHANED CODE ANALYSIS
Found 15 symbols that are NOT reachable from any main package:
=== Functions ===
π processLegacyData (private) - internal/legacy.go:67:1
π ExportedButUnused (exported) - pkg/api.go:34:1
π helperFunc (private) - utils/string.go:123:1
=== Types ===
π OldConfig (exported) - config/deprecated.go:18:1
π internalState (private) - state/manager.go:45:1
=== Variables ===
π debugFlag (private) - main.go:15:1
π‘ These symbols are not reachable from any main() or init() function.
π‘ Test functions are excluded as they have separate entry points.
π‘ Analysis based on 2 main package(s) found in the project.
π Analysis Summary:
β’ Total symbols: 147
β’ Reachable symbols: 132
β’ Orphaned symbols: 15
β’ Orphan rate: 10.2%$ gorphanage --json .
{
"project_path": "/home/user/myproject",
"total_symbols": 147,
"reachable_symbols": 132,
"main_packages": 2,
"excluded_packages": ["vendor/*", "*.pb.go"],
"included_tests": false,
"orphaned_symbols": [
{
"name": "processLegacyData",
"kind": "function",
"file": "/home/user/myproject/internal/legacy.go",
"start": { "line": 67, "column": 1 },
"end": { "line": 74, "column": 2 },
"exported": false,
"package": "github.com/user/myproject/internal"
}
]
}Create a configuration file for persistent settings:
# Initialize default config
gorphanage config init
# Show current configuration
gorphanage config showExample ~/.gorphanage.yaml:
# Output settings
json: false
verbose: false
# Analysis options
include-tests: false
# Exclude patterns (glob patterns for package paths)
exclude:
- "vendor/*" # Vendor dependencies
- "*.pb.go" # Protocol buffer generated files
- "*_generated.go" # Generated Go files
- "third_party/*" # Third-party code
- "mocks/*" # Mock implementations
- "testdata/*" # Test data directoriesexport GORPHANAGE_VERBOSE=true
export GORPHANAGE_EXCLUDE="vendor/*,generated/*"
export GORPHANAGE_JSON=true
gorphanage . # Uses environment settingsUsage: gorphanage [flags] <project-path>
Flags:
-e, --exclude strings exclude packages matching these patterns
-h, --help help for gorphanage
--include-tests include test files in analysis
--json output results in JSON format
-v, --verbose verbose output
--version version for gorphanage
Global Flags:
--config string config file (default is $HOME/.gorphanage.yaml)Gorphanage uses a sophisticated reachability analysis algorithm:
- π¦ Package Discovery - Loads all Go packages with full type information
- π Symbol Mapping - Identifies all functions, types, variables, and constants
- π― Entry Point Detection - Finds
main()andinit()functions as starting points - π BFS Traversal - Traces all possible execution paths from entry points
- π Orphan Detection - Reports symbols not reached during traversal
Traditional tools count references, but Gorphanage understands execution flow:
// β Simple tools miss this
func main() {
if false {
deadFunction() // This is actually dead!
}
}
// β
Gorphanage catches it
// Uses control flow analysis, not just reference counting- π§ͺ Test-Aware - Automatically excludes
Test*,Benchmark*, andExample*functions - π Library-Safe - Adapts behavior for library vs application projects
- π Conservative - When in doubt, preserves code rather than flagging it
- π Precise Locations - Shows exact file and line numbers for easy cleanup
- π¨ Smart Filtering - Configurable exclusion patterns for generated code
name: Dead Code Check
on: [push, pull_request]
jobs:
orphan-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Install Gorphanage
run: go install github.com/yourusername/gorphanage@latest
- name: Check for orphaned code
run: |
gorphanage --json . > orphans.json
if [ "$(jq '.orphaned_symbols | length' orphans.json)" -gt 0 ]; then
echo "β Orphaned code detected!"
jq '.orphaned_symbols[] | "\(.file):\(.start.line): \(.name) (\(.kind))"' orphans.json
exit 1
fi
echo "β
No orphaned code found"#!/bin/sh
# .git/hooks/pre-commit
echo "π Checking for orphaned code..."
gorphanage . || exit 1.PHONY: check-orphans
check-orphans:
@echo "π Checking for orphaned code..."
@gorphanage --json . | jq -e '.orphaned_symbols | length == 0' > /dev/null || \
(echo "β Orphaned code found. Run 'gorphanage .' for details" && exit 1)
@echo "β
No orphaned code found"| Tool | Method | Accuracy1 | Go-Aware | Config | JSON Output |
|---|---|---|---|---|---|
| Gorphanage | Reachability Analysis | 99.9% | β | β | β |
deadcode |
Reference Counting | 85% | β | β | β |
ineffassign |
Assignment Analysis | 70% | β | β | β |
grep -r "funcName" |
Text Search | 60% | β | β | β |
For complex applications with non-standard entry points:
# Future feature
entry-points:
- "github.com/myorg/myproject/pkg/plugin.Init"
- "github.com/myorg/myproject/pkg/server.Start"# Future features
max-depth: 100
timeout: "10m"
parallel: true
cache: trueWe love contributions! Here's how to get started:
- π΄ Fork the repository
- πΏ Branch from
main:git checkout -b feature/amazing-feature - π Commit your changes:
git commit -m 'Add amazing feature' - π Push to your fork:
git push origin feature/amazing-feature - π¬ Submit a Pull Request
git clone https://github.com/yourusername/gorphanage.git
cd gorphanage
make dev # Build with race detection
make test # Run tests
make lint # Run linterMIT License - see LICENSE for details.
- Go Team - For the amazing
go/packagesand AST libraries - gopls - Inspiration for the analysis approach
- Cobra & Viper - For excellent CLI framework
- Community - All the contributors and users
Made with β€οΈ for the Go community
Footnotes
-
I Completely made this up. β©