blob: 0f87d80bd24d12e57e3268a467d37fa48b4a1b0d (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
# Copyright (C) 2024 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
from pathlib import Path
import os
import re
import subprocess
import sys
"""Scan the Qt C++ headers per module for classes that should be present
in the matching type system and print the missing classes."""
VALUE_TYPE = re.compile(r'^\s*<value-type name="([^"]+)"')
OBJECT_TYPE = re.compile(r'^\s*<object-type name="([^"]+)"')
def query_qtpaths(keyword):
"""Query qtpaths for a keyword."""
query_cmd = ["qtpaths", "-query", keyword]
output = subprocess.check_output(query_cmd, stderr=subprocess.STDOUT,
universal_newlines=True)
return output.strip()
def is_class_exluded(name):
"""Check for excluded classes that do not make sense in a typesystem."""
if len(name) < 2:
return True
if "Iterator" in name or "iterator" in name:
return True
if name.startswith("If") or name.startswith("Is") or name.startswith("When"):
return True
if name[:1].islower():
return True
if name.startswith("QOpenGLFunctions") and name.endswith("Backend"):
return True
return False
def class_from_header_line(line):
"""Extract a class name from a C++ header line."""
def _is_macro(token):
return "EXPORT" in token or "API" in token
def _fix_class_name(name):
pos = name.find('<') # Some template specialization "class Name<TemplateParam>"
if pos > 0:
name = name[:pos]
if name.endswith(':'):
name = name[:-1]
return name
if line.startswith('//') or line.endswith(';'): # comment/forward decl
return None
line = line.strip()
if not line.startswith("class ") and not line.startswith("struct "):
return None
tokens = line.split()
pos = 1
while pos < len(tokens) and _is_macro(tokens[pos]):
pos += 1
return _fix_class_name(tokens[pos]) if pos < len(tokens) else None
def classes_from_header(header):
"""Extract classes from C++ header file."""
result = []
for line in header.read_text("utf-8").splitlines():
name = class_from_header_line(line)
if name and not is_class_exluded(name):
result.append(name)
return sorted(result)
def classes_from_typesystem(typesystem):
"""Extract classes from typesystem XML file."""
result = []
for line in typesystem.read_text("utf-8").splitlines():
match = VALUE_TYPE.search(line) or OBJECT_TYPE.search(line)
if match:
result.append(match.group(1))
return sorted(result)
def check_classes(qt_module_inc_dir, pyside_dir):
"""Check classes of a module."""
module_name = qt_module_inc_dir.name
sys.stderr.write(f"Checking {module_name} ")
cpp_classes = []
typesystem_classes = []
for header in qt_module_inc_dir.glob("q*.h"):
if not header.name.endswith("_p.h"):
cpp_classes.extend(classes_from_header(header))
for typesystem in pyside_dir.glob("*.xml"):
typesystem_classes.extend(classes_from_typesystem(typesystem))
cpp_count = len(cpp_classes)
typesystem_count = len(typesystem_classes)
sys.stderr.write(f"found {cpp_count} C++ / {typesystem_count} typesystem classes")
if cpp_count <= typesystem_count:
sys.stderr.write(" ok\n")
else:
sys.stderr.write(f", {cpp_count-typesystem_count} missing\n")
for cpp_class in cpp_classes:
if cpp_class not in typesystem_classes:
wrapper_name = cpp_class.lower() + "_wrapper.cpp"
print(f"{module_name}:{cpp_class}:{wrapper_name}")
if __name__ == '__main__':
qt_version = query_qtpaths("QT_VERSION")
qt_inc_dir = Path(query_qtpaths("QT_INSTALL_HEADERS"))
print(f"Qt {qt_version} at {os.fspath(qt_inc_dir.parent)}", file=sys.stderr)
dir = Path(__file__).parents[1].resolve()
for module_dir in (dir / "sources" / "pyside6" / "PySide6").glob("Qt*"):
qt_module_inc_dir = qt_inc_dir / module_dir.name
if qt_module_inc_dir.is_dir():
check_classes(qt_module_inc_dir, module_dir)
|