Chapter 10: Auto-clippy Integration
Chapter Status: ✅ 100% Working (8/8 examples)
Status | Count | Examples |
---|---|---|
✅ Working | 8 | All auto-clippy configurations tested |
⚠️ Not Implemented | 0 | Planned for future versions |
❌ Broken | 0 | Known issues, needs fixing |
📋 Planned | 0 | Future roadmap features |
Last updated: 2025-09-08
PMAT version: pmat 2.64.0
Test-Driven: All examples validated in tests/ch10/test_auto_clippy.sh
The Power of Automated Code Suggestions
PMAT’s auto-clippy feature brings the power of Rust’s clippy linter to any programming language, providing automated code suggestions and quality improvements across your entire codebase.
What is Auto-clippy?
Auto-clippy extends the concept of Rust’s clippy linter to provide:
- Cross-Language Support: Works with Python, JavaScript, TypeScript, Go, Java, and more
- Intelligent Suggestions: AI-powered recommendations beyond traditional linting
- Performance Optimizations: Identifies performance bottlenecks and improvements
- Security Analysis: Detects potential security issues and vulnerabilities
- Code Smell Detection: Identifies maintainability issues and anti-patterns
Why Auto-clippy?
Traditional linters check syntax and style. PMAT’s auto-clippy provides:
- Semantic Analysis: Understands code meaning, not just syntax
- Cross-Function Analysis: Identifies issues spanning multiple functions
- Performance Intelligence: Suggests algorithmic improvements
- Maintainability Focus: Prioritizes long-term code health
- Team Consistency: Enforces consistent patterns across languages
Quick Start
Enable auto-clippy in 60 seconds:
# Enable auto-clippy for current project
pmat clippy enable
# Run auto-clippy analysis
pmat clippy run
# Auto-fix safe suggestions
pmat clippy fix --safe
Installation and Configuration
Method 1: Global Configuration
# Enable auto-clippy globally
pmat config set clippy.enabled true
# Set suggestion levels
pmat config set clippy.level "all" # all, performance, security, style
# Configure languages
pmat config set clippy.languages "python,javascript,typescript,rust,go"
Method 2: Project-Specific Configuration
Create pmat.toml
in your project root:
[clippy]
enabled = true
level = "all"
languages = ["python", "javascript", "typescript", "rust", "go"]
auto_fix = false
parallel = true
[clippy.rules]
performance = true
security = true
maintainability = true
style = true
complexity = true
[clippy.thresholds]
max_complexity = 10
max_function_length = 50
max_cognitive_complexity = 15
duplicate_threshold = 0.85
[clippy.exclusions]
paths = ["tests/", "vendor/", "node_modules/", ".venv/"]
file_patterns = ["*.test.js", "*_test.py", "*.spec.ts"]
rule_exclusions = ["unused-variable"] # For test files
Method 3: IDE Integration
VS Code Extension
// .vscode/settings.json
{
"pmat.clippy.enabled": true,
"pmat.clippy.runOnSave": true,
"pmat.clippy.showInlineHints": true,
"pmat.clippy.severity": {
"performance": "warning",
"security": "error",
"style": "info"
}
}
Core Features
1. Performance Optimization Suggestions
Auto-clippy identifies performance bottlenecks:
# BEFORE: Inefficient list comprehension
def process_data(items):
result = []
for item in items:
if item.is_valid():
result.append(transform(item))
return result
Auto-clippy suggestion:
🚀 Performance: Use generator expression for memory efficiency
💡 Suggestion: Replace list comprehension with generator when possible
# AFTER: Optimized version
def process_data(items):
return (transform(item) for item in items if item.is_valid())
2. Security Vulnerability Detection
// BEFORE: Potential security issue
function executeCommand(userInput) {
const command = `ls ${userInput}`;
return exec(command);
}
Auto-clippy suggestion:
🔐 Security: Command injection vulnerability detected
💡 Suggestion: Use parameterized commands or input sanitization
⚠️ Severity: HIGH - Immediate attention required
// AFTER: Secure implementation
function executeCommand(userInput) {
const sanitized = userInput.replace(/[;&|`$]/g, '');
return exec('ls', [sanitized]);
}
3. Code Smell Detection
# BEFORE: Long parameter list
def create_user(name, email, phone, address, city, state, zip_code,
country, age, gender, preferences, notifications):
# Implementation...
Auto-clippy suggestion:
🏗️ Architecture: Long parameter list detected (12 parameters)
💡 Suggestion: Consider using a configuration object or builder pattern
📊 Complexity: High - Reduces maintainability
# AFTER: Improved design
@dataclass
class UserConfig:
name: str
email: str
phone: str
address: AddressInfo
demographics: Demographics
preferences: UserPreferences
def create_user(config: UserConfig):
# Implementation...
4. Algorithmic Improvements
# BEFORE: Inefficient search
def find_user(users, target_id):
for user in users:
if user.id == target_id:
return user
return None
Auto-clippy suggestion:
🔍 Algorithm: Linear search in potentially large collection
💡 Suggestion: Consider using dictionary lookup for O(1) access
📈 Impact: Performance improvement for large datasets
# AFTER: Optimized lookup
class UserRegistry:
def __init__(self, users):
self.users_by_id = {user.id: user for user in users}
def find_user(self, target_id):
return self.users_by_id.get(target_id)
Advanced Configuration
Custom Rules
Create custom auto-clippy rules:
# .pmat/clippy-rules.yaml
rules:
- name: "avoid-nested-loops"
pattern: "for.*in.*:\n.*for.*in.*:"
message: "Nested loops detected - consider vectorization"
severity: "warning"
language: "python"
- name: "async-without-await"
pattern: "async def \\w+\\([^)]*\\):\\s*(?!.*await)"
message: "Async function without await - consider making sync"
severity: "info"
language: "python"
- name: "magic-numbers"
pattern: "\\d{2,}"
exclude_patterns: ["test_", "_test"]
message: "Magic number detected - consider using named constant"
severity: "style"
languages: ["python", "javascript", "java"]
# Team-specific rules
team_rules:
- name: "max-class-methods"
threshold: 15
message: "Class has too many methods - consider splitting"
- name: "database-connection-leak"
pattern: "connect\\(.*\\).*(?!.*close\\(\\))"
message: "Potential connection leak - ensure proper cleanup"
severity: "error"
Language-Specific Configuration
[clippy.python]
enable_type_hints = true
enforce_docstrings = true
max_line_length = 100
prefer_f_strings = true
[clippy.javascript]
enforce_strict_mode = true
prefer_const = true
no_var_declarations = true
async_await_over_promises = true
[clippy.rust]
clippy_integration = true
custom_lints = ["pedantic", "nursery"]
allow_unsafe = false
[clippy.go]
gofmt_style = true
error_handling_required = true
interface_segregation = true
[clippy.typescript]
strict_null_checks = true
no_any_types = true
prefer_readonly = true
Real-World Examples
Example 1: Refactoring Legacy Code
# Legacy Python code with multiple issues
def process_orders(orders):
result = []
for order in orders:
if order != None:
if order.status == "pending":
if order.amount > 0:
if order.customer_id != None:
processed_order = {}
processed_order["id"] = order.id
processed_order["amount"] = order.amount * 1.1
processed_order["tax"] = order.amount * 0.08
result.append(processed_order)
return result
Auto-clippy analysis:
🔍 Auto-clippy Analysis Results:
🏗️ [ARCHITECTURE] Deep nesting detected (4 levels)
💡 Suggestion: Use early returns and guard clauses
🐍 [PYTHON] Non-Pythonic None comparison
💡 Suggestion: Use 'is not None' instead of '!= None'
🔢 [PERFORMANCE] Magic numbers detected (1.1, 0.08)
💡 Suggestion: Extract to named constants
📊 [MAINTAINABILITY] Primitive obsession - using dict instead of dataclass
💡 Suggestion: Create ProcessedOrder dataclass
⚡ [PERFORMANCE] List append in loop - consider list comprehension
💡 Suggestion: Use functional approach for better performance
Auto-clippy refactored version:
from dataclasses import dataclass
from typing import List, Optional
TAX_RATE = 0.08
PROCESSING_FEE = 1.1
@dataclass
class ProcessedOrder:
id: str
amount: float
tax: float
def process_orders(orders: List[Order]) -> List[ProcessedOrder]:
"""Process pending orders with tax and fees."""
return [
ProcessedOrder(
id=order.id,
amount=order.amount * PROCESSING_FEE,
tax=order.amount * TAX_RATE
)
for order in orders
if (order is not None
and order.status == "pending"
and order.amount > 0
and order.customer_id is not None)
]
Example 2: JavaScript Performance Optimization
// Suboptimal JavaScript code
function analyzeUserBehavior(users) {
const results = [];
users.forEach(function(user) {
const sessions = getAllSessions(user.id); // N+1 query problem
const totalTime = 0;
sessions.forEach(function(session) {
totalTime += session.duration;
});
const avgTime = totalTime / sessions.length;
if (avgTime > 300) {
results.push({
userId: user.id,
avgSessionTime: avgTime,
category: avgTime > 600 ? 'high' : 'medium'
});
}
});
return results.sort(function(a, b) {
return b.avgSessionTime - a.avgSessionTime;
});
}
Auto-clippy optimized version:
async function analyzeUserBehavior(users) {
// Batch load all sessions to avoid N+1 queries
const allSessions = await batchGetSessions(users.map(u => u.id));
return users
.map(user => {
const userSessions = allSessions[user.id] || [];
const totalTime = userSessions.reduce((sum, s) => sum + s.duration, 0);
const avgTime = totalTime / (userSessions.length || 1);
return { user, avgTime };
})
.filter(({ avgTime }) => avgTime > 300)
.map(({ user, avgTime }) => ({
userId: user.id,
avgSessionTime: avgTime,
category: avgTime > 600 ? 'high' : 'medium'
}))
.sort((a, b) => b.avgSessionTime - a.avgSessionTime);
}
CI/CD Integration
GitHub Actions
# .github/workflows/auto-clippy.yml
name: Auto-clippy Analysis
on:
pull_request:
types: [opened, synchronize]
push:
branches: [main, develop]
jobs:
clippy-analysis:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for better analysis
- name: Install PMAT
run: |
cargo install pmat
pmat --version
- name: Run auto-clippy analysis
run: |
pmat clippy run --format json > clippy-results.json
pmat clippy run --format markdown > clippy-report.md
- name: Check for critical issues
run: |
CRITICAL_COUNT=$(jq '.violations | map(select(.severity == "error")) | length' clippy-results.json)
echo "Critical issues found: $CRITICAL_COUNT"
if [ "$CRITICAL_COUNT" -gt 0 ]; then
echo "❌ Critical auto-clippy violations detected!"
jq '.violations | map(select(.severity == "error"))' clippy-results.json
exit 1
fi
- name: Auto-fix safe issues
run: |
pmat clippy fix --safe --dry-run > auto-fixes.log
if [ -s auto-fixes.log ]; then
echo "🔧 Safe auto-fixes available:"
cat auto-fixes.log
fi
- name: Comment PR with results
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const results = JSON.parse(fs.readFileSync('clippy-results.json', 'utf8'));
const report = fs.readFileSync('clippy-report.md', 'utf8');
const summary = {
total: results.violations.length,
errors: results.violations.filter(v => v.severity === 'error').length,
warnings: results.violations.filter(v => v.severity === 'warning').length,
suggestions: results.violations.filter(v => v.severity === 'info').length
};
const comment = `## 🚀 Auto-clippy Analysis Results
**Summary**: ${summary.total} total suggestions
- 🚨 Errors: ${summary.errors}
- ⚠️ Warnings: ${summary.warnings}
- 💡 Suggestions: ${summary.suggestions}
${report}
<details>
<summary>📊 Detailed Results</summary>
\`\`\`json
${JSON.stringify(results, null, 2)}
\`\`\`
</details>`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
Pre-commit Hook Integration
#!/bin/bash
# .git/hooks/pre-commit with auto-clippy
echo "🚀 Running auto-clippy analysis..."
# Run clippy analysis on staged files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
if [ -z "$STAGED_FILES" ]; then
echo "No staged files to analyze"
exit 0
fi
# Create temporary directory for analysis
TEMP_DIR=$(mktemp -d)
trap "rm -rf $TEMP_DIR" EXIT
# Copy staged files to temp directory
for file in $STAGED_FILES; do
if [ -f "$file" ]; then
mkdir -p "$TEMP_DIR/$(dirname "$file")"
cp "$file" "$TEMP_DIR/$file"
fi
done
# Run auto-clippy on staged files
cd "$TEMP_DIR"
pmat clippy run --format json > clippy-results.json
# Check for critical issues
ERRORS=$(jq '.violations | map(select(.severity == "error")) | length' clippy-results.json 2>/dev/null || echo "0")
if [ "$ERRORS" -gt 0 ]; then
echo "❌ Auto-clippy found $ERRORS critical issue(s):"
jq -r '.violations[] | select(.severity == "error") | " \(.file):\(.line) - \(.message)"' clippy-results.json
echo ""
echo "Fix these issues or use 'git commit --no-verify' to bypass"
exit 1
fi
# Show warnings but don't block
WARNINGS=$(jq '.violations | map(select(.severity == "warning")) | length' clippy-results.json 2>/dev/null || echo "0")
if [ "$WARNINGS" -gt 0 ]; then
echo "⚠️ Auto-clippy found $WARNINGS warning(s):"
jq -r '.violations[] | select(.severity == "warning") | " \(.file):\(.line) - \(.message)"' clippy-results.json
fi
echo "✅ Auto-clippy analysis passed"
Performance Tuning
Large Codebase Optimization
# pmat.toml - Performance settings
[clippy.performance]
parallel_analysis = true
max_threads = 8
cache_enabled = true
cache_duration = 3600 # 1 hour
incremental_analysis = true # Only analyze changed files
batch_size = 100 # Process files in batches
[clippy.optimization]
skip_node_modules = true
skip_vendor = true
skip_generated = true
skip_test_files = false
# Memory management
max_memory_mb = 2048
gc_frequency = 1000 # Run GC every 1000 files
# File size limits
max_file_size_mb = 10
skip_binary_files = true
Caching Strategy
# Enable persistent caching
pmat config set clippy.cache.enabled true
pmat config set clippy.cache.directory "$HOME/.pmat/clippy-cache"
pmat config set clippy.cache.max_size_gb 5
# Cache maintenance
pmat clippy cache clean # Clean expired cache entries
pmat clippy cache clear # Clear all cache
pmat clippy cache stats # Show cache statistics
Troubleshooting
Common Issues
1. High Memory Usage
# pmat.toml - Memory optimization
[clippy.memory]
max_heap_size = "4g"
parallel_threads = 4 # Reduce from default 8
batch_processing = true
stream_analysis = true # Don't load entire files into memory
2. Slow Analysis Speed
# Profile analysis performance
pmat clippy run --profile --verbose
# Use incremental mode
pmat clippy run --incremental
# Skip non-essential rules
pmat clippy run --rules="security,performance" --skip="style"
3. False Positives
# .pmat/clippy-ignore.yaml
ignore_rules:
- rule: "unused-variable"
files: ["*_test.py", "test_*.py"]
reason: "Test fixtures may have unused variables"
- rule: "magic-numbers"
lines: ["src/constants.py:10-50"]
reason: "Mathematical constants are acceptable"
- rule: "long-parameter-list"
functions: ["legacy_api_handler"]
reason: "Legacy API compatibility required"
4. Language-Specific Issues
[clippy.python.rules]
# Disable specific rules for Python
disable = ["line-too-long"] # Using black formatter
max_complexity = 15 # Higher threshold for Python
[clippy.javascript.rules]
# JavaScript-specific configuration
allow_console_log = true # For debugging
prefer_arrow_functions = false # Mixed team preference
Best Practices
1. Gradual Adoption
# Week 1: Information only
pmat clippy run --severity="error" --report-only
# Week 2: Block on errors
pmat clippy run --severity="error" --fail-on-error
# Week 3: Add warnings
pmat clippy run --severity="warning" --fail-on-error
# Month 2: Full analysis
pmat clippy run --severity="all" --fail-on-error
2. Team Configuration
# team-clippy-config.yaml
team_standards:
max_function_length: 30
max_complexity: 8
enforce_type_hints: true
require_docstrings: true
code_review_integration:
auto_comment_prs: true
block_on_critical: true
suggest_fixes: true
training_mode:
explain_violations: true
show_examples: true
suggest_resources: true
3. Continuous Improvement
# scripts/track-clippy-metrics.py
import json
import subprocess
from datetime import datetime
def collect_clippy_metrics():
"""Collect auto-clippy metrics over time."""
result = subprocess.run(
["pmat", "clippy", "run", "--format", "json"],
capture_output=True,
text=True
)
if result.returncode == 0:
data = json.loads(result.stdout)
metrics = {
"timestamp": datetime.now().isoformat(),
"total_violations": len(data["violations"]),
"by_severity": {
"error": len([v for v in data["violations"] if v["severity"] == "error"]),
"warning": len([v for v in data["violations"] if v["severity"] == "warning"]),
"info": len([v for v in data["violations"] if v["severity"] == "info"]),
},
"by_category": {},
"files_analyzed": data.get("files_count", 0),
"analysis_time": data.get("duration_ms", 0)
}
# Track by category
for violation in data["violations"]:
category = violation.get("category", "unknown")
metrics["by_category"][category] = metrics["by_category"].get(category, 0) + 1
# Append to history
with open(".metrics/clippy-history.jsonl", "a") as f:
f.write(json.dumps(metrics) + "\n")
return metrics
return None
if __name__ == "__main__":
metrics = collect_clippy_metrics()
if metrics:
print(f"📊 Auto-clippy metrics collected: {metrics['total_violations']} violations")
else:
print("❌ Failed to collect metrics")
Summary
PMAT’s auto-clippy feature provides:
- Intelligent Code Analysis: Beyond traditional linting
- Cross-Language Support: Consistent quality across technologies
- Performance Optimization: Automated performance improvements
- Security Analysis: Vulnerability detection and prevention
- Team Consistency: Unified code standards and practices
With auto-clippy, your codebase continuously improves with every analysis, maintaining high quality standards automatically.