[vala/0.40] codegen: Correctly handle signals returning real non-nullable struct



commit e72b805ebdc4abb71dcae0bcae5fccfb9f884eaa
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Sun Apr 12 11:02:29 2020 +0200

    codegen: Correctly handle signals returning real non-nullable struct
    
    Fixes https://gitlab.gnome.org/GNOME/vala/issues/466

 codegen/valagsignalmodule.vala           | 97 +++++++++++++++++++++-----------
 tests/Makefile.am                        |  1 +
 tests/objects/signals-struct-return.vala | 46 +++++++++++++++
 3 files changed, 111 insertions(+), 33 deletions(-)
---
diff --git a/codegen/valagsignalmodule.vala b/codegen/valagsignalmodule.vala
index c22fb6cf6..b9b8eaa77 100644
--- a/codegen/valagsignalmodule.vala
+++ b/codegen/valagsignalmodule.vala
@@ -24,8 +24,8 @@
 
 
 public class Vala.GSignalModule : GObjectModule {
-       string get_marshaller_function (List<Parameter> params, DataType return_type, string? prefix = null) {
-               var signature = get_marshaller_signature (params, return_type);
+       string get_marshaller_function (Signal sig, List<Parameter> params, DataType return_type, string? 
prefix = null) {
+               var signature = get_marshaller_signature (sig, params, return_type);
                string ret;
 
                if (prefix == null) {
@@ -37,13 +37,14 @@ public class Vala.GSignalModule : GObjectModule {
                }
                
                ret = "%s_%s_".printf (prefix, get_ccode_marshaller_type_name (return_type));
-               
-               if (params == null || params.size == 0) {
+
+               foreach (Parameter p in params) {
+                       ret = "%s_%s".printf (ret, get_ccode_marshaller_type_name (p).replace (",", "_"));
+               }
+               if (sig.return_type.is_real_non_null_struct_type ()) {
+                       ret = ret + "_POINTER";
+               } else if (params.size == 0) {
                        ret = ret + "_VOID";
-               } else {
-                       foreach (Parameter p in params) {
-                               ret = "%s_%s".printf (ret, get_ccode_marshaller_type_name (p).replace (",", 
"_"));
-                       }
                }
                
                return ret;
@@ -92,25 +93,26 @@ public class Vala.GSignalModule : GObjectModule {
                        return get_value_type_name_from_type_reference (p.variable_type);
                }
        }
-       
-       private string get_marshaller_signature (List<Parameter> params, DataType return_type) {
+
+       private string get_marshaller_signature (Signal sig, List<Parameter> params, DataType return_type) {
                string signature;
                
                signature = "%s:".printf (get_ccode_marshaller_type_name (return_type));
-               if (params == null || params.size == 0) {
-                       signature = signature + "VOID";
-               } else {
-                       bool first = true;
-                       foreach (Parameter p in params) {
-                               if (first) {
-                                       signature = signature + get_ccode_marshaller_type_name (p);
-                                       first = false;
-                               } else {
-                                       signature = "%s,%s".printf (signature, get_ccode_marshaller_type_name 
(p));
-                               }
+               bool first = true;
+               foreach (Parameter p in params) {
+                       if (first) {
+                               signature = signature + get_ccode_marshaller_type_name (p);
+                               first = false;
+                       } else {
+                               signature = "%s,%s".printf (signature, get_ccode_marshaller_type_name (p));
                        }
                }
-               
+               if (sig.return_type.is_real_non_null_struct_type ()) {
+                       signature = signature + (first ? "POINTER" : ",POINTER");
+               } else if (params.size == 0) {
+                       signature = signature + "VOID";
+               }
+
                return signature;
        }
 
@@ -195,24 +197,29 @@ public class Vala.GSignalModule : GObjectModule {
                sig.accept_children (this);
 
                // declare parameter type
-               foreach (Parameter p in sig.get_parameters ()) {
+               var params = sig.get_parameters ();
+               foreach (Parameter p in params) {
                        generate_parameter (p, cfile, new HashMap<int,CCodeParameter> (), null);
                }
 
-               generate_marshaller (sig.get_parameters (), sig.return_type);
+               if (sig.return_type.is_real_non_null_struct_type ()) {
+                       generate_marshaller (sig, params, new VoidType ());
+               } else {
+                       generate_marshaller (sig, params, sig.return_type);
+               }
        }
 
-       void generate_marshaller (List<Parameter> params, DataType return_type) {
+       void generate_marshaller (Signal sig, List<Parameter> params, DataType return_type) {
                string signature;
                int n_params, i;
                
                /* check whether a signal with the same signature already exists for this source file (or 
predefined) */
-               signature = get_marshaller_signature (params, return_type);
+               signature = get_marshaller_signature (sig, params, return_type);
                if (predefined_marshal_set.contains (signature) || user_marshal_set.contains (signature)) {
                        return;
                }
-               
-               var signal_marshaller = new CCodeFunction (get_marshaller_function (params, return_type, 
null), "void");
+
+               var signal_marshaller = new CCodeFunction (get_marshaller_function (sig, params, return_type, 
null), "void");
                signal_marshaller.modifiers = CCodeModifiers.STATIC;
                
                signal_marshaller.add_parameter (new CCodeParameter ("closure", "GClosure *"));
@@ -224,7 +231,7 @@ public class Vala.GSignalModule : GObjectModule {
 
                push_function (signal_marshaller);
 
-               var callback_decl = new CCodeFunctionDeclarator (get_marshaller_function (params, 
return_type, "GMarshalFunc"));
+               var callback_decl = new CCodeFunctionDeclarator (get_marshaller_function (sig, params, 
return_type, "GMarshalFunc"));
                callback_decl.add_parameter (new CCodeParameter ("data1", "gpointer"));
                n_params = 1;
                foreach (Parameter p in params) {
@@ -247,10 +254,15 @@ public class Vala.GSignalModule : GObjectModule {
                                }
                        }
                }
+               if (sig.return_type.is_real_non_null_struct_type ()) {
+                       callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), 
"gpointer"));
+                       n_params++;
+               }
+
                callback_decl.add_parameter (new CCodeParameter ("data2", "gpointer"));
                ccode.add_statement (new CCodeTypeDefinition (get_value_type_name_from_type_reference 
(return_type), callback_decl));
 
-               ccode.add_declaration (get_marshaller_function (params, return_type, "GMarshalFunc"), new 
CCodeVariableDeclarator ("callback"), CCodeModifiers.REGISTER);
+               ccode.add_declaration (get_marshaller_function (sig, params, return_type, "GMarshalFunc"), 
new CCodeVariableDeclarator ("callback"), CCodeModifiers.REGISTER);
 
                ccode.add_declaration ("GCClosure *", new CCodeVariableDeclarator ("cc", new 
CCodeCastExpression (new CCodeIdentifier ("closure"), "GCClosure *")), CCodeModifiers.REGISTER);
 
@@ -283,7 +295,7 @@ public class Vala.GSignalModule : GObjectModule {
                ccode.add_assignment (new CCodeIdentifier ("data2"), data);
                ccode.close ();
 
-               var c_assign_rhs =  new CCodeCastExpression (new CCodeConditionalExpression (new 
CCodeIdentifier ("marshal_data"), new CCodeIdentifier ("marshal_data"), new CCodeMemberAccess (new 
CCodeIdentifier ("cc"), "callback", true)), get_marshaller_function (params, return_type, "GMarshalFunc"));
+               var c_assign_rhs =  new CCodeCastExpression (new CCodeConditionalExpression (new 
CCodeIdentifier ("marshal_data"), new CCodeIdentifier ("marshal_data"), new CCodeMemberAccess (new 
CCodeIdentifier ("cc"), "callback", true)), get_marshaller_function (sig, params, return_type, 
"GMarshalFunc"));
                ccode.add_assignment (new CCodeIdentifier ("callback"), c_assign_rhs);
                
                fc = new CCodeFunctionCall (new CCodeIdentifier ("callback"));
@@ -324,6 +336,12 @@ public class Vala.GSignalModule : GObjectModule {
                                }
                        }
                }
+               if (sig.return_type.is_real_non_null_struct_type ()) {
+                       var inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
+                       inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new 
CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
+                       fc.add_argument (inner_fc);
+                       i++;
+               }
                fc.add_argument (new CCodeIdentifier ("data2"));
                
                if (return_type.data_type != null || return_type.is_array ()) {
@@ -405,12 +423,17 @@ public class Vala.GSignalModule : GObjectModule {
                csignew.add_argument (new CCodeConstant ("NULL"));
                csignew.add_argument (new CCodeConstant ("NULL"));
 
-               string marshaller = get_marshaller_function (sig.get_parameters (), sig.return_type);
+               var params = sig.get_parameters ();
+               string marshaller;
+               if (sig.return_type.is_real_non_null_struct_type ()) {
+                       marshaller = get_marshaller_function (sig, params, new VoidType ());
+               } else {
+                       marshaller = get_marshaller_function (sig, params, sig.return_type);
+               }
 
                var marshal_arg = new CCodeIdentifier (marshaller);
                csignew.add_argument (marshal_arg);
 
-               var params = sig.get_parameters ();
                if (sig.return_type is PointerType || sig.return_type is GenericType) {
                        csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
                } else if (sig.return_type is ErrorType) {
@@ -419,6 +442,8 @@ public class Vala.GSignalModule : GObjectModule {
                        csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
                } else if (sig.return_type.data_type == null) {
                        csignew.add_argument (new CCodeConstant ("G_TYPE_NONE"));
+               } else if (sig.return_type.is_real_non_null_struct_type ()) {
+                       csignew.add_argument (new CCodeConstant ("G_TYPE_NONE"));
                } else {
                        csignew.add_argument (new CCodeConstant (get_ccode_type_id 
(sig.return_type.data_type)));
                }
@@ -438,6 +463,9 @@ public class Vala.GSignalModule : GObjectModule {
                                }
                        }
                }
+               if (sig.return_type.is_real_non_null_struct_type ()) {
+                       params_len++;
+               }
 
                csignew.add_argument (new CCodeConstant ("%d".printf (params_len)));
                foreach (Parameter param in params) {
@@ -469,6 +497,9 @@ public class Vala.GSignalModule : GObjectModule {
                                csignew.add_argument (new CCodeConstant (get_ccode_type_id 
(param.variable_type.data_type)));
                        }
                }
+               if (sig.return_type.is_real_non_null_struct_type ()) {
+                       csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
+               }
 
                marshal_arg.name = marshaller;
 
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 126d3daa2..7f52a72bb 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -346,6 +346,7 @@ TESTS = \
        objects/signals-delegate-parameter.vala \
        objects/signals-fundamental-return.vala \
        objects/signals-gobject-return.vala \
+       objects/signals-struct-return.vala \
        objects/test-025.vala \
        objects/test-026.vala \
        objects/test-029.vala \
diff --git a/tests/objects/signals-struct-return.vala b/tests/objects/signals-struct-return.vala
new file mode 100644
index 000000000..4790d9d9d
--- /dev/null
+++ b/tests/objects/signals-struct-return.vala
@@ -0,0 +1,46 @@
+struct Foo {
+       public string s;
+       public int i;
+}
+
+class Bar : Object {
+       public signal Foo on_foo ();
+       public signal Foo on_foo_with_arg (string s);
+       public signal Foo? on_bar ();
+       public signal Foo? on_bar_with_arg (string s);
+}
+
+void main () {
+       {
+               var bar = new Bar ();
+               bar.on_foo.connect (() => {
+                       return { "foo", 23 };
+               });
+               bar.on_foo_with_arg.connect ((s) => {
+                       assert (s == "foo");
+                       return { "foo", 42 };
+               });
+               var foo = bar.on_foo ();
+               assert (foo.s == "foo");
+               assert (foo.i == 23);
+               var foo2 = bar.on_foo_with_arg ("foo");
+               assert (foo2.s == "foo");
+               assert (foo2.i == 42);
+       }
+       {
+               var bar = new Bar ();
+               bar.on_bar.connect (() => {
+                       return { "bar", 42 };
+               });
+               bar.on_bar_with_arg.connect ((s) => {
+                       assert (s == "bar");
+                       return { "bar", 23 };
+               });
+               var foo = bar.on_bar ();
+               assert (foo.s == "bar");
+               assert (foo.i == 42);
+               var foo2 = bar.on_bar_with_arg ("bar");
+               assert (foo2.s == "bar");
+               assert (foo2.i == 23);
+       }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]