From f3248c8531e1500db79f73fb01c426f7c3dfeeff Mon Sep 17 00:00:00 2001 From: Rico Tzschichholz Date: Wed, 2 Oct 2019 09:29:06 +0200 Subject: [PATCH] codegen: Support gobject property of null-terminated array without length Properly evaluate given array_length and array_null_terminated attributes on properties to create the expected API. Fixes https://gitlab.gnome.org/GNOME/vala/issues/855 --- codegen/valaccodebasemodule.vala | 14 +++--- codegen/valagobjectmodule.vala | 16 +++--- codegen/valagtypemodule.vala | 8 +-- tests/Makefile.am | 1 + tests/objects/property-array.vala | 84 +++++++++++++++++++++++++++++++ vala/valapropertyaccessor.vala | 3 ++ vala/valasemanticanalyzer.vala | 7 ++- 7 files changed, 114 insertions(+), 19 deletions(-) create mode 100644 tests/objects/property-array.vala diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index 012c78081..548ec58a6 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -1586,7 +1586,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { function.add_parameter (cvalueparam); } - if (acc.value_type is ArrayType) { + if (acc.value_type is ArrayType && get_ccode_array_length (prop)) { var array_type = (ArrayType) acc.value_type; var length_ctype = get_ccode_array_length_type (array_type); for (int dim = 1; dim <= array_type.rank; dim++) { @@ -1680,7 +1680,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { function.add_parameter (cvalueparam); } - if (acc.value_type is ArrayType) { + if (acc.value_type is ArrayType && get_ccode_array_length (prop)) { var array_type = (ArrayType) acc.value_type; var length_ctype = get_ccode_array_length_type (array_type); for (int dim = 1; dim <= array_type.rank; dim++) { @@ -1734,7 +1734,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { vcall.add_argument (new CCodeIdentifier ("result")); ccode.add_expression (vcall); } else { - if (acc.value_type is ArrayType) { + if (acc.value_type is ArrayType && get_ccode_array_length (prop)) { var array_type = (ArrayType) acc.value_type; for (int dim = 1; dim <= array_type.rank; dim++) { @@ -1752,7 +1752,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { vcall.add_argument (new CCodeIdentifier ("self")); vcall.add_argument (new CCodeIdentifier ("value")); - if (acc.value_type is ArrayType) { + if (acc.value_type is ArrayType && get_ccode_array_length (prop)) { var array_type = (ArrayType) acc.value_type; for (int dim = 1; dim <= array_type.rank; dim++) { @@ -1804,7 +1804,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { function.add_parameter (cvalueparam); } - if (acc.value_type is ArrayType) { + if (acc.value_type is ArrayType && get_ccode_array_length (prop)) { var array_type = (ArrayType) acc.value_type; var length_ctype = get_ccode_array_length_type (array_type); for (int dim = 1; dim <= array_type.rank; dim++) { @@ -1862,7 +1862,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { var get_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (get_accessor))); get_call.add_argument (new CCodeIdentifier (is_virtual ? "base" : "self")); - if (property_type is ArrayType) { + if (property_type is ArrayType && get_ccode_array_length (prop)) { ccode.add_declaration (get_ccode_array_length_type (property_type), new CCodeVariableDeclarator ("old_value_length")); get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value_length"))); ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_call, new CCodeIdentifier ("value"))); @@ -3852,7 +3852,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { } // return array length if appropriate - if (((current_method != null && get_ccode_array_length (current_method)) || current_property_accessor != null) && current_return_type is ArrayType) { + if (((current_method != null && get_ccode_array_length (current_method)) || (current_property_accessor != null && get_ccode_array_length (current_property_accessor.prop))) && current_return_type is ArrayType) { var temp_value = store_temp_value (stmt.return_expression.target_value, stmt); var array_type = (ArrayType) current_return_type; diff --git a/codegen/valagobjectmodule.vala b/codegen/valagobjectmodule.vala index a54242882..65726fe68 100644 --- a/codegen/valagobjectmodule.vala +++ b/codegen/valagobjectmodule.vala @@ -263,7 +263,7 @@ public class Vala.GObjectModule : GTypeModule { ccall = new CCodeFunctionCall (cfunc); ccall.add_argument (cself); var array_type = prop.property_type as ArrayType; - if (array_type != null && array_type.element_type.type_symbol == string_type.type_symbol) { + if (array_type != null && get_ccode_array_length (prop) && array_type.element_type.type_symbol == string_type.type_symbol) { // G_TYPE_STRV ccode.open_block (); ccode.add_declaration ("int", new CCodeVariableDeclarator ("length")); @@ -278,7 +278,7 @@ public class Vala.GObjectModule : GTypeModule { csetcall.add_argument (new CCodeIdentifier ("value")); csetcall.add_argument (ccall); add_guarded_expression (prop, csetcall); - if (array_type != null && array_type.element_type.type_symbol == string_type.type_symbol) { + if (array_type != null && get_ccode_array_length (prop) && array_type.element_type.type_symbol == string_type.type_symbol) { ccode.close (); } } @@ -355,12 +355,14 @@ public class Vala.GObjectModule : GTypeModule { ccode.add_assignment (new CCodeIdentifier ("boxed"), cgetcall); ccall.add_argument (new CCodeIdentifier ("boxed")); - var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("boxed"), new CCodeConstant ("NULL")); - var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length")); - cstrvlen.add_argument (new CCodeIdentifier ("boxed")); - var ccond = new CCodeConditionalExpression (cisnull, new CCodeConstant ("0"), cstrvlen); + if (get_ccode_array_length (prop)) { + var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("boxed"), new CCodeConstant ("NULL")); + var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length")); + cstrvlen.add_argument (new CCodeIdentifier ("boxed")); + var ccond = new CCodeConditionalExpression (cisnull, new CCodeConstant ("0"), cstrvlen); - ccall.add_argument (ccond); + ccall.add_argument (ccond); + } add_guarded_expression (prop, ccall); ccode.close (); } else { diff --git a/codegen/valagtypemodule.vala b/codegen/valagtypemodule.vala index 56bf3188d..7f05bfd7c 100644 --- a/codegen/valagtypemodule.vala +++ b/codegen/valagtypemodule.vala @@ -348,7 +348,7 @@ public class Vala.GTypeModule : GErrorModule { } var array_type = prop.property_type as ArrayType; - if (array_type != null) { + if (array_type != null && get_ccode_array_length (prop)) { var length_ctype = get_ccode_array_length_type (array_type) + "*"; for (int dim = 1; dim <= array_type.rank; dim++) { vdeclarator.add_parameter (new CCodeParameter (get_array_length_cname ("result", dim), length_ctype)); @@ -379,7 +379,7 @@ public class Vala.GTypeModule : GErrorModule { vdeclarator.add_parameter (cvalueparam); var array_type = prop.property_type as ArrayType; - if (array_type != null) { + if (array_type != null && get_ccode_array_length (prop)) { var length_ctype = get_ccode_array_length_type (array_type); for (int dim = 1; dim <= array_type.rank; dim++) { vdeclarator.add_parameter (new CCodeParameter (get_array_length_cname ("value", dim), length_ctype)); @@ -2156,7 +2156,7 @@ public class Vala.GTypeModule : GErrorModule { } var array_type = prop.property_type as ArrayType; - if (array_type != null) { + if (array_type != null && get_ccode_array_length (prop)) { var length_ctype = get_ccode_array_length_type (array_type) + "*"; for (int dim = 1; dim <= array_type.rank; dim++) { vdeclarator.add_parameter (new CCodeParameter (get_array_length_cname ("result", dim), length_ctype)); @@ -2179,7 +2179,7 @@ public class Vala.GTypeModule : GErrorModule { } var array_type = prop.property_type as ArrayType; - if (array_type != null) { + if (array_type != null && get_ccode_array_length (prop)) { var length_ctype = get_ccode_array_length_type (array_type); for (int dim = 1; dim <= array_type.rank; dim++) { vdeclarator.add_parameter (new CCodeParameter (get_array_length_cname ("value", dim), length_ctype)); diff --git a/tests/Makefile.am b/tests/Makefile.am index 3efdffbba..bc3f0773e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -321,6 +321,7 @@ TESTS = \ objects/paramspec.vala \ objects/plugin-module-init.vala \ objects/properties.vala \ + objects/property-array.vala \ objects/property-notify.vala \ objects/property-ownership.vala \ objects/property-read-only-auto.vala \ diff --git a/tests/objects/property-array.vala b/tests/objects/property-array.vala new file mode 100644 index 000000000..0c7eaae0c --- /dev/null +++ b/tests/objects/property-array.vala @@ -0,0 +1,84 @@ +public struct Manam { + public int i; +} + +public class Foo { + public Manam?[] array { get; set; } + + public virtual Manam?[] array_v { get; set; } + + [CCode (array_length = false, array_null_terminated = true)] + public Manam?[] array_no_length { get; set; } + + [CCode (array_length = false, array_null_terminated = true)] + public virtual Manam?[] array_no_length_v { get; set; } + + [CCode (array_length = false, array_null_terminated = true)] + public string[] strv { set; get; } + + [CCode (array_length = false, array_null_terminated = true)] + public virtual string[] strv_v { set; get; } +} + +public class Bar : Object { + [CCode (array_length = false, array_null_terminated = true)] + public Manam?[] array { get; set; } + + [CCode (array_length = false, array_null_terminated = true)] + public virtual Manam?[] array_v { get; set; } + + [CCode (array_length = false, array_null_terminated = true)] + public string[] strv { set; get; } + + [CCode (array_length = false, array_null_terminated = true)] + public virtual string[] strv_v { set; get; } +} + +void main () { + Manam?[] manam = { Manam () { i = 23 }, Manam () { i = 42 }, null }; + string[] minim = { "foo", "bar", null }; + + { + var foo = new Foo (); + + foo.array = manam; + assert (foo.array[0].i == 23); + foo.array_v = manam; + assert (foo.array_v[1].i == 42); + + foo.array_no_length = manam; + assert (foo.array_no_length[0].i == 23); + foo.array_no_length_v = manam; + assert (foo.array_no_length_v[1].i == 42); + + foo.strv = minim; + assert (foo.strv[0] == "foo"); + foo.strv_v = minim; + assert (foo.strv_v[1] == "bar"); + } + { + var bar = new Bar (); + + bar.array = manam; + assert (bar.array[0].i == 23); + bar.array_v = manam; + assert (bar.array_v[1].i == 42); + + bar.strv = minim; + assert (bar.strv[0] == "foo"); + bar.strv_v = minim; + assert (bar.strv_v[1] == "bar"); + + unowned Manam?[] res; + bar.get ("array", out res); + assert (res[0].i == 23); + bar.get ("array-v", out res); + assert (res[1].i == 42); + + unowned string[] strv; + bar.get ("strv", out strv); + assert (strv[0] == "foo"); + bar.get ("strv-v", out strv); + assert (strv[1] == "bar"); + } +} diff --git a/vala/valapropertyaccessor.vala b/vala/valapropertyaccessor.vala index d98aebc3a..553777afb 100644 --- a/vala/valapropertyaccessor.vala +++ b/vala/valapropertyaccessor.vala @@ -156,6 +156,9 @@ public class Vala.PropertyAccessor : Subroutine { if (writable || construction) { value_parameter = new Parameter ("value", value_type, source_reference); + // Inherit important atttributes + value_parameter.copy_attribute_bool (prop, "CCode", "array_length"); + value_parameter.copy_attribute_bool (prop, "CCode", "array_null_terminated"); } if (context.profile == Profile.GOBJECT diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index 30c4dadf3..f9eae2b07 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -432,7 +432,12 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } if (!is_gobject_property_type (prop.property_type)) { - return false; + if (prop.property_type is ArrayType && (!prop.get_attribute_bool ("CCode", "array_length", true) + && prop.get_attribute_bool ("CCode", "array_null_terminated", false))) { + // null-terminated arrays without length are allowed + } else { + return false; + } } if (type_sym is Class && prop.base_interface_property != null && -- 2.47.2