247 lines
11 KiB
Python
Executable File
247 lines
11 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Add logger initialization to constructors in Qt6 .cpp files.
|
|
Pattern: m_logger(NGL::NGLLoggerBootstrap::getLogger())
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Paths
|
|
SCRIPT_DIR = Path(__file__).parent
|
|
QT6_BASE = SCRIPT_DIR / "qt6-after/qt6-migrated-legatus"
|
|
|
|
# Qt classes that shouldn't have logger initialization
|
|
QT_CLASSES = {
|
|
'QObject', 'QWidget', 'QMainWindow', 'QDialog', 'QMessageBox',
|
|
'QAbstractTableModel', 'QAbstractListModel', 'QAbstractItemModel',
|
|
'QTreeView', 'QTableView', 'QListView', 'QComboBox',
|
|
'QTcpSocket', 'QTcpServer', 'QUdpSocket', 'QTimer', 'QThread',
|
|
'QSettings', 'QFileInfo', 'QDir', 'QFile', 'QTextStream',
|
|
'QDomElement', 'QDomDocument', 'QXmlStreamReader', 'QXmlStreamWriter',
|
|
'QPainter', 'QPixmap', 'QImage', 'QIcon', 'QBrush', 'QPen',
|
|
'QMenu', 'QMenuBar', 'QToolBar', 'QStatusBar', 'QAction',
|
|
'QVBoxLayout', 'QHBoxLayout', 'QGridLayout', 'QFormLayout',
|
|
'QPushButton', 'QLabel', 'QLineEdit', 'QTextEdit', 'QPlainTextEdit',
|
|
'QCheckBox', 'QRadioButton', 'QSpinBox', 'QDoubleSpinBox',
|
|
'QSlider', 'QScrollBar', 'QProgressBar', 'QTabWidget',
|
|
'QStackedWidget', 'QSplitter', 'QScrollArea', 'QFrame',
|
|
'QGroupBox', 'QToolBox', 'QWizard', 'QFontDialog', 'QColorDialog',
|
|
'QFileDialog', 'QInputDialog', 'QProgressDialog', 'QErrorMessage',
|
|
'QSystemTrayIcon', 'QClipboard', 'QDrag', 'QMimeData',
|
|
'QKeyEvent', 'QMouseEvent', 'QPaintEvent', 'QResizeEvent',
|
|
'QShowEvent', 'QHideEvent', 'QCloseEvent', 'QFocusEvent',
|
|
'QMoveEvent', 'QContextMenuEvent', 'QInputEvent', 'QWheelEvent',
|
|
'QHoverEvent', 'QTabletEvent', 'QGestureEvent', 'QShortcut',
|
|
'QKeySequence', 'QValidator', 'QIntValidator', 'QDoubleValidator',
|
|
'QRegExpValidator', 'QCompleter', 'QAbstractSpinBox', 'QDateTimeEdit',
|
|
'QDateEdit', 'QTimeEdit', 'QCalendarWidget', 'QDial', 'QLCDNumber',
|
|
'QSpinBox', 'QDoubleSpinBox', 'QTimeEdit', 'QDateTimeEdit',
|
|
'QDateEdit', 'QFontComboBox', 'QToolButton', 'QCommandLinkButton',
|
|
'QDialogButtonBox', 'QPlainTextEdit', 'QTextEdit', 'QTextBrowser',
|
|
'QListWidget', 'QTreeWidget', 'QTableWidget', 'QListWidgetItem',
|
|
'QTreeWidgetItem', 'QTableWidgetItem', 'QHeaderView', 'QColumnView',
|
|
'QDataWidgetMapper', 'QFileSystemModel', 'QStandardItemModel',
|
|
'QStandardItem', 'QSortFilterProxyModel', 'QStringListModel',
|
|
'QAbstractProxyModel', 'QIdentityProxyModel', 'QItemSelectionModel',
|
|
'QItemSelection', 'QItemSelectionRange', 'QStyledItemDelegate',
|
|
'QItemDelegate', 'QAbstractItemDelegate', 'QAbstractItemView',
|
|
'QGraphicsView', 'QGraphicsScene', 'QGraphicsItem', 'QGraphicsWidget',
|
|
'QGraphicsObject', 'QGraphicsLayout', 'QGraphicsLinearLayout',
|
|
'QGraphicsGridLayout', 'QGraphicsProxyWidget', 'QGraphicsTextItem',
|
|
'QGraphicsRectItem', 'QGraphicsEllipseItem', 'QGraphicsLineItem',
|
|
'QGraphicsPathItem', 'QGraphicsPolygonItem', 'QGraphicsPixmapItem',
|
|
'QGraphicsSimpleTextItem', 'QGraphicsItemGroup', 'QGraphicsLayoutItem',
|
|
'QGraphicsAnchorLayout', 'QGraphicsGridLayout', 'QStackedLayout',
|
|
'QBoxLayout', 'QFormLayout', 'QGridLayout', 'QHBoxLayout',
|
|
'QVBoxLayout', 'QLayout', 'QLayoutItem', 'QSpacerItem',
|
|
'QSizeGrip', 'QSizePolicy', 'QStyle', 'QStyleFactory',
|
|
'QStyleOption', 'QStylePainter', 'QProxyStyle', 'QCommonStyle',
|
|
'QWindowsVistaStyle', 'QMacStyle', 'QFusionStyle', 'QCleanlooksStyle',
|
|
'QPlastiqueStyle', 'QMotifStyle', 'QApplication', 'QDesktopWidget',
|
|
'QSessionManager', 'QStyleHintReturn', 'QStyleHintReturnMask',
|
|
'QStyleHintReturnVariant', 'QStyleOptionFocusRect',
|
|
'QStyleOptionFrame', 'QStyleOptionFrameV2', 'QStyleOptionFrameV3',
|
|
'QStyleOptionButton', 'QStyleOptionComboBox', 'QStyleOptionHeader',
|
|
'QStyleOptionHeaderV2', 'QStyleOptionComplex', 'QStyleOptionSlider',
|
|
'QStyleOptionSpinBox', 'QStyleOptionToolButton', 'QStyleOptionToolBar',
|
|
'QStyleOptionDockWidget', 'QStyleOptionDockWidgetV2',
|
|
'QStyleOptionViewItem', 'QStyleOptionViewItemV2', 'QStyleOptionViewItemV3',
|
|
'QStyleOptionViewItemV4', 'QStyleOptionTab', 'QStyleOptionTabV2',
|
|
'QStyleOptionTabV3', 'QStyleOptionTabBarBase', 'QStyleOptionTabBarBaseV2',
|
|
'QStyleOptionRubberBand', 'QStyleOptionGraphicsItem',
|
|
'QStyleOptionTitleBar', 'QStyleOptionToolBox', 'QStyleOptionToolBoxV2',
|
|
'QStyleOptionViewItem', 'QStyleOptionProgressBar',
|
|
'QStyleOptionProgressBarV2', 'QStyleOptionMenuItem', 'QStyleOptionSlider',
|
|
'QStyleOptionSpinBox', 'QStyleOptionToolButton', 'QStyleOptionToolBar',
|
|
'QStyleOptionDockWidget', 'QStyleOptionDockWidgetV2',
|
|
'QStyleOptionFocusRect', 'QStyleOptionFrame', 'QStyleOptionFrameV2',
|
|
'QStyleOptionFrameV3', 'QStyleOptionButton', 'QStyleOptionComboBox',
|
|
'QStyleOptionHeader', 'QStyleOptionHeaderV2', 'QStyleOptionComplex',
|
|
'QStyleOptionTab', 'QStyleOptionTabV2', 'QStyleOptionTabV3',
|
|
'QStyleOptionTabBarBase', 'QStyleOptionTabBarBaseV2',
|
|
'QStyleOptionRubberBand', 'QStyleOptionGraphicsItem',
|
|
'QStyleOptionTitleBar', 'QStyleOptionToolBox', 'QStyleOptionToolBoxV2',
|
|
'QStyleOptionProgressBar', 'QStyleOptionProgressBarV2',
|
|
'QStyleOptionMenuItem', 'QStyleOptionSizeMode', 'QStyleOptionVersion',
|
|
}
|
|
|
|
def find_cpp_files_with_logger_member():
|
|
"""Find all Qt6 .cpp files that have m_logger member in corresponding header"""
|
|
cpp_files = []
|
|
|
|
for cpp_file in QT6_BASE.rglob("*.cpp"):
|
|
# Find corresponding header
|
|
header = cpp_file.with_suffix('.h')
|
|
if not header.exists():
|
|
header = cpp_file.with_suffix('.hpp')
|
|
|
|
if header.exists():
|
|
try:
|
|
header_content = header.read_text(encoding='utf-8', errors='ignore')
|
|
if 'm_logger' in header_content:
|
|
cpp_files.append(cpp_file)
|
|
except:
|
|
pass
|
|
|
|
print(f"Found {len(cpp_files)} .cpp files with m_logger in header")
|
|
return cpp_files
|
|
|
|
def add_logger_init_to_constructor(content, class_name):
|
|
"""Add logger initialization to constructor"""
|
|
|
|
# Pattern to match constructor initialization list
|
|
# Matches: ClassName::ClassName(...) : existing_init1(val1), existing_init2(val2)
|
|
# Also matches: ClassName::ClassName(...) {
|
|
# And: ClassName::ClassName(...)
|
|
|
|
# First check if already has logger init
|
|
if 'm_logger(' in content or 'm_logger(NGL' in content:
|
|
return content, False, "Already initialized"
|
|
|
|
# Pattern for constructor with initialization list
|
|
# Group 1: constructor signature up to :
|
|
# Group 2: existing initializers
|
|
# Group 3: opening brace or colon continuing init list
|
|
|
|
# Try to find constructor with init list
|
|
pattern_with_init = rf'({re.escape(class_name)}::\s*{re.escape(class_name)}\s*\([^)]*\))\s*:\s*([^{{]+?)\s*({{)'
|
|
match = re.search(pattern_with_init, content, re.MULTILINE | re.DOTALL)
|
|
|
|
if match:
|
|
# Add m_logger to existing init list
|
|
before = match.group(1)
|
|
inits = match.group(2).rstrip()
|
|
brace = match.group(3)
|
|
|
|
# Add m_logger initialization (comma if needed)
|
|
new_init = f"{before} : {inits},\n m_logger(NGL::NGLLoggerBootstrap::getLogger()) {brace}"
|
|
new_content = content[:match.start()] + new_init + content[match.end():]
|
|
return new_content, True, "Added to init list"
|
|
|
|
# Try constructor without init list (direct brace)
|
|
pattern_direct_brace = rf'({re.escape(class_name)}::\s*{re.escape(class_name)}\s*\([^)]*\))\s*({{)'
|
|
match = re.search(pattern_direct_brace, content, re.MULTILINE)
|
|
|
|
if match:
|
|
sig = match.group(1)
|
|
brace = match.group(2)
|
|
new_constructor = f"{sig} : m_logger(NGL::NGLLoggerBootstrap::getLogger()) {brace}"
|
|
new_content = content[:match.start()] + new_constructor + content[match.end():]
|
|
return new_content, True, "Added init list"
|
|
|
|
# Try constructor that continues on next line
|
|
pattern_multiline = rf'({re.escape(class_name)}::\s*{re.escape(class_name)}\s*\([^)]*\))\s*\n\s*:\s*([^{{]+?)\s*({{)'
|
|
match = re.search(pattern_multiline, content, re.MULTILINE)
|
|
|
|
if match:
|
|
before = match.group(1)
|
|
inits = match.group(2).rstrip()
|
|
brace = match.group(3)
|
|
new_init = f"{before}\n : {inits},\n m_logger(NGL::NGLLoggerBootstrap::getLogger()) {brace}"
|
|
new_content = content[:match.start()] + new_init + content[match.end():]
|
|
return new_content, True, "Added to multiline init"
|
|
|
|
return content, False, "No constructor found"
|
|
|
|
def extract_class_name_from_header(header_path):
|
|
"""Extract class name from header file"""
|
|
try:
|
|
content = header_path.read_text(encoding='utf-8', errors='ignore')
|
|
# Find first class definition (not forward declaration)
|
|
pattern = r'^class\s+(\w+)\s*(?::\s*public\s+\w+)?\s*\{'
|
|
match = re.search(pattern, content, re.MULTILINE)
|
|
if match:
|
|
return match.group(1)
|
|
except:
|
|
pass
|
|
return None
|
|
|
|
def main():
|
|
print("=" * 80)
|
|
print("Adding logger initialization to constructors")
|
|
print("=" * 80)
|
|
|
|
# Find cpp files with m_logger in header
|
|
cpp_files = find_cpp_files_with_logger_member()
|
|
|
|
# Track results
|
|
added = 0
|
|
skipped = 0
|
|
skip_reasons = {}
|
|
examples = []
|
|
|
|
for cpp_file in cpp_files:
|
|
try:
|
|
content = cpp_file.read_text(encoding='utf-8')
|
|
|
|
# Get class name from header
|
|
header = cpp_file.with_suffix('.h')
|
|
if not header.exists():
|
|
header = cpp_file.with_suffix('.hpp')
|
|
|
|
class_name = None
|
|
if header.exists():
|
|
class_name = extract_class_name_from_header(header)
|
|
|
|
if not class_name:
|
|
# Try to guess from filename
|
|
class_name = cpp_file.stem
|
|
|
|
# Try to add logger init
|
|
new_content, success, message = add_logger_init_to_constructor(content, class_name)
|
|
|
|
if success:
|
|
cpp_file.write_text(new_content, encoding='utf-8')
|
|
added += 1
|
|
if added <= 10:
|
|
print(f"ADDED: {cpp_file.relative_to(QT6_BASE)} - {message}")
|
|
else:
|
|
skipped += 1
|
|
reason = message
|
|
skip_reasons[reason] = skip_reasons.get(reason, 0) + 1
|
|
if len(examples) < 5:
|
|
examples.append(f"{cpp_file.relative_to(QT6_BASE)} ({class_name})")
|
|
|
|
except Exception as e:
|
|
skipped += 1
|
|
reason = f"Error: {str(e)}"
|
|
skip_reasons[reason] = skip_reasons.get(reason, 0) + 1
|
|
|
|
print("\n" + "=" * 80)
|
|
print(f"Results: {added} files updated, {skipped} skipped")
|
|
print("\nSkip reasons:")
|
|
for reason, count in sorted(skip_reasons.items(), key=lambda x: -x[1])[:10]:
|
|
print(f" {reason}: {count}")
|
|
|
|
if examples:
|
|
print("\nSkipped examples (first 5):")
|
|
for example in examples:
|
|
print(f" - {example}")
|
|
print("=" * 80)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|