#!/usr/bin/env python3 """ Fix Qt6 API compatibility issues in training_area_telegrams.cpp Handles two struct patterns: - Pattern A: private m_* members with getter methods (Header, BatteryState) - Pattern B: public direct members (most other structs) """ import re from pathlib import Path cpp_file = Path('/home/torsten/swy/sandbox/qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/Proxies/TrainingAreaBase/training_area_telegrams.cpp') h_file = Path('/home/torsten/swy/sandbox/qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/Proxies/TrainingAreaBase/training_area_telegrams.h') # Parse header to determine struct member patterns def parse_struct_members(header_content): """Returns dict: struct_name -> {'has_m_prefix': bool, 'members': list, 'getters': dict}""" structs = {} # Match struct definitions struct_pattern = r'^struct\s+(\w+)(?:\s*:[^{\n]+)?\s*\{(.*?)^\};' for match in re.finditer(struct_pattern, header_content, re.MULTILINE | re.DOTALL): struct_name = match.group(1) body = match.group(2) # Find member variables (lines with type and name, not functions) members = [] getters = {} # member_name -> getter_name has_m_prefix = False for line in body.split('\n'): line = line.strip() # Skip empty lines, comments, functions, static, etc. if not line or line.startswith('//') or line.startswith('static') or \ line.startswith('virtual') or '(' in line or line.startswith('}'): continue # Match member variable declarations member_match = re.match(r'(?:mutable\s+)?(?:const\s+)?(\w+(?:\s*<[^>]+>)?)\s+(\w+)(?:\s*=\s*[^;]+)?;', line) if member_match: member_name = member_match.group(2) members.append(member_name) if member_name.startswith('m_'): has_m_prefix = True # Getter name is member without m_ prefix getter_name = member_name[2:] getters[getter_name] = member_name if members: structs[struct_name] = { 'has_m_prefix': has_m_prefix, 'members': members, 'getters': getters } return structs # Read files with open(h_file, 'r') as f: header_content = f.read() with open(cpp_file, 'r') as f: cpp_content = f.read() # Parse struct patterns structs = parse_struct_members(header_content) print(f"Found {len(structs)} structs") for name, info in list(structs.items())[:10]: print(f" {name}: m_prefix={info['has_m_prefix']}, getters={info['getters']}") # Fix fromJson functions def fix_fromJson(content, structs): """Fix fromJson to assign to correct member (m_* or direct)""" lines = content.split('\n') new_lines = [] for line in lines: # Pattern: get(obj, ..., ret.member); match = re.search(r'get\(obj,\s*[^,]+,\s*ret\.(\w+)\);', line) if match: member_used = match.group(1) # Check if this is a getter name that should be a member for struct_name, info in structs.items(): if info['has_m_prefix'] and member_used in info['getters']: # This is a getter name, should be member name correct_member = info['getters'][member_used] line = line.replace(f'ret.{member_used});', f'ret.{correct_member});') print(f" fromJson fix: ret.{member_used} -> ret.{correct_member}") break new_lines.append(line) return '\n'.join(new_lines) # Fix toJson functions def fix_toJson(content, structs): """Fix toJson to use Qt6-compatible QJsonObject{{}} syntax with correct member access""" lines = content.split('\n') new_lines = [] in_toJson = False current_struct = None brace_count = 0 for line in lines: # Detect toJson function start toJson_match = re.match(r'QJsonObject\s+(\w+)::toJson\(\)\s*const\s*\{', line) if toJson_match: in_toJson = True current_struct = toJson_match.group(1) brace_count = 1 new_lines.append(line) continue if in_toJson: # Count braces brace_count += line.count('{') - line.count('}') # Fix member access in toJson (convert to method calls for m_* structs) if current_struct and current_struct in structs: info = structs[current_struct] if info['has_m_prefix']: # Need to convert member references to method calls for getter_name, member_name in info['getters'].items(): # Match standalone member references (not already method calls) # Be careful not to match inside strings or comments pattern = rf'\b{getter_name}\b(?!\s*\()' if re.search(pattern, line): line = re.sub(pattern, f'{getter_name}()', line) print(f" toJson fix: {getter_name} -> {getter_name}()") # Fix QJsonObject initializer syntax: QJsonObject({{ -> QJsonObject{{ if 'QJsonObject({' in line: line = line.replace('QJsonObject({', 'QJsonObject{{') print(f" toJson syntax: QJsonObject({{ -> QJsonObject{{") # Fix closing: }}); -> }}); if re.search(r'\}\}\);\s*$', line): line = re.sub(r'\}\}\);\s*$', '}});', line) if brace_count == 0: in_toJson = False current_struct = None new_lines.append(line) return '\n'.join(new_lines) # Apply fixes print("\n=== Fixing fromJson ===") cpp_content = fix_fromJson(cpp_content, structs) print("\n=== Fixing toJson ===") cpp_content = fix_toJson(cpp_content, structs) # Write back with open(cpp_file, 'w') as f: f.write(cpp_content) print(f"\n✓ Fixed {cpp_file}")