Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .goperf.yml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# goperf configuration file
# Place this file as .goperf.yml in your project root.

# rules: list of rule categories to run (use "all" for everything)
rules:
- algorithm
- database
- concurrency

# ignore_paths: path substrings to skip during file collection
ignore_paths:
- vendor
- testdata
- generated

# fail_on: exit 1 if issues at this level or higher (low, medium, high, critical)
fail_on: high

# format: output format (console, json, diff)
format: console

# context: lines of context to show around issues
context: 3

# verbose: show verbose output
verbose: false
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ All notable changes to goperf will be documented in this file.

- Output formats: `console`, `json`, `diff`
- CI integration with `--fail-on` threshold
- Auto-fix suggestions with `--fix` and `--dry-run`
- Fix suggestions with `--suggest` and `--dry-run`
- Ignore comments: `// perf:ignore`, `// perf:ignore-start/end`
- Smart detection to reduce false positives:
- Recognizes prepared statements in database loops
Expand All @@ -28,7 +28,7 @@ All notable changes to goperf will be documented in this file.
### Dogfooding Results
Ran goperf on itself:
- **Before**: 147 issues (36 medium, 111 low)
- **Fixed**: 34 issues (slice preallocation, strings.Builder, map hints)
- **Addressed**: 34 issues (slice preallocation, strings.Builder, map hints)
- **After**: 113 issues (3 medium, 110 low)

The 3 remaining medium issues are intentional AST traversal patterns, and the 110 low issues are benchmark suggestions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ goperf/
│ ├── allocation.go # Memory allocation patterns
│ ├── database.go # N+1 query detection
│ └── ...
├── fixer/ # Auto-fix suggestions
├── fixer/ # Fix suggestions
├── reporter/ # Output formatters (console, JSON)
└── examples/ # Example problematic code
```
Expand Down
39 changes: 33 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ goperf --rules=algorithm,database ./...

# CI mode - fail on high severity issues
goperf --fail-on=high --format=json ./...

# Show fix suggestions (does not modify files)
goperf --suggest ./...
```

## What It Detects
Expand Down Expand Up @@ -125,16 +128,38 @@ goperf --fail-on=critical ./...

## Configuration

### Config File

`goperf` will load `.goperf.yml` from the current directory. CLI flags override config values.

Example:

```yaml
rules:
- algorithm
- database
ignore_paths:
- vendor
- testdata
fail_on: high
format: console
context: 3
verbose: false
```

See `.goperf.yml.example` for a fully documented template.

### Command Line Flags

| Flag | Default | Description |
|------|---------|-------------|
| `--rules` | `all` | Rules to run: `algorithm,allocation,database,concurrency,io,cache` |
| `--format` | `console` | Output format: `console`, `json` |
| `--rules` | `all` | Rules to run: `algorithm,allocation,database,concurrency,io,cache,context,memory,benchmark` |
| `--format` | `console` | Output format: `console`, `json`, `diff` |
| `--fail-on` | - | Exit code 1 if issues at this level: `low,medium,high,critical` |
| `--context` | `3` | Lines of code context to show |
| `--ignore` | - | Comma-separated paths to ignore |
| `--verbose` | `false` | Show verbose output |
| `--suggest` | `false` | Show fix suggestions (does not modify files) |

## Severity Levels

Expand Down Expand Up @@ -197,15 +222,15 @@ $ goperf ./...
╰───────────────────────────────────────────────────────────────────╯
```

**We fixed all 34 actionable issues:**
**We manually addressed 34 actionable issues based on suggestions:**

| Issue Type | Count | Fix Applied |
|------------|-------|-------------|
| Unpreallocated slices | 31 | `make([]T, 0, N)` with capacity hints |
| String concat in loops | 2 | `strings.Builder` |
| Map without size hint | 1 | `make(map[K]V, size)` |

**After fixes:**
**After applying those changes:**
```
$ goperf ./...
╭───────────────────────────────────────────────────────────────────╮
Expand All @@ -217,7 +242,7 @@ The remaining 113 issues are:
- **3 medium**: Nested loops for AST traversal (intentional, not O(n²) on data)
- **110 low**: "Consider adding benchmarks" suggestions

This demonstrates that `goperf` finds real issues - including in itself - and that fixing them is straightforward.
This demonstrates that `goperf` finds real issues - including in itself - and that acting on suggestions is straightforward.

## Contributing

Expand All @@ -229,7 +254,7 @@ Areas we'd love help with:
- [ ] False positive reduction
- [ ] IDE integrations (VS Code, GoLand)
- [ ] Benchmark integration
- [ ] Auto-fix suggestions
- [ ] Fix suggestions

Please read our [Code of Conduct](CODE_OF_CONDUCT.md) before contributing.

Expand All @@ -246,3 +271,5 @@ MIT License - see [LICENSE](LICENSE) for details.
Inspired by the philosophy that **preventing performance problems is better than fixing them**.

Built with Go's excellent `go/ast` package for static analysis.

Note: automatic code fixing is not yet implemented. `goperf` only produces suggestions for manual changes.
6 changes: 3 additions & 3 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ We appreciate responsible disclosure and will:

goperf is designed with security in mind:

1. **Read-only by default**: Only analyzes code, doesn't modify unless `--fix` is used
1. **Read-only by default**: Only analyzes code and does not modify files (automatic fixing is not implemented)
2. **Path validation**: Refuses to operate outside the current working directory
3. **Symlink protection**: Validates symlinks don't escape the working directory
4. **Resource limits**: Caps file count, file size, and directory depth
5. **No network access**: Operates entirely locally

## Best Practices for Users

1. **Review before fixing**: Always use `--dry-run` before `--fix`
2. **Trust but verify**: Review auto-fix suggestions before applying
1. **Review suggestions**: Use `--suggest` to review proposed changes
2. **Trust but verify**: Treat suggestions as guidance and apply manually
3. **Keep updated**: Use the latest version for security fixes
38 changes: 38 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package config

import (
"fmt"
"os"

"gopkg.in/yaml.v3"
)

// Config defines .goperf.yml settings.
type Config struct {
Rules []string `yaml:"rules"`
IgnorePaths []string `yaml:"ignore_paths"`
FailOn string `yaml:"fail_on"`
Format string `yaml:"format"`
Context int `yaml:"context"`
Verbose bool `yaml:"verbose"`
}

// LoadConfig reads .goperf.yml from the current working directory.
func LoadConfig() (Config, error) {
const configFile = ".goperf.yml"

data, err := os.ReadFile(configFile)
if err != nil {
if os.IsNotExist(err) {
return Config{}, nil
}
return Config{}, fmt.Errorf("read %s: %w", configFile, err)
}

var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
return Config{}, fmt.Errorf("parse %s: %w", configFile, err)
}

return cfg, nil
}
Loading
Loading