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.
- checksums.yaml +4 -4
- data/ext/qt_ruby_bridge/extconf.rb +2 -0
- data/ext/qt_ruby_bridge/qt_ruby_runtime.hpp +14 -0
- data/ext/qt_ruby_bridge/runtime_events.cpp +8 -3
- data/ext/qt_ruby_bridge/runtime_value_types.cpp +22 -0
- data/ext/qt_ruby_bridge/runtime_virtual_methods.cpp +78 -0
- data/lib/qt/application_lifecycle.rb +1 -1
- data/lib/qt/event_runtime_dispatch.rb +2 -0
- data/lib/qt/generated_overload_runtime.rb +7 -0
- data/lib/qt/object_wrapper.rb +1 -0
- data/lib/qt/value_wrapper.rb +26 -0
- data/lib/qt/version.rb +1 -1
- data/lib/qt/virtual_method_runtime.rb +165 -0
- data/lib/qt.rb +4 -0
- data/scripts/generate_bridge/ast_introspection.rb +16 -3
- data/scripts/generate_bridge/auto_methods.rb +205 -24
- data/scripts/generate_bridge/cpp_method_return_emitter.rb +75 -24
- data/scripts/generate_bridge/ffi_api.rb +17 -1
- data/scripts/generate_bridge/free_function_specs.rb +0 -153
- data/scripts/generate_bridge/spec_discovery.rb +53 -13
- data/scripts/generate_bridge.rb +410 -31
- metadata +6 -1
data/scripts/generate_bridge.rb
CHANGED
|
@@ -35,6 +35,7 @@ def build_qapplication_spec(ast)
|
|
|
35
35
|
constructor: { parent: false, mode: :qapplication },
|
|
36
36
|
class_methods: class_methods,
|
|
37
37
|
methods: instance_methods,
|
|
38
|
+
auto_methods: :all,
|
|
38
39
|
validate: { constructors: ['QApplication'], methods: ['exec'] }
|
|
39
40
|
}
|
|
40
41
|
end
|
|
@@ -66,8 +67,6 @@ def next_trace_base(fetch_bases, cur, visited)
|
|
|
66
67
|
end
|
|
67
68
|
|
|
68
69
|
def trace_generated_super_chain(fetch_bases, known_qt, qt_class, super_qt_by_qt)
|
|
69
|
-
return if qt_class == 'QApplication'
|
|
70
|
-
|
|
71
70
|
visited = {}
|
|
72
71
|
prev = cur = qt_class
|
|
73
72
|
loop do
|
|
@@ -154,13 +153,13 @@ def find_getter_decl(ast, qt_class, property)
|
|
|
154
153
|
parsed = parse_method_signature(decl)
|
|
155
154
|
next false unless parsed && parsed[:params].empty?
|
|
156
155
|
|
|
157
|
-
map_cpp_return_type(parsed[:return_type], ast: ast)
|
|
156
|
+
map_cpp_return_type(parsed[:return_type], ast: ast, qt_class: qt_class)
|
|
158
157
|
end
|
|
159
158
|
end
|
|
160
159
|
|
|
161
160
|
def build_property_getter_method(ast, getter_decl, property)
|
|
162
161
|
parsed_getter = parse_method_signature(getter_decl)
|
|
163
|
-
ret_info = map_cpp_return_type(parsed_getter[:return_type], ast: ast)
|
|
162
|
+
ret_info = map_cpp_return_type(parsed_getter[:return_type], ast: ast, qt_class: getter_decl['__owner_class'])
|
|
164
163
|
return nil unless ret_info
|
|
165
164
|
|
|
166
165
|
getter = {
|
|
@@ -250,7 +249,9 @@ def arg_expr(arg)
|
|
|
250
249
|
when :qicon_ref then "*static_cast<QIcon*>(#{arg[:name]})"
|
|
251
250
|
when :qany_string_view then "QAnyStringView(as_qstring(#{arg[:name]}))"
|
|
252
251
|
when :qvariant_from_utf8 then "qvariant_from_bridge_value(#{arg[:name]})"
|
|
252
|
+
when :qint_list_from_variant then "QtRubyRuntime::qint_list_from_variant(qvariant_from_bridge_value(#{arg[:name]}))"
|
|
253
253
|
when :alignment then "static_cast<Qt::Alignment>(#{arg[:name]})"
|
|
254
|
+
when :qt_value_ref then "*static_cast<#{arg[:value_class]}*>(#{arg[:name]})"
|
|
254
255
|
when String then "static_cast<#{arg[:cast]}>(#{arg[:name]})"
|
|
255
256
|
else
|
|
256
257
|
arg[:name]
|
|
@@ -306,26 +307,27 @@ end
|
|
|
306
307
|
|
|
307
308
|
def generate_cpp_constructor(lines, spec)
|
|
308
309
|
name = ctor_function_name(spec)
|
|
310
|
+
qt_class = spec[:virtual_adapter] ? generated_virtual_subclass_name(spec) : spec[:qt_class]
|
|
309
311
|
|
|
310
312
|
if spec[:constructor][:mode] == :qapplication
|
|
311
313
|
emit_cpp_qapplication_constructor(lines, name)
|
|
312
314
|
return
|
|
313
315
|
end
|
|
314
316
|
if spec[:constructor][:mode] == :string_path
|
|
315
|
-
emit_cpp_string_path_constructor(lines, name,
|
|
317
|
+
emit_cpp_string_path_constructor(lines, name, qt_class, spec[:constructor][:arg_cast])
|
|
316
318
|
return
|
|
317
319
|
end
|
|
318
320
|
if spec[:constructor][:mode] == :keysequence_parent
|
|
319
|
-
emit_cpp_keysequence_parent_constructor(lines, name, spec)
|
|
321
|
+
emit_cpp_keysequence_parent_constructor(lines, name, spec.merge(qt_class: qt_class))
|
|
320
322
|
return
|
|
321
323
|
end
|
|
322
324
|
|
|
323
325
|
unless spec[:constructor][:parent]
|
|
324
|
-
emit_cpp_default_constructor(lines, name,
|
|
326
|
+
emit_cpp_default_constructor(lines, name, qt_class)
|
|
325
327
|
return
|
|
326
328
|
end
|
|
327
329
|
|
|
328
|
-
emit_cpp_parent_constructor(lines, name, spec)
|
|
330
|
+
emit_cpp_parent_constructor(lines, name, spec.merge(qt_class: qt_class))
|
|
329
331
|
end
|
|
330
332
|
|
|
331
333
|
def generate_cpp_delete(lines)
|
|
@@ -335,8 +337,18 @@ def generate_cpp_delete(lines)
|
|
|
335
337
|
lines << '}'
|
|
336
338
|
end
|
|
337
339
|
|
|
340
|
+
def generate_cpp_qt_value_deletes(lines, specs, free_function_specs)
|
|
341
|
+
value_wrapper_classes(specs, free_function_specs: free_function_specs).each do |qt_class|
|
|
342
|
+
lines << "extern \"C\" void #{qt_value_delete_function_name(qt_class)}(void* handle) {"
|
|
343
|
+
lines << " delete static_cast<#{qt_class}*>(handle);"
|
|
344
|
+
lines << '}'
|
|
345
|
+
lines << ''
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
338
349
|
def cpp_method_signature(method)
|
|
339
|
-
['void* handle'] + method[:
|
|
350
|
+
['void* handle'] + (method[:dispatch] ? ['int argc'] : []) +
|
|
351
|
+
method[:args].map { |arg| "#{ffi_to_cpp_type(arg[:ffi])} #{arg[:name]}" }
|
|
340
352
|
end
|
|
341
353
|
|
|
342
354
|
def cpp_null_handle_return(method)
|
|
@@ -358,19 +370,37 @@ end
|
|
|
358
370
|
|
|
359
371
|
def cpp_method_invocation(method)
|
|
360
372
|
call_args = method[:args].map { |arg| arg_expr(arg) }.join(', ')
|
|
361
|
-
"self_obj->#{method[:qt_name]}
|
|
373
|
+
target = method[:static] ? "#{method[:owner_class]}::#{method[:qt_name]}" : "self_obj->#{method[:qt_name]}"
|
|
374
|
+
"#{target}(#{call_args})"
|
|
362
375
|
end
|
|
363
376
|
|
|
364
377
|
def generate_cpp_method(lines, spec, method)
|
|
365
378
|
fn = method_function_name(spec, method)
|
|
366
379
|
ret = ffi_return_to_cpp(method[:ffi_return])
|
|
367
380
|
lines << "extern \"C\" #{ret} #{fn}(#{cpp_method_signature(method).join(', ')}) {"
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
381
|
+
unless method[:static]
|
|
382
|
+
lines << ' if (!handle) {'
|
|
383
|
+
lines << cpp_null_handle_return(method)
|
|
384
|
+
lines << ' }'
|
|
385
|
+
end
|
|
371
386
|
lines << ''
|
|
372
|
-
lines << " auto* self_obj = static_cast<#{spec[:qt_class]}*>(handle);"
|
|
373
|
-
|
|
387
|
+
lines << " auto* self_obj = static_cast<#{spec[:qt_class]}*>(handle);" unless method[:static]
|
|
388
|
+
if method[:dispatch]
|
|
389
|
+
lines << ' switch (argc) {'
|
|
390
|
+
(method[:required_arg_count]..method[:args].length).each do |arg_count|
|
|
391
|
+
selected = method.merge(args: method[:args].take(arg_count))
|
|
392
|
+
lines << " case #{arg_count}: {"
|
|
393
|
+
emit_cpp_method_return(lines, selected, cpp_method_invocation(selected))
|
|
394
|
+
lines << ' break;' if method[:ffi_return] == :void
|
|
395
|
+
lines << ' }'
|
|
396
|
+
end
|
|
397
|
+
lines << ' default:'
|
|
398
|
+
lines << cpp_null_handle_return(method).sub(/^ /, ' ')
|
|
399
|
+
lines << ' }'
|
|
400
|
+
lines << cpp_null_handle_return(method) if method[:ffi_return] != :void
|
|
401
|
+
else
|
|
402
|
+
emit_cpp_method_return(lines, method, cpp_method_invocation(method))
|
|
403
|
+
end
|
|
374
404
|
lines << '}'
|
|
375
405
|
end
|
|
376
406
|
|
|
@@ -381,11 +411,13 @@ def generate_cpp_bridge(specs, free_function_specs)
|
|
|
381
411
|
|
|
382
412
|
specs.each { |spec| append_cpp_spec_methods(lines, spec) }
|
|
383
413
|
|
|
414
|
+
generate_cpp_qt_value_deletes(lines, specs, free_function_specs)
|
|
384
415
|
generate_cpp_delete(lines)
|
|
385
416
|
"#{lines.join("\n")}\n"
|
|
386
417
|
end
|
|
387
418
|
|
|
388
419
|
def append_cpp_spec_methods(lines, spec)
|
|
420
|
+
generate_cpp_virtual_adapter(lines, spec) if spec[:virtual_adapter]
|
|
389
421
|
unless spec[:constructor][:mode] == :wrap_only
|
|
390
422
|
generate_cpp_constructor(lines, spec)
|
|
391
423
|
lines << ''
|
|
@@ -407,6 +439,8 @@ def cpp_bridge_prelude
|
|
|
407
439
|
#include <QAnyStringView>
|
|
408
440
|
#include <QIcon>
|
|
409
441
|
#include <QJsonDocument>
|
|
442
|
+
#include <QJsonArray>
|
|
443
|
+
#include <QJsonObject>
|
|
410
444
|
#include <QJsonParseError>
|
|
411
445
|
#include <QDateTime>
|
|
412
446
|
#include <QDate>
|
|
@@ -553,6 +587,14 @@ def cpp_bridge_prelude
|
|
|
553
587
|
return QStringLiteral("qtv:str:") + QString::fromUtf8(fallback);
|
|
554
588
|
}
|
|
555
589
|
|
|
590
|
+
QString qstring_list_to_bridge_string(const QStringList& value) {
|
|
591
|
+
QJsonArray array;
|
|
592
|
+
for (const QString& item : value) {
|
|
593
|
+
array.append(item);
|
|
594
|
+
}
|
|
595
|
+
return QString::fromUtf8(QJsonDocument(array).toJson(QJsonDocument::Compact));
|
|
596
|
+
}
|
|
597
|
+
|
|
556
598
|
QString qobject_list_to_bridge_string(const QObjectList& value) {
|
|
557
599
|
QJsonArray array;
|
|
558
600
|
for (QObject* object : value) {
|
|
@@ -640,6 +682,7 @@ def optional_arg_replacement(arg, safe)
|
|
|
640
682
|
when :bool then "(#{safe}.nil? ? false : #{safe})"
|
|
641
683
|
when :pointer then safe
|
|
642
684
|
when :string
|
|
685
|
+
return "(#{safe}.nil? ? Qt::VariantCodec.encode([]) : Qt::VariantCodec.encode(#{safe}))" if arg[:cast] == :qint_list_from_variant
|
|
643
686
|
return "(#{safe}.nil? ? '' : Qt::VariantCodec.encode(#{safe}))" if arg[:cast] == :qvariant_from_utf8
|
|
644
687
|
return "(#{safe}.nil? ? '' : Qt::DateTimeCodec.encode_qdatetime(#{safe}))" if arg[:cast] == :qdatetime_from_utf8
|
|
645
688
|
return "(#{safe}.nil? ? '' : Qt::DateTimeCodec.encode_qdate(#{safe}))" if arg[:cast] == :qdate_from_utf8
|
|
@@ -653,8 +696,13 @@ def optional_arg_replacement(arg, safe)
|
|
|
653
696
|
end
|
|
654
697
|
|
|
655
698
|
def ruby_arg_call_value(arg, safe, optional:)
|
|
699
|
+
if arg[:cast] == :qt_value_ref
|
|
700
|
+
return optional ? "(#{safe}.nil? ? nil : #{safe}.handle)" : "#{safe}.handle"
|
|
701
|
+
end
|
|
702
|
+
|
|
656
703
|
return "Qt::StringCodec.to_qt_text(#{safe})" if text_bridge_arg?(arg) && !optional
|
|
657
704
|
return "Qt::VariantCodec.encode(#{safe})" if arg[:cast] == :qvariant_from_utf8 && !optional
|
|
705
|
+
return "Qt::VariantCodec.encode(#{safe})" if arg[:cast] == :qint_list_from_variant && !optional
|
|
658
706
|
return "Qt::DateTimeCodec.encode_qdatetime(#{safe})" if arg[:cast] == :qdatetime_from_utf8 && !optional
|
|
659
707
|
return "Qt::DateTimeCodec.encode_qdate(#{safe})" if arg[:cast] == :qdate_from_utf8 && !optional
|
|
660
708
|
return "Qt::DateTimeCodec.encode_qtime(#{safe})" if arg[:cast] == :qtime_from_utf8 && !optional
|
|
@@ -687,20 +735,26 @@ def append_ruby_native_call_method(lines, method:, native_call:, indent:)
|
|
|
687
735
|
method_body = ruby_native_method_body(method, rewritten_native_call)
|
|
688
736
|
|
|
689
737
|
lines << "#{indent}def #{ruby_name}(#{ruby_args})"
|
|
690
|
-
lines << "#{indent} #{method_body}"
|
|
738
|
+
lines << "#{indent} Qt::VirtualMethodRuntime.after_native_call(#{method_body})"
|
|
691
739
|
lines << "#{indent}end"
|
|
692
740
|
lines << "#{indent}alias_method :#{snake_alias}, :#{ruby_name}" if snake_alias != ruby_name
|
|
693
741
|
end
|
|
694
742
|
|
|
695
743
|
def ruby_native_method_body(method, rewritten_native_call)
|
|
696
744
|
return "Qt::StringCodec.from_qt_text(#{rewritten_native_call})" if method[:return_cast] == :qstring_to_utf8
|
|
745
|
+
return "JSON.parse(Qt::StringCodec.from_qt_text(#{rewritten_native_call}))" if method[:return_cast] == :qstring_list_to_json
|
|
697
746
|
if method[:return_cast] == :qobject_list_to_wrapped_array
|
|
698
747
|
return "Qt::ObjectListCodec.decode(#{rewritten_native_call}, '#{method[:object_list_class]}')"
|
|
699
748
|
end
|
|
700
749
|
return "Qt::VariantCodec.decode(#{rewritten_native_call})" if method[:return_cast] == :qvariant_to_utf8
|
|
750
|
+
return "Qt::VariantCodec.decode(#{rewritten_native_call})" if method[:return_cast] == :qint_list_to_variant
|
|
701
751
|
return "Qt::DateTimeCodec.decode_qdatetime(#{rewritten_native_call})" if method[:return_cast] == :qdatetime_to_utf8
|
|
702
752
|
return "Qt::DateTimeCodec.decode_qdate(#{rewritten_native_call})" if method[:return_cast] == :qdate_to_utf8
|
|
703
753
|
return "Qt::DateTimeCodec.decode_qtime(#{rewritten_native_call})" if method[:return_cast] == :qtime_to_utf8
|
|
754
|
+
if method[:return_cast] == :qt_value_copy
|
|
755
|
+
delete_method = qt_value_delete_function_name(method[:value_class])
|
|
756
|
+
return "Qt::ValueWrapper.wrap(#{rewritten_native_call}, '#{method[:value_class]}', :#{delete_method})"
|
|
757
|
+
end
|
|
704
758
|
return "Qt::ObjectWrapper.wrap(#{rewritten_native_call}, '#{method[:pointer_class]}')" if method[:pointer_class]
|
|
705
759
|
|
|
706
760
|
rewritten_native_call
|
|
@@ -765,6 +819,8 @@ def append_widget_initializer(lines, spec:, widget_root:, indent:)
|
|
|
765
819
|
append_default_widget_initializer(lines, spec, indent)
|
|
766
820
|
end
|
|
767
821
|
|
|
822
|
+
lines << "#{indent} Qt::VirtualMethodRuntime.attach(self)" if spec[:virtual_adapter]
|
|
823
|
+
|
|
768
824
|
lines << "#{indent} yield self if block_given?"
|
|
769
825
|
lines << "#{indent}end"
|
|
770
826
|
end
|
|
@@ -777,22 +833,32 @@ end
|
|
|
777
833
|
|
|
778
834
|
def append_parent_widget_initializer(lines, spec, widget_root, indent)
|
|
779
835
|
lines << "#{indent}def initialize(parent = nil)"
|
|
836
|
+
append_virtual_runtime_install(lines, spec, indent)
|
|
780
837
|
lines << "#{indent} @handle = Native.#{spec[:prefix]}_new(parent&.handle)"
|
|
781
838
|
append_parent_registration_logic(lines, spec, indent)
|
|
782
839
|
end
|
|
783
840
|
|
|
784
841
|
def append_default_widget_initializer(lines, spec, indent)
|
|
785
842
|
lines << "#{indent}def initialize(_argc = 0, _argv = [])"
|
|
843
|
+
append_virtual_runtime_install(lines, spec, indent)
|
|
786
844
|
lines << "#{indent} @handle = Native.#{spec[:prefix]}_new"
|
|
787
845
|
end
|
|
788
846
|
|
|
789
847
|
def append_string_path_initializer(lines, spec, indent)
|
|
790
848
|
lines << "#{indent}def initialize(path = nil)"
|
|
849
|
+
append_virtual_runtime_install(lines, spec, indent)
|
|
791
850
|
lines << "#{indent} @handle = Native.#{spec[:prefix]}_new(Qt::StringCodec.to_qt_text(path))"
|
|
792
851
|
end
|
|
793
852
|
|
|
853
|
+
def append_virtual_runtime_install(lines, spec, indent)
|
|
854
|
+
return unless spec[:virtual_adapter]
|
|
855
|
+
|
|
856
|
+
lines << "#{indent} Qt::VirtualMethodRuntime.ensure_installed!"
|
|
857
|
+
end
|
|
858
|
+
|
|
794
859
|
def append_keysequence_parent_initializer(lines, spec, widget_root, indent)
|
|
795
860
|
lines << "#{indent}def initialize(key = nil, parent = nil)"
|
|
861
|
+
append_virtual_runtime_install(lines, spec, indent)
|
|
796
862
|
lines << "#{indent} if parent.nil? && (key.nil? || key.respond_to?(:handle))"
|
|
797
863
|
lines << "#{indent} parent = key"
|
|
798
864
|
lines << "#{indent} key = nil"
|
|
@@ -810,8 +876,9 @@ def append_parent_registration_logic(lines, spec, indent)
|
|
|
810
876
|
end
|
|
811
877
|
end
|
|
812
878
|
|
|
813
|
-
def append_ruby_qapplication_prelude(lines, spec, metadata)
|
|
814
|
-
|
|
879
|
+
def append_ruby_qapplication_prelude(lines, spec, metadata, super_ruby)
|
|
880
|
+
superclass = super_ruby ? " < #{super_ruby}" : ''
|
|
881
|
+
lines << " class QApplication#{superclass}"
|
|
815
882
|
append_ruby_class_api_constants(lines, qt_class: spec[:qt_class], metadata: metadata, indent: ' ')
|
|
816
883
|
lines << ''
|
|
817
884
|
lines << ' attr_reader :handle'
|
|
@@ -831,7 +898,7 @@ def append_ruby_qapplication_singleton_accessors(lines)
|
|
|
831
898
|
lines << ' end'
|
|
832
899
|
end
|
|
833
900
|
|
|
834
|
-
def generate_ruby_qapplication(lines, spec)
|
|
901
|
+
def generate_ruby_qapplication(lines, spec, super_ruby:)
|
|
835
902
|
metadata = ruby_api_metadata(spec[:methods])
|
|
836
903
|
metadata[:singleton_setter_aliases] = Array(spec[:class_methods]).each_with_object({}) do |method, aliases|
|
|
837
904
|
aliases.merge!(setter_alias_specs(method))
|
|
@@ -841,7 +908,8 @@ def generate_ruby_qapplication(lines, spec)
|
|
|
841
908
|
metadata[:singleton_setter_aliases]
|
|
842
909
|
)
|
|
843
910
|
|
|
844
|
-
append_ruby_qapplication_prelude(lines, spec, metadata)
|
|
911
|
+
append_ruby_qapplication_prelude(lines, spec, metadata, super_ruby)
|
|
912
|
+
append_ruby_widget_methods(lines, spec.merge(methods: spec[:methods].reject { |method| method[:qt_name] == 'exec' }))
|
|
845
913
|
append_ruby_qapplication_singleton_accessors(lines)
|
|
846
914
|
|
|
847
915
|
Array(spec[:class_methods]).each { |method| append_ruby_qapplication_class_method(lines, method) }
|
|
@@ -893,12 +961,18 @@ end
|
|
|
893
961
|
|
|
894
962
|
def qapplication_class_method_body(method, native_call)
|
|
895
963
|
return " Qt::StringCodec.from_qt_text(#{native_call})" if method[:return_cast] == :qstring_to_utf8
|
|
964
|
+
return " JSON.parse(Qt::StringCodec.from_qt_text(#{native_call}))" if method[:return_cast] == :qstring_list_to_json
|
|
896
965
|
if method[:return_cast] == :qobject_list_to_wrapped_array
|
|
897
966
|
return " Qt::ObjectListCodec.decode(#{native_call}, '#{method[:object_list_class]}')"
|
|
898
967
|
end
|
|
899
968
|
return " Qt::DateTimeCodec.decode_qdatetime(#{native_call})" if method[:return_cast] == :qdatetime_to_utf8
|
|
900
969
|
return " Qt::DateTimeCodec.decode_qdate(#{native_call})" if method[:return_cast] == :qdate_to_utf8
|
|
901
970
|
return " Qt::DateTimeCodec.decode_qtime(#{native_call})" if method[:return_cast] == :qtime_to_utf8
|
|
971
|
+
return " Qt::VariantCodec.decode(#{native_call})" if method[:return_cast] == :qint_list_to_variant
|
|
972
|
+
if method[:return_cast] == :qt_value_copy
|
|
973
|
+
delete_method = qt_value_delete_function_name(method[:value_class])
|
|
974
|
+
return " Qt::ValueWrapper.wrap(#{native_call}, '#{method[:value_class]}', :#{delete_method})"
|
|
975
|
+
end
|
|
902
976
|
return " Qt::ObjectWrapper.wrap(#{native_call}, '#{method[:pointer_class]}')" if method[:pointer_class]
|
|
903
977
|
|
|
904
978
|
" #{native_call}"
|
|
@@ -918,26 +992,303 @@ def generate_ruby_widget_class_header(lines, spec, metadata:, super_ruby:, class
|
|
|
918
992
|
end
|
|
919
993
|
|
|
920
994
|
def append_ruby_widget_methods(lines, spec)
|
|
921
|
-
spec[:methods].
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
995
|
+
instance_groups = spec[:methods].reject { |method| method[:static] }.group_by { |method| method[:ruby_name] }
|
|
996
|
+
instance_groups.each_value do |methods|
|
|
997
|
+
if methods.one? && !methods.first[:dispatch]
|
|
998
|
+
method = methods.first
|
|
999
|
+
call_args = ['@handle'] + method[:args].map { |arg| arg[:name] }
|
|
1000
|
+
native_name = method_function_name(spec, method).delete_prefix('qt_ruby_')
|
|
1001
|
+
append_ruby_native_call_method(
|
|
1002
|
+
lines,
|
|
1003
|
+
method: method,
|
|
1004
|
+
native_call: "Native.#{native_name}(#{call_args.join(', ')})",
|
|
1005
|
+
indent: ' '
|
|
1006
|
+
)
|
|
1007
|
+
append_ruby_property_writer(lines, method: method, indent: ' ')
|
|
1008
|
+
else
|
|
1009
|
+
append_ruby_overload_dispatcher(lines, methods, spec: spec, target: :instance, indent: ' ')
|
|
1010
|
+
end
|
|
1011
|
+
lines << ''
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
static_groups = spec[:methods].select { |method| method[:static] }.group_by { |method| method[:ruby_name] }
|
|
1015
|
+
return if static_groups.empty?
|
|
1016
|
+
|
|
1017
|
+
lines << ' class << self'
|
|
1018
|
+
static_groups.each_value do |methods|
|
|
1019
|
+
if methods.one? && !methods.first[:dispatch]
|
|
1020
|
+
method = methods.first
|
|
1021
|
+
native_name = method_function_name(spec, method).delete_prefix('qt_ruby_')
|
|
1022
|
+
append_ruby_native_call_method(
|
|
1023
|
+
lines,
|
|
1024
|
+
method: method,
|
|
1025
|
+
native_call: "Native.#{native_name}(nil, #{method[:args].map { |arg| arg[:name] }.join(', ')})",
|
|
1026
|
+
indent: ' '
|
|
1027
|
+
)
|
|
1028
|
+
else
|
|
1029
|
+
append_ruby_overload_dispatcher(lines, methods, spec: spec, target: :class, indent: ' ')
|
|
1030
|
+
end
|
|
927
1031
|
lines << ''
|
|
928
1032
|
end
|
|
1033
|
+
lines << ' end'
|
|
1034
|
+
lines << ''
|
|
1035
|
+
end
|
|
1036
|
+
|
|
1037
|
+
def append_ruby_overload_dispatcher(lines, methods, spec:, target:, indent:)
|
|
1038
|
+
first = methods.first
|
|
1039
|
+
ruby_name = ruby_safe_method_name(first[:ruby_name])
|
|
1040
|
+
snake_alias = to_snake(ruby_name)
|
|
1041
|
+
max_args = methods.map { |method| method[:args].length }.max
|
|
1042
|
+
min_required = methods.map { |method| method[:required_arg_count] }.min
|
|
1043
|
+
arg_names = (1..max_args).map { |index| "qt_arg#{index}" }
|
|
1044
|
+
signature = arg_names.each_with_index.map do |arg_name, index|
|
|
1045
|
+
index < min_required ? arg_name : "#{arg_name} = Qt::GeneratedOverloadRuntime::OMITTED"
|
|
1046
|
+
end.join(', ')
|
|
1047
|
+
|
|
1048
|
+
lines << "#{indent}def #{ruby_name}(#{signature})"
|
|
1049
|
+
lines << "#{indent} args = [#{arg_names.join(', ')}]"
|
|
1050
|
+
lines << "#{indent} args.pop while args.last.equal?(Qt::GeneratedOverloadRuntime::OMITTED)"
|
|
1051
|
+
|
|
1052
|
+
methods.sort_by { |method| [-method[:args].count { |arg| overload_arg_specificity(arg).positive? }, -method[:required_arg_count], method[:args].length] }
|
|
1053
|
+
.each do |method|
|
|
1054
|
+
predicates = [
|
|
1055
|
+
"args.length >= #{method[:required_arg_count]}",
|
|
1056
|
+
"args.length <= #{method[:args].length}"
|
|
1057
|
+
]
|
|
1058
|
+
method[:args].each_with_index do |arg, index|
|
|
1059
|
+
predicates << overload_arg_predicate(arg, "args[#{index}]", optional: index >= method[:required_arg_count])
|
|
1060
|
+
end
|
|
1061
|
+
lines << "#{indent} if #{predicates.join(' && ')}"
|
|
1062
|
+
|
|
1063
|
+
arg_map = ruby_arg_name_map(method[:args])
|
|
1064
|
+
method[:args].each_with_index do |arg, index|
|
|
1065
|
+
lines << "#{indent} #{arg_map[arg[:name]]} = args[#{index}]"
|
|
1066
|
+
end
|
|
1067
|
+
native_name = method_function_name(spec, method).delete_prefix('qt_ruby_')
|
|
1068
|
+
native_args = [target == :instance ? '@handle' : 'nil']
|
|
1069
|
+
native_args << 'args.length' if method[:dispatch]
|
|
1070
|
+
native_args.concat(method[:args].map { |arg| arg_map[arg[:name]] })
|
|
1071
|
+
native_call = "Native.#{native_name}(#{native_args.join(', ')})"
|
|
1072
|
+
required_arg_count = method.fetch(:required_arg_count, method[:args].length)
|
|
1073
|
+
rewritten_native_call = rewrite_native_call_args(native_call, method, arg_map, required_arg_count)
|
|
1074
|
+
lines << "#{indent} return Qt::VirtualMethodRuntime.after_native_call(#{ruby_native_method_body(method, rewritten_native_call)})"
|
|
1075
|
+
lines << "#{indent} end"
|
|
1076
|
+
end
|
|
1077
|
+
|
|
1078
|
+
lines << "#{indent} raise ArgumentError, \"no matching overload for #{ruby_name} (given \" + args.length.to_s + \" arguments)\""
|
|
1079
|
+
lines << "#{indent}end"
|
|
1080
|
+
lines << "#{indent}alias_method :#{snake_alias}, :#{ruby_name}" if snake_alias != ruby_name
|
|
1081
|
+
end
|
|
1082
|
+
|
|
1083
|
+
def overload_arg_specificity(arg)
|
|
1084
|
+
return 3 if arg[:cast] == :qt_value_ref || arg[:cast] == :qicon_ref
|
|
1085
|
+
return 2 if arg[:cast].is_a?(String) && arg[:cast].end_with?('*')
|
|
1086
|
+
|
|
1087
|
+
0
|
|
1088
|
+
end
|
|
1089
|
+
|
|
1090
|
+
def overload_arg_predicate(arg, expression, optional:)
|
|
1091
|
+
prefix = optional ? "(#{expression}.nil? || " : ''
|
|
1092
|
+
suffix = optional ? ')' : ''
|
|
1093
|
+
predicate =
|
|
1094
|
+
if arg[:cast] == :qt_value_ref || arg[:cast] == :qicon_ref
|
|
1095
|
+
class_name = arg[:value_class] || ('QIcon' if arg[:cast] == :qicon_ref)
|
|
1096
|
+
class_name ? "#{expression}.is_a?(Qt::#{class_name})" : "#{expression}.respond_to?(:handle)"
|
|
1097
|
+
elsif arg[:cast].is_a?(String) && arg[:cast].end_with?('*')
|
|
1098
|
+
class_name = arg[:cast].delete_suffix('*').split('::').last
|
|
1099
|
+
if class_name.match?(/\AQ[A-Z]\w*\z/)
|
|
1100
|
+
"#{expression}.is_a?(Qt::#{class_name})"
|
|
1101
|
+
else
|
|
1102
|
+
"#{expression}.respond_to?(:handle)"
|
|
1103
|
+
end
|
|
1104
|
+
else
|
|
1105
|
+
case arg[:ffi]
|
|
1106
|
+
when :string then "#{expression}.is_a?(String) || #{expression}.respond_to?(:to_str)"
|
|
1107
|
+
when :int then "#{expression}.is_a?(Integer)"
|
|
1108
|
+
when :bool then "#{expression} == true || #{expression} == false"
|
|
1109
|
+
when :pointer then "#{expression}.nil? || #{expression}.respond_to?(:handle)"
|
|
1110
|
+
else 'true'
|
|
1111
|
+
end
|
|
1112
|
+
end
|
|
1113
|
+
"#{prefix}(#{predicate})#{suffix}"
|
|
929
1114
|
end
|
|
930
1115
|
|
|
931
1116
|
def assign_unique_native_method_names(specs)
|
|
932
1117
|
used = Set.new
|
|
933
1118
|
specs.map do |spec|
|
|
934
|
-
|
|
1119
|
+
method_groups = spec[:methods].group_by { |method| method[:ruby_name] }
|
|
1120
|
+
methods = spec[:methods].map do |original|
|
|
1121
|
+
method = original.merge(dispatch: method_groups[original[:ruby_name]].length > 1 ||
|
|
1122
|
+
original.fetch(:required_arg_count, original[:args].length) < original[:args].length)
|
|
935
1123
|
assign_unique_native_method_name(spec, method, used)
|
|
936
1124
|
end
|
|
937
1125
|
spec.merge(methods: methods)
|
|
938
1126
|
end
|
|
939
1127
|
end
|
|
940
1128
|
|
|
1129
|
+
def virtual_wire_argument(arg)
|
|
1130
|
+
return { kind: :integer } if arg[:ffi] == :int
|
|
1131
|
+
return { kind: :boolean } if arg[:ffi] == :bool
|
|
1132
|
+
return { kind: :string } if arg[:ffi] == :string && arg[:cast] == :qstring
|
|
1133
|
+
return { kind: :value, qt_class: arg[:value_class] } if arg[:cast] == :qt_value_ref
|
|
1134
|
+
return { kind: :value, qt_class: 'QIcon' } if arg[:cast] == :qicon_ref
|
|
1135
|
+
|
|
1136
|
+
if arg[:ffi] == :pointer && arg[:cast].is_a?(String) && arg[:cast].end_with?('*')
|
|
1137
|
+
qt_class = arg[:cast].delete_suffix('*').split('::').last
|
|
1138
|
+
return { kind: :pointer, qt_class: qt_class } if qt_class.match?(/\AQ[A-Z]\w*\z/)
|
|
1139
|
+
end
|
|
1140
|
+
nil
|
|
1141
|
+
end
|
|
1142
|
+
|
|
1143
|
+
def virtual_wire_return(method)
|
|
1144
|
+
return { kind: :void } if method[:ffi_return] == :void
|
|
1145
|
+
return { kind: :integer } if method[:ffi_return] == :int
|
|
1146
|
+
return { kind: :boolean } if method[:ffi_return] == :bool
|
|
1147
|
+
return { kind: :string } if method[:ffi_return] == :string && method[:return_cast] == :qstring_to_utf8
|
|
1148
|
+
return { kind: :value, qt_class: method[:value_class] } if method[:return_cast] == :qt_value_copy
|
|
1149
|
+
return { kind: :pointer, qt_class: method[:pointer_class] } if method[:ffi_return] == :pointer && method[:pointer_class]
|
|
1150
|
+
|
|
1151
|
+
nil
|
|
1152
|
+
end
|
|
1153
|
+
|
|
1154
|
+
def virtual_method_wire_spec(method)
|
|
1155
|
+
return nil unless method[:virtual] && !method[:static] && !method[:final]
|
|
1156
|
+
return nil if method[:qt_name].start_with?('qt_') || forbidden_auto_exportable_method_name?(method[:qt_name])
|
|
1157
|
+
return nil unless method[:args].length == method[:cpp_params].length
|
|
1158
|
+
|
|
1159
|
+
args = method[:args].map { |arg| virtual_wire_argument(arg) }
|
|
1160
|
+
result = virtual_wire_return(method)
|
|
1161
|
+
return nil if args.any?(&:nil?) || result.nil?
|
|
1162
|
+
|
|
1163
|
+
{ args: args, return: result }
|
|
1164
|
+
end
|
|
1165
|
+
|
|
1166
|
+
def assign_virtual_method_ids(specs, ast:)
|
|
1167
|
+
next_id = 1
|
|
1168
|
+
class_index = ast_class_index(ast)
|
|
1169
|
+
specs.map do |spec|
|
|
1170
|
+
constructor_mode = spec.dig(:constructor, :mode)
|
|
1171
|
+
adapter_available = constructor_mode != :wrap_only && constructor_mode != :qapplication &&
|
|
1172
|
+
!class_index[:abstract_by_class][spec[:qt_class]] &&
|
|
1173
|
+
!class_index[:final_by_class][spec[:qt_class]]
|
|
1174
|
+
methods = spec[:methods].map do |method|
|
|
1175
|
+
wire_spec = virtual_method_wire_spec(method)
|
|
1176
|
+
next method unless adapter_available && wire_spec
|
|
1177
|
+
|
|
1178
|
+
result = method.merge(virtual_method_id: next_id, virtual_wire: wire_spec)
|
|
1179
|
+
next_id += 1
|
|
1180
|
+
result
|
|
1181
|
+
end
|
|
1182
|
+
spec.merge(
|
|
1183
|
+
methods: methods,
|
|
1184
|
+
virtual_adapter: adapter_available && methods.any? { |method| method[:virtual_method_id] }
|
|
1185
|
+
)
|
|
1186
|
+
end
|
|
1187
|
+
end
|
|
1188
|
+
|
|
1189
|
+
def generated_virtual_subclass_name(spec)
|
|
1190
|
+
"QtRubyGenerated#{spec[:qt_class].gsub(/[^A-Za-z0-9_]/, '_')}Override"
|
|
1191
|
+
end
|
|
1192
|
+
|
|
1193
|
+
def cpp_virtual_argument_wire_lines(arg, index)
|
|
1194
|
+
expression = "arg#{index + 1}"
|
|
1195
|
+
wire = virtual_wire_argument(arg)
|
|
1196
|
+
case wire&.dig(:kind)
|
|
1197
|
+
when :integer then ["arguments.append(static_cast<int>(#{expression}));"]
|
|
1198
|
+
when :boolean then ["arguments.append(#{expression});"]
|
|
1199
|
+
when :string then ["arguments.append(#{expression});"]
|
|
1200
|
+
when :pointer, :value
|
|
1201
|
+
pointer_expr = wire[:kind] == :pointer ? expression : "&#{expression}"
|
|
1202
|
+
[
|
|
1203
|
+
"if (#{pointer_expr}) {",
|
|
1204
|
+
" arguments.append(QString::number(static_cast<qulonglong>(reinterpret_cast<quintptr>(#{pointer_expr}))));",
|
|
1205
|
+
'} else {',
|
|
1206
|
+
' arguments.append(QJsonValue(QJsonValue::Null));',
|
|
1207
|
+
'}'
|
|
1208
|
+
]
|
|
1209
|
+
else
|
|
1210
|
+
[]
|
|
1211
|
+
end
|
|
1212
|
+
end
|
|
1213
|
+
|
|
1214
|
+
def cpp_virtual_fallback_lines(method, spec, arg_names, indent: ' ')
|
|
1215
|
+
invocation = "#{spec[:qt_class]}::#{method[:qt_name]}(#{arg_names.join(', ')})"
|
|
1216
|
+
if method[:ffi_return] == :void
|
|
1217
|
+
["#{indent}#{invocation};", "#{indent}return;"]
|
|
1218
|
+
else
|
|
1219
|
+
["#{indent}return #{invocation};"]
|
|
1220
|
+
end
|
|
1221
|
+
end
|
|
1222
|
+
|
|
1223
|
+
def cpp_virtual_response_lines(method, indent: ' ')
|
|
1224
|
+
wire_return = method.dig(:virtual_wire, :return)
|
|
1225
|
+
value = 'response_object.value(QStringLiteral("value"))'
|
|
1226
|
+
case wire_return[:kind]
|
|
1227
|
+
when :void
|
|
1228
|
+
["#{indent}return;"]
|
|
1229
|
+
when :integer
|
|
1230
|
+
["#{indent}return static_cast<#{method[:cpp_return_type]}>(#{value}.toInt());"]
|
|
1231
|
+
when :boolean
|
|
1232
|
+
["#{indent}return #{value}.toBool();"]
|
|
1233
|
+
when :string
|
|
1234
|
+
["#{indent}return #{value}.toString();"]
|
|
1235
|
+
when :pointer
|
|
1236
|
+
[
|
|
1237
|
+
"#{indent}const quintptr address = static_cast<quintptr>(#{value}.toString().toULongLong());",
|
|
1238
|
+
"#{indent}return reinterpret_cast<#{method[:cpp_return_type]}>(address);"
|
|
1239
|
+
]
|
|
1240
|
+
when :value
|
|
1241
|
+
[
|
|
1242
|
+
"#{indent}const quintptr address = static_cast<quintptr>(#{value}.toString().toULongLong());",
|
|
1243
|
+
"#{indent}if (address == 0) return #{method[:cpp_return_type]}();",
|
|
1244
|
+
"#{indent}return *reinterpret_cast<#{method[:cpp_return_type]}*>(address);"
|
|
1245
|
+
]
|
|
1246
|
+
else
|
|
1247
|
+
[]
|
|
1248
|
+
end
|
|
1249
|
+
end
|
|
1250
|
+
|
|
1251
|
+
def generate_cpp_virtual_adapter(lines, spec)
|
|
1252
|
+
methods = spec[:methods].select { |method| method[:virtual_method_id] }
|
|
1253
|
+
return if methods.empty?
|
|
1254
|
+
|
|
1255
|
+
adapter_name = generated_virtual_subclass_name(spec)
|
|
1256
|
+
lines << "class #{adapter_name} final : public #{spec[:qt_class]} {"
|
|
1257
|
+
lines << 'public:'
|
|
1258
|
+
lines << " using #{spec[:qt_class]}::#{spec[:qt_class]};"
|
|
1259
|
+
lines << " ~#{adapter_name}() { QtRubyRuntime::set_virtual_dispatch_enabled(this, 0); }"
|
|
1260
|
+
lines << ''
|
|
1261
|
+
methods.each do |method|
|
|
1262
|
+
arg_names = method[:args].each_index.map { |index| "arg#{index + 1}" }
|
|
1263
|
+
cpp_params = method[:cpp_params].each_with_index.map { |type, index| "#{type} #{arg_names[index]}" }
|
|
1264
|
+
const_qualifier = method[:cpp_const] ? ' const' : ''
|
|
1265
|
+
lines << " #{method[:cpp_return_type]} #{method[:qt_name]}(#{cpp_params.join(', ')})#{const_qualifier} override {"
|
|
1266
|
+
lines << " if (!QtRubyRuntime::virtual_dispatch_enabled(const_cast<#{adapter_name}*>(this))) {"
|
|
1267
|
+
lines.concat(cpp_virtual_fallback_lines(method, spec, arg_names, indent: ' '))
|
|
1268
|
+
lines << ' }'
|
|
1269
|
+
lines << " if (QtRubyRuntime::ruby_virtual_method_active(this, #{method[:virtual_method_id]})) {"
|
|
1270
|
+
lines.concat(cpp_virtual_fallback_lines(method, spec, arg_names))
|
|
1271
|
+
lines << ' }'
|
|
1272
|
+
lines << ' QJsonArray arguments;'
|
|
1273
|
+
method[:args].each_with_index do |arg, index|
|
|
1274
|
+
cpp_virtual_argument_wire_lines(arg, index).each { |line| lines << " #{line}" }
|
|
1275
|
+
end
|
|
1276
|
+
lines << ' const QByteArray payload = QJsonDocument(arguments).toJson(QJsonDocument::Compact);'
|
|
1277
|
+
lines << " const QByteArray response = QtRubyRuntime::dispatch_virtual_method(this, #{method[:virtual_method_id]}, payload);"
|
|
1278
|
+
lines << ' QJsonParseError response_error;'
|
|
1279
|
+
lines << ' const QJsonDocument response_document = QJsonDocument::fromJson(response, &response_error);'
|
|
1280
|
+
lines << ' const QJsonObject response_object = response_document.object();'
|
|
1281
|
+
lines << ' if (response_error.error == QJsonParseError::NoError && response_object.value(QStringLiteral("handled")).toBool()) {'
|
|
1282
|
+
lines.concat(cpp_virtual_response_lines(method))
|
|
1283
|
+
lines << ' }'
|
|
1284
|
+
lines.concat(cpp_virtual_fallback_lines(method, spec, arg_names, indent: ' '))
|
|
1285
|
+
lines << ' }'
|
|
1286
|
+
lines << ''
|
|
1287
|
+
end
|
|
1288
|
+
lines << '};'
|
|
1289
|
+
lines << ''
|
|
1290
|
+
end
|
|
1291
|
+
|
|
941
1292
|
def assign_unique_native_method_name(spec, method, used)
|
|
942
1293
|
native_name = default_method_function_name(spec, method)
|
|
943
1294
|
return used_add_and_return(used, native_name, method) unless used.include?(native_name)
|
|
@@ -1039,16 +1390,35 @@ end
|
|
|
1039
1390
|
|
|
1040
1391
|
def append_ruby_widgets_classes(lines, specs, super_qt_by_qt, wrapper_qt_classes)
|
|
1041
1392
|
qapplication_spec = specs.find { |spec| spec[:ruby_class] == 'QApplication' }
|
|
1042
|
-
generate_ruby_qapplication(lines, qapplication_spec)
|
|
1043
|
-
|
|
1044
1393
|
specs_by_qt = specs.each_with_object({}) { |spec, map| map[spec[:qt_class]] = spec }
|
|
1045
1394
|
qt_to_ruby = build_qt_to_ruby_map(specs, wrapper_qt_classes)
|
|
1046
1395
|
emitted_qts = qts_to_emit(specs, wrapper_qt_classes)
|
|
1047
1396
|
emit_qt_classes(lines, emitted_qts, specs_by_qt, super_qt_by_qt, qt_to_ruby)
|
|
1397
|
+
generate_ruby_qapplication(
|
|
1398
|
+
lines,
|
|
1399
|
+
qapplication_spec,
|
|
1400
|
+
super_ruby: qt_to_ruby[super_qt_by_qt['QApplication']]
|
|
1401
|
+
)
|
|
1048
1402
|
end
|
|
1049
1403
|
|
|
1050
1404
|
def generate_ruby_widgets(specs, super_qt_by_qt, wrapper_qt_classes)
|
|
1051
1405
|
lines = ruby_widgets_prelude_lines
|
|
1406
|
+
descriptors = specs.flat_map do |spec|
|
|
1407
|
+
spec[:methods].filter_map do |method|
|
|
1408
|
+
next unless method[:virtual_method_id]
|
|
1409
|
+
|
|
1410
|
+
{
|
|
1411
|
+
id: method[:virtual_method_id],
|
|
1412
|
+
wrapper_class: spec[:ruby_class],
|
|
1413
|
+
ruby_name: ruby_safe_method_name(method[:ruby_name]),
|
|
1414
|
+
snake_name: to_snake(ruby_safe_method_name(method[:ruby_name])),
|
|
1415
|
+
args: method[:virtual_wire][:args],
|
|
1416
|
+
return: method[:virtual_wire][:return]
|
|
1417
|
+
}
|
|
1418
|
+
end
|
|
1419
|
+
end
|
|
1420
|
+
lines << " GENERATED_VIRTUAL_METHODS = #{descriptors.inspect}.freeze"
|
|
1421
|
+
lines << '' unless descriptors.empty?
|
|
1052
1422
|
append_ruby_widgets_classes(lines, specs, super_qt_by_qt, wrapper_qt_classes)
|
|
1053
1423
|
|
|
1054
1424
|
lines << 'end'
|
|
@@ -1173,6 +1543,7 @@ def collect_qt_scoped_enum_constants(ast, warnings = [])
|
|
|
1173
1543
|
next unless owner.match?(/\AQ[A-Z]\w*\z/)
|
|
1174
1544
|
next if owner == 'Qt' || owner == 'QEvent'
|
|
1175
1545
|
|
|
1546
|
+
next_value = 0
|
|
1176
1547
|
Array(node['inner']).each do |entry|
|
|
1177
1548
|
next unless entry['kind'] == 'EnumConstantDecl'
|
|
1178
1549
|
|
|
@@ -1181,7 +1552,13 @@ def collect_qt_scoped_enum_constants(ast, warnings = [])
|
|
|
1181
1552
|
|
|
1182
1553
|
raw_value = ast_extract_first_value(entry)
|
|
1183
1554
|
value = parse_ast_integer_value(raw_value)
|
|
1184
|
-
|
|
1555
|
+
value = next_value if value.nil? && !next_value.nil?
|
|
1556
|
+
if value.nil?
|
|
1557
|
+
next_value = nil
|
|
1558
|
+
next
|
|
1559
|
+
end
|
|
1560
|
+
|
|
1561
|
+
next_value = value + 1
|
|
1185
1562
|
|
|
1186
1563
|
append_constant_with_conflict_warning(
|
|
1187
1564
|
constants_by_owner[owner],
|
|
@@ -1240,7 +1617,9 @@ base_specs = timed('build_base_specs') { build_base_specs(ast) }
|
|
|
1240
1617
|
timed('validate_qt_api') { validate_qt_api!(ast, base_specs) }
|
|
1241
1618
|
expanded_specs = timed('expand_auto_methods') { expand_auto_methods(base_specs, ast) }
|
|
1242
1619
|
property_specs = timed('enrich_specs_with_properties') { enrich_specs_with_properties(expanded_specs, ast) }
|
|
1243
|
-
effective_specs = timed('assign_unique_native_method_names')
|
|
1620
|
+
effective_specs = timed('assign_unique_native_method_names') do
|
|
1621
|
+
assign_virtual_method_ids(assign_unique_native_method_names(property_specs), ast: ast)
|
|
1622
|
+
end
|
|
1244
1623
|
super_qt_by_qt, wrapper_qt_classes = timed('build_generated_inheritance') do
|
|
1245
1624
|
build_generated_inheritance(ast, effective_specs)
|
|
1246
1625
|
end
|