Skip to content

Instantly share code, notes, and snippets.

@eiskalteschatten
Created August 18, 2025 06:50
Show Gist options
  • Select an option

  • Save eiskalteschatten/1b8150bf9bd1c90ddc4cd4a2f3c1a4a2 to your computer and use it in GitHub Desktop.

Select an option

Save eiskalteschatten/1b8150bf9bd1c90ddc4cd4a2f3c1a4a2 to your computer and use it in GitHub Desktop.
A Python script for parsing C++ files and making fun of older code generated by GPT-5
#!/usr/bin/env python3
"""
C++ Code Roast Master (Play-it-Nice Edition)
Recursively scans C++ files and adds humorous comments about outdated patterns.
Focuses on the code, not the coder.
"""
import os
import re
import argparse
from pathlib import Path
from typing import List, Tuple
CPP_EXTENSIONS = {'.cpp', '.cxx', '.cc', '.c++', '.hpp', '.hxx', '.h++', '.hh', '.h'}
ROASTS = [
# Memory management
(re.compile(r'\bnew\b'), "// Retro alert: raw 'new' detected. Consider RAII or smart pointers (std::unique_ptr/std::make_unique)."),
(re.compile(r'\bdelete(\s*\[\])?\b'), "// Manual 'delete' spotted. Modern C++ prefers RAII and smart pointers."),
(re.compile(r'\b(malloc|calloc|realloc|free)\s*\('), "// C-style memory mgmt in C++ detected. Prefer containers, smart pointers, or RAII."),
# nullptr vs NULL
(re.compile(r'\bNULL\b'), "// Using NULL? nullptr would be safer and clearer in modern C++."),
# C-style casts
(re.compile(r'\(\s*(?:unsigned|signed|short|long|char|int|float|double|bool|void|size_t|u?int(?:8|16|32|64)_t|[A-Za-z_]\w*(?:::[A-Za-z_]\w*)*)\s*\)\s*'),
"// C-style cast detected. static_cast/reinterpret_cast/const_cast are more explicit."),
# Deprecated/removed keywords/types
(re.compile(r'\bregister\b'), "// 'register' keyword spotted. Compilers handle this now—no need to hint."),
(re.compile(r'\b(?:std::)?auto_ptr\s*<'), "// std::auto_ptr is deprecated/removed. Use std::unique_ptr instead."),
# Old-school I/O and unsafe functions
(re.compile(r'\bprintf\s*\('), "// printf in C++ code—consider std::ostream or fmt for type safety and ergonomics."),
(re.compile(r'\bscanf\s*\('), "// scanf found. Safer alternatives (iostreams or fmt) are recommended."),
(re.compile(r'\bgets\s*\('), "// gets() is dangerous and removed from standards. Avoid at all costs."),
# Macros for constants
(re.compile(r'^\s*#\s*define\s+[A-Z][A-Z0-9_]*\s+[0-9]+(?:\s|$)'), "// Macro constant detected. Prefer const/constexpr or enum class.", re.MULTILINE),
# main signature
(re.compile(r'\bvoid\s+main\s*\('), "// Non-standard 'void main()' detected. Use 'int main()' per the standard."),
# char* strings
(re.compile(r'\bchar\s*\*\s*\w+\s*(?:=|;|,|\))'), "// Raw char* string usage—std::string is safer and easier to manage."),
# Old-style loops over .size()
(re.compile(r'for\s*\(\s*[^;]+;\s*[^;]+\.size\s*\(\s*\)\s*;[^)]*\)'),
"// Classic index-based loop over .size(). Consider a range-based for or iterators."),
# Function pointer syntax
(re.compile(r'\w+\s*\(\s*\*\s*\w+\s*\)\s*\('), "// Function pointer syntax detected. std::function or auto lambdas may be clearer."),
# make_pair + push_back
(re.compile(r'\.push_back\s*\(\s*std::make_pair\s*\('), "// push_back(make_pair(...)) found—emplace_back({}) can be cleaner and faster."),
]
HEADER_EXTENSIONS = {'.h', '.hpp', '.hxx', '.h++', '.hh'}
def find_cpp_files(directory: str) -> List[Path]:
files: List[Path] = []
for root, _, fs in os.walk(directory):
for f in fs:
p = Path(root) / f
if p.suffix.lower() in CPP_EXTENSIONS:
files.append(p)
return files
def analyze_file(file_path: Path) -> List[Tuple[int, str]]:
issues: List[Tuple[int, str]] = []
try:
with open(file_path, 'r', encoding='utf-8', errors='ignore') as fh:
lines = fh.readlines()
text = ''.join(lines)
# Line-based patterns
for i, line in enumerate(lines, start=1):
roasted_this_line = False
for pat in ROASTS:
if len(pat) == 3:
pattern, roast, _ = pat
else:
pattern, roast = pat
if pattern.search(line):
issues.append((i, roast))
roasted_this_line = True
break
if roasted_this_line:
continue
# Header-only check: using namespace std; (only roast in headers)
if file_path.suffix.lower() in HEADER_EXTENSIONS and re.search(r'^\s*using\s+namespace\s+std\s*;\s*$', line):
issues.append((i, "// 'using namespace std;' in a header can cause ODR/name pollution. Prefer explicit qualifiers or using declarations locally."))
# Optional: include guard nudge (headers only)
if file_path.suffix.lower() in HEADER_EXTENSIONS:
if re.search(r'^\s*#\s*ifndef\s+\w+\s*$[\s\S]*?^\s*#\s*define\s+\w+\s*$', text, re.MULTILINE):
# Place a single gentle note at the first line
first_line = 1
issues.append((first_line, "// Include guards detected. #pragma once is widely supported and simpler (optional)."))
except Exception as e:
print(f"Error analyzing {file_path}: {e}")
return issues
def add_roast_comments(file_path: Path, dry_run: bool = True) -> int:
issues = analyze_file(file_path)
if not issues:
return 0
try:
with open(file_path, 'r', encoding='utf-8', errors='ignore') as fh:
lines = fh.readlines()
# Insert comments above the target lines (reverse order to keep offsets stable)
for line_no, roast in sorted(issues, key=lambda x: x[0], reverse=True):
insert_at = max(0, line_no - 1)
lines.insert(insert_at, roast + "\n")
if dry_run:
print(f"[DRY RUN] Would add {len(issues)} comments to {file_path}")
else:
with open(file_path, 'w', encoding='utf-8') as fh:
fh.writelines(lines)
print(f"Updated {file_path} with {len(issues)} comments.")
return len(issues)
except Exception as e:
print(f"Error updating {file_path}: {e}")
return 0
def generate_report(directory: str) -> int:
files = find_cpp_files(directory)
total_issues = 0
print(f"Scanning {len(files)} C++ files in '{directory}'...\n")
for f in files:
issues = analyze_file(f)
if issues:
print(f"{f}: {len(issues)} potential modernizations")
for line_no, roast in issues[:10]:
print(f" line {line_no}: {roast}")
if len(issues) > 10:
print(f" ... and {len(issues)-10} more")
total_issues += len(issues)
print(f"\nSummary: {total_issues} suggestions across {len(files)} files.")
return total_issues
def main():
parser = argparse.ArgumentParser(description="Roast outdated C++ patterns with playful, constructive comments.")
parser.add_argument("directory", help="Directory to scan")
parser.add_argument("--report-only", "-r", action="store_true", help="Only print a report; do not modify files")
parser.add_argument("--no-dry-run", action="store_true", help="Actually write comments to files")
parser.add_argument("--fail-on-find", action="store_true", help="Exit non-zero if any issues are found (useful for CI)")
args = parser.parse_args()
target = args.directory
if not os.path.isdir(target):
print(f"Not a directory: {target}")
return 2
if args.report_only:
total = generate_report(target)
return 1 if args.fail_on_find and total > 0 else 0
dry_run = not args.no_dry_run
files = find_cpp_files(target)
print(f"{'DRY RUN' if dry_run else 'WRITE MODE'}: Processing {len(files)} files...\n")
touched_files = 0
total_comments = 0
for f in files:
added = add_roast_comments(f, dry_run=dry_run)
if added > 0:
touched_files += 1
total_comments += added
print(f"\nDone. {'Would add' if dry_run else 'Added'} {total_comments} comments across {touched_files} files.")
if args.fail_on_find and total_comments > 0:
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())
@eiskalteschatten
Copy link
Author

eiskalteschatten commented Aug 18, 2025

Usage:

# Report only
python cpp_roast_master_gpt5.py /path/to/project --report-only

# Dry run (default)
python cpp_roast_master_gpt5.py /path/to/project

# Apply changes
python cpp_roast_master_gpt5.py /path/to/project --no-dry-run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment