qt 0.1.9 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,24 +2,12 @@
2
2
 
3
3
  RUNTIME_HEADER_PATH = File.expand_path('../../ext/qt_ruby_bridge/qt_ruby_runtime.hpp', __dir__)
4
4
 
5
- SCALAR_CLASS_METHOD_FFI_RETURNS = %i[void int bool string pointer].freeze
6
- QAPPLICATION_STATIC_METHOD_EXCLUSIONS = %w[exec].freeze
7
- QAPPLICATION_STATIC_TEXT_SETTERS = %w[
8
- setApplicationName
9
- setDesktopFileName
10
- setOrganizationName
11
- setApplicationDisplayName
12
- ].freeze
13
-
14
5
  def qt_free_function_specs(ast)
15
6
  @qt_free_function_specs_cache ||= {}.compare_by_identity
16
7
  return @qt_free_function_specs_cache[ast] if @qt_free_function_specs_cache.key?(ast)
17
8
 
18
9
  qt_specs = []
19
10
  qt_specs << qversion_free_function_spec(ast)
20
- qt_specs.concat(qapplication_static_free_function_specs(ast))
21
- qt_specs.concat(qapplication_static_text_setter_specs(ast))
22
- qt_specs << qapplication_top_level_widgets_count_spec(ast)
23
11
  runtime_specs = runtime_free_function_specs_from_header
24
12
  @qt_free_function_specs_cache[ast] = merge_free_function_specs(qt_specs, runtime_specs).freeze
25
13
  end
@@ -140,147 +128,6 @@ def qversion_free_function_spec(ast)
140
128
  }
141
129
  end
142
130
 
143
- def qapplication_top_level_widgets_count_spec(ast)
144
- has_top_level_widgets = collect_method_decls_with_bases(ast, 'QApplication', 'topLevelWidgets').any?
145
- raise 'Unable to find QApplication::topLevelWidgets in AST' unless has_top_level_widgets
146
-
147
- {
148
- name: 'qt_ruby_qapplication_top_level_widgets_count',
149
- ffi_return: :int,
150
- args: [],
151
- cpp_return: 'int',
152
- cpp_args: '',
153
- cpp_body: ['return QApplication::topLevelWidgets().size();'],
154
- qapplication_method: { ruby_name: 'topLevelWidgetsCount', native: 'qapplication_top_level_widgets_count', args: [] }
155
- }
156
- end
157
-
158
- def qapplication_static_free_function_specs(ast)
159
- int_cast_types = ast_int_cast_type_set(ast)
160
- method_names = collect_method_names_with_bases(ast, 'QApplication').uniq
161
- method_names -= QAPPLICATION_STATIC_METHOD_EXCLUSIONS
162
- method_names.filter_map do |qt_name|
163
- build_qapplication_static_free_function_spec(ast, qt_name, int_cast_types)
164
- end
165
- end
166
-
167
- def qapplication_static_text_setter_specs(ast)
168
- QAPPLICATION_STATIC_TEXT_SETTERS.filter_map do |qt_name|
169
- build_qapplication_static_text_setter_spec(ast, qt_name)
170
- end
171
- end
172
-
173
- def build_qapplication_static_text_setter_spec(ast, qt_name)
174
- return nil unless resolve_qapplication_static_text_setter_candidate(ast, qt_name)
175
-
176
- native_name = "qapplication_#{to_snake(qt_name)}"
177
- {
178
- name: "qt_ruby_#{native_name}",
179
- ffi_return: :void,
180
- args: [:string],
181
- cpp_return: 'void',
182
- cpp_args: 'const char* value',
183
- cpp_body: ["QApplication::#{qt_name}(as_qstring(value));"],
184
- qapplication_method: {
185
- ruby_name: qt_name,
186
- native: native_name,
187
- args: [{ name: :value, ffi: :string, cast: :qstring }],
188
- required_arg_count: 1
189
- }
190
- }
191
- end
192
-
193
- def resolve_qapplication_static_text_setter_candidate(ast, qt_name)
194
- decls = collect_method_decls_with_bases(ast, 'QApplication', qt_name)
195
- decls.any? do |decl|
196
- next false unless decl['storageClass'] == 'static'
197
- next false unless decl['__effective_access'] == 'public'
198
-
199
- parsed = parse_method_signature(decl)
200
- next false unless parsed
201
- next false unless parsed[:return_type].to_s.strip == 'void'
202
- next false unless parsed[:required_arg_count] == 1
203
- next false unless parsed[:params].length == 1
204
-
205
- normalized = normalized_cpp_type_name(parsed[:params].first[:type])
206
- normalized == 'QString'
207
- end
208
- end
209
-
210
- def build_qapplication_static_free_function_spec(ast, qt_name, int_cast_types)
211
- candidate = resolve_qapplication_static_noarg_candidate(ast, qt_name, int_cast_types)
212
- return nil unless candidate
213
-
214
- native_name = "qapplication_#{to_snake(qt_name)}"
215
- cpp_body =
216
- if candidate[:ffi_return] == :void
217
- ["QApplication::#{qt_name}();"]
218
- elsif candidate[:enum_cast]
219
- ["return static_cast<int>(QApplication::#{qt_name}());"]
220
- elsif candidate[:ffi_return] == :string
221
- [
222
- "const QString value = QApplication::#{qt_name}();",
223
- 'thread_local QByteArray utf8;',
224
- 'utf8 = value.toUtf8();',
225
- 'return utf8.constData();'
226
- ]
227
- else
228
- ["return QApplication::#{qt_name}();"]
229
- end
230
-
231
- {
232
- name: "qt_ruby_#{native_name}",
233
- ffi_return: candidate[:ffi_return],
234
- args: [],
235
- cpp_return: ffi_return_to_cpp(candidate[:ffi_return]),
236
- cpp_args: '',
237
- cpp_body: cpp_body,
238
- qapplication_method: {
239
- ruby_name: qt_name,
240
- native: native_name,
241
- args: [],
242
- return_cast: candidate[:return_cast],
243
- pointer_class: candidate[:pointer_class]
244
- }
245
- }
246
- end
247
-
248
- def resolve_qapplication_static_noarg_candidate(ast, qt_name, int_cast_types)
249
- decls = collect_method_decls_with_bases(ast, 'QApplication', qt_name)
250
- candidates = decls.filter_map do |decl|
251
- next unless decl['storageClass'] == 'static'
252
- next unless decl['__effective_access'] == 'public'
253
-
254
- parsed = parse_method_signature(decl)
255
- next unless parsed && parsed[:required_arg_count].zero?
256
-
257
- ret_info = qapplication_static_return_info(parsed[:return_type], int_cast_types, ast: ast)
258
- next unless ret_info
259
-
260
- { decl: decl, param_count: parsed[:params].length }.merge(ret_info)
261
- end
262
- return nil if candidates.empty?
263
-
264
- candidates.min_by { |item| item[:param_count] }
265
- end
266
-
267
- def qapplication_static_return_info(return_type, int_cast_types, ast:)
268
- mapped = map_cpp_return_type(return_type, ast: ast)
269
- if mapped && SCALAR_CLASS_METHOD_FFI_RETURNS.include?(mapped[:ffi_return])
270
- return {
271
- ffi_return: mapped[:ffi_return],
272
- return_cast: mapped[:return_cast],
273
- pointer_class: mapped[:pointer_class],
274
- enum_cast: false
275
- }
276
- end
277
-
278
- normalized = normalized_cpp_type_name(return_type)
279
- return nil unless normalized.include?('::') && int_cast_types.include?(normalized)
280
-
281
- { ffi_return: :int, return_cast: nil, enum_cast: true }
282
- end
283
-
284
131
  def qapplication_class_method_specs(ast)
285
132
  qt_free_function_specs(ast).filter_map { |spec| spec[:qapplication_method] }
286
133
  end
@@ -12,7 +12,7 @@ def constructor_supports_parent_only?(decl)
12
12
  return false if params.empty?
13
13
 
14
14
  first_type = normalized_cpp_type_name(params.first[:type])
15
- return false unless %w[QWidget* QObject*].include?(first_type)
15
+ return false unless first_type.match?(/\AQ[A-Z]\w*\*\z/)
16
16
 
17
17
  params.drop(1).all? { |param| param[:has_default] }
18
18
  end
@@ -44,7 +44,7 @@ def parent_constructor_first_type(decl)
44
44
  return nil if params.empty?
45
45
 
46
46
  first_type = normalized_cpp_type_name(params.first[:type])
47
- return nil unless %w[QWidget* QObject*].include?(first_type)
47
+ return nil unless first_type.match?(/\AQ[A-Z]\w*\*\z/)
48
48
  return nil unless params.drop(1).all? { |param| param[:has_default] }
49
49
 
50
50
  first_type
@@ -139,7 +139,7 @@ def discover_related_value_classes(ast, seed_classes, all_classes, template_clas
139
139
 
140
140
  until queue.empty?
141
141
  klass = queue.shift
142
- related_qt_type_names(ast, klass).each do |candidate|
142
+ (related_qt_type_names(ast, klass).to_a + derived_qt_classes(ast, klass, all_classes)).uniq.each do |candidate|
143
143
  next if discovered.include?(candidate)
144
144
  next unless related_value_class_candidate?(ast, candidate, all_classes, template_classes)
145
145
 
@@ -151,6 +151,42 @@ def discover_related_value_classes(ast, seed_classes, all_classes, template_clas
151
151
  discovered.to_a
152
152
  end
153
153
 
154
+ def derived_qt_classes(ast, qt_class, all_classes)
155
+ all_classes.select { |candidate| candidate != qt_class && class_inherits?(ast, candidate, qt_class) }
156
+ end
157
+
158
+ def discover_related_static_api_classes(ast, seed_classes, all_classes, template_classes)
159
+ discovered = seed_classes.to_set
160
+ loop do
161
+ added = all_classes.select do |owner|
162
+ next false if discovered.include?(owner) || template_classes.include?(owner)
163
+
164
+ method_decls_for_related_wrapper_scan(ast, owner).any? do |decl|
165
+ next false unless decl['storageClass'] == 'static'
166
+ next false unless decl['__effective_access'] == 'public'
167
+
168
+ parsed = parse_method_signature(decl)
169
+ next false unless parsed
170
+
171
+ return_type = related_qt_type_name(parsed[:return_type])
172
+ next false unless discovered.include?(return_type)
173
+
174
+ !build_auto_method_from_decl(
175
+ decl,
176
+ { qt_name: decl['name'] },
177
+ qt_class: owner,
178
+ int_cast_types: ast_int_cast_type_set(ast),
179
+ ast: ast
180
+ ).nil?
181
+ end
182
+ end
183
+ break if added.empty?
184
+
185
+ discovered.merge(added)
186
+ end
187
+ discovered.to_a - seed_classes
188
+ end
189
+
154
190
  def discover_related_qobject_wrapper_classes(ast, seed_classes, all_classes, template_classes, scope)
155
191
  discovered = seed_classes.to_set
156
192
  queue = seed_classes.dup
@@ -265,9 +301,7 @@ def append_related_qt_types_from_decl(out, parsed, method_name)
265
301
  candidates << [related_qt_type_name(parsed[:return_type]), parsed[:return_type].to_s] if parsed[:return_type]
266
302
  parsed[:params].each { |param| candidates << [related_qt_type_name(param[:type]), param[:type].to_s] }
267
303
  candidates.each do |candidate, raw_type|
268
- next if candidate.empty? || !candidate.start_with?('Q')
269
- next unless related_type_name_matches_method?(candidate, method_name) ||
270
- (qt_pointer_type?(raw_type) && candidate.end_with?('Item'))
304
+ next unless candidate.match?(/\AQ[A-Z]\w*\z/)
271
305
 
272
306
  out << candidate
273
307
  end
@@ -299,8 +333,18 @@ def discover_target_qt_classes(ast, scope)
299
333
  targets = timed("discover_target_qt_classes/#{scope}/related") do
300
334
  discover_related_value_classes(ast, base_targets, all_classes, template_classes).sort
301
335
  end
336
+ targets = timed("discover_target_qt_classes/#{scope}/static_api_owners") do
337
+ related_static_owners = discover_related_static_api_classes(
338
+ ast,
339
+ (targets + ['QApplication']).uniq,
340
+ all_classes,
341
+ template_classes
342
+ )
343
+ (targets + related_static_owners).sort
344
+ end
302
345
  wrapper_targets = timed("discover_target_qt_classes/#{scope}/related_qobject_wrappers") do
303
- discover_related_qobject_wrapper_classes(ast, targets, all_classes, template_classes, scope).sort
346
+ seed_classes = (targets + ['QApplication']).uniq
347
+ discover_related_qobject_wrapper_classes(ast, seed_classes, all_classes, template_classes, scope).sort
304
348
  end
305
349
  targets = (targets + wrapper_targets).uniq.sort
306
350
  debug_log(
@@ -391,17 +435,14 @@ def constructor_string_path_cast(ctor_decls)
391
435
  ctor_decls.filter_map do |decl|
392
436
  parsed = parse_method_signature(decl)
393
437
  next nil unless parsed && parsed[:params].first
438
+ next nil unless parsed[:required_arg_count] <= 1
439
+ next nil unless parsed[:params].drop(1).all? { |param| param[:has_default] }
394
440
 
395
441
  constructor_string_like_arg_cast(parsed[:params].first[:type])
396
442
  end.first
397
443
  end
398
444
 
399
445
  def base_spec_hash(qt_class, parent_ctor)
400
- auto_method_rules = {}
401
- # Prefer QShortcut#setKeys(StandardKey) in generated API and provide
402
- # QKeySequence path via setKey(QKeySequence) + Ruby-level compatibility shim.
403
- auto_method_rules[:setKeys] = { param_types: ['QKeySequence::StandardKey'] } if qt_class == 'QShortcut'
404
-
405
446
  {
406
447
  qt_class: qt_class,
407
448
  ruby_class: qt_class,
@@ -410,7 +451,6 @@ def base_spec_hash(qt_class, parent_ctor)
410
451
  constructor: parent_ctor,
411
452
  methods: [],
412
453
  auto_methods: :all,
413
- auto_method_rules: auto_method_rules,
414
454
  # Constructor availability is already filtered during discovery.
415
455
  # Keep validation lightweight for auto-discovered classes to avoid false negatives
416
456
  # on template/specialized constructor names in Clang AST.