#!/usr/bin/env python3 """ Inlines method bodies from a .cpp file into the corresponding .h file. Scans the .cpp for method definitions matching "ClassName::MethodName(...)" and extracts the body (from opening '{' to closing '}'). Then reads the .h file and replaces matching declaration-only lines (ending with ';') with the declaration (minus ';') followed by the body. Usage: python3 tools/inline-methods.py Outputs the new header to stdout. """ import sys import re def extract_bodies(cpp_lines): """Extract method bodies from cpp file. Returns dict of (ClassName, MethodName) -> list of body lines (from '{' to '}').""" bodies = {} i = 0 while i < len(cpp_lines): # Match lines like: void UMCPHandler_Foo::Handle(...) m = re.match(r'^\S.*?\s+(\w+)::(\w+)\s*\(', cpp_lines[i]) if not m: i += 1 continue class_name = m.group(1) method_name = m.group(2) # Skip forward to the line containing '{' while i < len(cpp_lines) and '{' not in cpp_lines[i]: i += 1 if i >= len(cpp_lines): break # Collect from '{' to matching '}' brace_depth = 0 body_lines = [] while i < len(cpp_lines): line = cpp_lines[i] brace_depth += line.count('{') - line.count('}') body_lines.append(line) i += 1 if brace_depth == 0: break bodies[(class_name, method_name)] = body_lines return bodies def inline_into_header(h_lines, bodies): """Replace declaration-only methods in header with inlined bodies.""" output = [] for line in h_lines: # Match declaration lines like: # \tvirtual void Handle(const FJsonObject* Json, ...) override; # Capture: indent, everything before method name, method name, rest up to ';' m = re.match(r'^(\t+)(.*?\s+)(\w+)\s*(\(.*\)\s*(?:const\s*)?(?:override\s*)?);', line) if m: indent = m.group(1) prefix = m.group(2) # e.g. "virtual void " method_name = m.group(3) params = m.group(4) # e.g. "(const FJsonObject* Json, FJsonObject* Result) override" # Find which class we're inside class_name = None for prev in reversed(output): cm = re.match(r'^class\s+(\w+)\s*', prev) if cm: class_name = cm.group(1) break if class_name and (class_name, method_name) in bodies: body_lines = bodies[(class_name, method_name)] # Emit the declaration as a definition (replace ';' with body) output.append(f'{indent}{prefix}{method_name}{params}') for bline in body_lines: if bline.strip(): output.append(indent + bline) else: output.append('') continue output.append(line) return output def main(): if len(sys.argv) != 3: print(f"Usage: {sys.argv[0]} ", file=sys.stderr) sys.exit(1) h_path = sys.argv[1] cpp_path = sys.argv[2] with open(cpp_path) as f: cpp_lines = [line.rstrip('\n') for line in f] with open(h_path) as f: h_lines = [line.rstrip('\n') for line in f] bodies = extract_bodies(cpp_lines) if not bodies: print("No method bodies found in cpp file.", file=sys.stderr) sys.exit(1) print(f"Found {len(bodies)} method(s) to inline:", file=sys.stderr) for (cls, method) in bodies: print(f" {cls}::{method}", file=sys.stderr) result = inline_into_header(h_lines, bodies) for line in result: print(line) if __name__ == '__main__': main()