[glibmm] gmmproc: _WRAP_PROPERTY: Check the data type



commit 203063d1b7a8bcc9bb0ffb9e8bbbfe5d5832a944
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Thu Jan 31 13:41:01 2019 +0100

    gmmproc: _WRAP_PROPERTY: Check the data type
    
    * glib/glibmm/value_custom.h: Add template class
    Glib::Traits::ValueCompatibleWithWrapProperty<> that checks if the template
    parameter names a type that can be used with _WRAP_PROPERTY
    and _WRAP_CHILD_PROPERTY.
    * tools/m4/property.m4:
    * tools/pm/Output.pm:
    * tools/pm/WrapParser.pm: _WRAP_PROPERTY and _WRAP_CHILD_PROPERTY generate
    a static_assert() that checks if the data type is acceptable. The generation
    of the static_assert() can be suppressed with the new no_type_check parameter.

 glib/glibmm/value_custom.h | 35 +++++++++++++++++++++++++++++++++++
 tools/m4/property.m4       | 10 ++++++++--
 tools/pm/Output.pm         | 44 ++++++++++++++++++++++++++++++++------------
 tools/pm/WrapParser.pm     | 17 ++++++++++++-----
 4 files changed, 87 insertions(+), 19 deletions(-)
---
diff --git a/glib/glibmm/value_custom.h b/glib/glibmm/value_custom.h
index 7c23a8d2..e5c19895 100644
--- a/glib/glibmm/value_custom.h
+++ b/glib/glibmm/value_custom.h
@@ -99,6 +99,10 @@ template <class T, typename Enable = void>
 class Value : public ValueBase_Boxed
 {
 public:
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+  // Used in class Glib::Traits::ValueCompatibleWithWrapProperty.
+  using dont_use_with_wrap_property_ = int;
+#endif
   using CppType = T;
 
   static GType value_type() G_GNUC_CONST;
@@ -283,6 +287,37 @@ Value<T, Enable>::value_copy_func(const GValue* src_value, GValue* dest_value)
   dest_value->data[0].v_pointer = new (std::nothrow) T(source);
 }
 
+namespace Traits
+{
+/** Helper class for testing if Glib::Value<T> would instantiate a Glib::Value
+ * that can be used in _WRAP_PROPERTY and _WRAP_CHILD_PROPERTY.
+ *
+ * Some instantiations of Glib::Value, such as instantiations of the primary
+ * template, generate code which is useless but compilable when generated by
+ * _WRAP_PROPERTY and _WRAP_CHILD_PROPERTY.
+ */
+template <typename T>
+class ValueCompatibleWithWrapProperty
+{
+private:
+  struct big
+  {
+    int memory[64];
+  };
+
+  static big check_type(...);
+
+  // If Glib::Value<X>::dont_use_with_wrap_property_ is not a type, this check_type()
+  // overload is ignored because of the SFINAE rule (Substitution Failure Is Not An Error).
+  template <typename X>
+  static typename Glib::Value<X>::dont_use_with_wrap_property_ check_type(X* obj);
+
+public:
+  static const bool value = sizeof(check_type(static_cast<T*>(nullptr))) == sizeof(big);
+};
+
+} // namespace Traits
+
 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
 
 } // namespace Glib
diff --git a/tools/m4/property.m4 b/tools/m4/property.m4
index 1709affa..c4544ded 100644
--- a/tools/m4/property.m4
+++ b/tools/m4/property.m4
@@ -4,8 +4,8 @@ dnl  Code generation sections for properties
 dnl
 dnl
 
-dnl                  $1         $2            $3          $4           $5        $6
-dnl _PROPERTY_PROXY(name, name_underscored, cpp_type, proxy_suffix, deprecated, docs)
+dnl                  $1         $2            $3          $4           $5        $6      $7
+dnl _PROPERTY_PROXY(name, name_underscored, cpp_type, proxy_suffix, deprecated, docs, check_type)
 dnl proxy_suffix could be "", "_WriteOnly" or "_ReadOnly"
 dnl The method will be const if the propertyproxy is _ReadOnly.
 dnl
@@ -24,6 +24,12 @@ ifelse($4,_ReadOnly,get,`ifelse($4,_WriteOnly,set,get or set)') the value of the
   __PROXY_TYPE__ property_$2`'() ifelse($4,_ReadOnly, const,);
 _PUSH(SECTION_CC_PROPERTYPROXIES)
 ifelse(`$5',,,`_DEPRECATE_IFDEF_START
+')dnl
+ifelse(`$7',,,`dnl
+static_assert(`$7'<_QUOTE($3)>::value,
+  "Type _QUOTE($3) cannot be used in _WRAP_PROPERTY. "
+  "There is no suitable template specialization of Glib::Value<>.");
+
 ')dnl
 __PROXY_TYPE__ __CPPNAME__::property_$2`'() ifelse($4,_ReadOnly, const,)
 {
diff --git a/tools/pm/Output.pm b/tools/pm/Output.pm
index 5fcfc9d6..a7bdc8cf 100644
--- a/tools/pm/Output.pm
+++ b/tools/pm/Output.pm
@@ -860,11 +860,12 @@ sub output_wrap_gerror($$$$$$$$$$$$$)
 }
 
 # _PROPERTY_PROXY(name, cpp_type) and _CHILD_PROPERTY_PROXY(name, cpp_type)
-# void output_wrap_any_property($filename, $line_num, $name, $cpp_type, $c_class, $deprecated, 
$deprecation_docs, $objProperty, $proxy_macro)
+# void output_wrap_any_property($filename, $line_num, $name, $cpp_type, $c_class,
+#   $deprecated, $deprecation_docs, $newin, $bNoTypeCheck, $objProperty, $proxy_macro)
 sub output_wrap_any_property($$$$$$$$$$)
 {
   my ($self, $filename, $line_num, $name, $cpp_type, $c_class, $deprecated,
-      $deprecation_docs, $newin, $objProperty, $proxy_macro) = @_;
+      $deprecation_docs, $newin, $bNoTypeCheck, $objProperty, $proxy_macro) = @_;
 
   my $objDefsParser = $$self{objDefsParser};
 
@@ -950,19 +951,34 @@ sub output_wrap_any_property($$$$$$$$$$)
     $documentation .= $default_value;
   }
 
+  # Possibly generate a static_assert(), asserting that the generated code
+  # will include a Glib::Value instantiation which is compatible with
+  # _WRAP_PROPERTY and _WRAP_CHILD_PROPERTY.
+  # This test is skipped for some types that are known to have suitable
+  # Glib::Value<> instantiations, or if the no_type_check parameter is specified.
+  my $check_type = "";
+  if (!$bNoTypeCheck)
+  {
+    my @good_types = qw(bool int guint float double std::string Glib::ustring
+                        Widget* Gtk::Widget*);
+    push(@good_types, "unsigned int");
+    $check_type = "Glib::Traits::ValueCompatibleWithWrapProperty" if (!grep {$cpp_type eq $_} @good_types);
+  }
+
   #Declaration:
   if($deprecated ne "")
   {
     $self->append("\n_DEPRECATE_IFDEF_START\n");
   }
 
-  my $str = sprintf("$proxy_macro(%s,%s,%s,%s,%s,`%s')dnl\n",
+  my $str = sprintf("$proxy_macro(%s,%s,%s,%s,%s,`%s',`%s')dnl\n",
     $name,
     $name_underscored,
     $cpp_type,
     $proxy_suffix,
     $deprecated,
-    $documentation
+    $documentation,
+    $check_type
   );
   $self->append($str);
   $self->append("\n");
@@ -971,13 +987,15 @@ sub output_wrap_any_property($$$$$$$$$$)
   # then add a second const accessor for a read-only propertyproxy:
   if( ($proxy_suffix ne "_ReadOnly") && ($objProperty->get_readable()) )
   {
-    my $str = sprintf("$proxy_macro(%s,%s,%s,%s,%s,`%s')dnl\n",
+    $check_type = ""; # Don't check twice.
+    my $str = sprintf("$proxy_macro(%s,%s,%s,%s,%s,`%s',`%s')dnl\n",
       $name,
       $name_underscored,
       $cpp_type,
       "_ReadOnly",
       $deprecated,
-      $documentation
+      $documentation,
+      $check_type
     );
     $self->append($str);
   }
@@ -990,11 +1008,11 @@ sub output_wrap_any_property($$$$$$$$$$)
 
 # _PROPERTY_PROXY(name, cpp_type)
 # void output_wrap_property($filename, $line_num, $name, $cpp_type, $file_deprecated,
-#   $deprecated, $deprecation_docs)
+#   $deprecated, $deprecation_docs, $newin, $bNoTypeCheck)
 sub output_wrap_property($$$$$$$$$$)
 {
   my ($self, $filename, $line_num, $name, $cpp_type, $c_class, $file_deprecated,
-      $deprecated, $deprecation_docs, $newin) = @_;
+      $deprecated, $deprecation_docs, $newin, $bNoTypeCheck) = @_;
 
   my $objProperty = GtkDefs::lookup_property($c_class, $name);
   if($objProperty eq 0) #If the lookup failed:
@@ -1007,17 +1025,18 @@ sub output_wrap_property($$$$$$$$$$)
       $deprecated, $name, "property", "PROPERTY");
 
     $self->output_wrap_any_property($filename, $line_num, $name, $cpp_type, $c_class,
-      $deprecated, $deprecation_docs, $newin, $objProperty, "_PROPERTY_PROXY");
+      $deprecated, $deprecation_docs, $newin, $bNoTypeCheck, $objProperty,
+      "_PROPERTY_PROXY");
   }
 }
 
 # _CHILD_PROPERTY_PROXY(name, cpp_type)
 # void output_wrap_child_property($filename, $line_num, $name, $cpp_type, $file_deprecated,
-#   $deprecated, $deprecation_docs)
+#   $deprecated, $deprecation_docs, $newin, $bNoTypeCheck)
 sub output_wrap_child_property($$$$$$$$$$)
 {
   my ($self, $filename, $line_num, $name, $cpp_type, $c_class, $file_deprecated,
-      $deprecated, $deprecation_docs, $newin) = @_;
+      $deprecated, $deprecation_docs, $newin, $bNoTypeCheck) = @_;
 
   my $objChildProperty = GtkDefs::lookup_child_property($c_class, $name);
   if($objChildProperty eq 0) #If the lookup failed:
@@ -1030,7 +1049,8 @@ sub output_wrap_child_property($$$$$$$$$$)
       $deprecated, $name, "child property", "CHILD_PROPERTY");
 
     $self->output_wrap_any_property($filename, $line_num, $name, $cpp_type, $c_class,
-      $deprecated, $deprecation_docs, $newin, $objChildProperty, "_CHILD_PROPERTY_PROXY");
+      $deprecated, $deprecation_docs, $newin, $bNoTypeCheck, $objChildProperty,
+      "_CHILD_PROPERTY_PROXY");
   }
 }
 
diff --git a/tools/pm/WrapParser.pm b/tools/pm/WrapParser.pm
index 36adfc4f..20af0f03 100644
--- a/tools/pm/WrapParser.pm
+++ b/tools/pm/WrapParser.pm
@@ -1600,6 +1600,7 @@ sub on_wrap_any_property($)
   my $argDeprecated = "";
   my $deprecation_docs = "";
   my $newin = "";
+  my $bNoTypeCheck = 0;
   while($#args >= 2) # If the optional arguments are there.
   {
     my $argRef = string_trim(pop @args);
@@ -1617,10 +1618,14 @@ sub on_wrap_any_property($)
     {
       $newin = string_unquote(string_trim($1));
     }
+    elsif($argRef eq "no_type_check")
+    {
+      $bNoTypeCheck = 1;
+    }
   }
 
   return ($filename, $line_num, $argPropertyName, $argCppType,
-          $argDeprecated, $deprecation_docs, $newin);
+          $argDeprecated, $deprecation_docs, $newin, $bNoTypeCheck);
 }
 
 sub on_wrap_property($)
@@ -1631,10 +1636,11 @@ sub on_wrap_property($)
   return unless ($self->check_for_eof());
 
   my ($filename, $line_num, $argPropertyName, $argCppType, $argDeprecated,
-      $deprecation_docs, $newin) = $self->on_wrap_any_property();
+      $deprecation_docs, $newin, $bNoTypeCheck) = $self->on_wrap_any_property();
 
   $objOutputter->output_wrap_property($filename, $line_num, $argPropertyName,
-    $argCppType, $$self{c_class}, $$self{deprecated}, $argDeprecated, $deprecation_docs, $newin);
+    $argCppType, $$self{c_class}, $$self{deprecated}, $argDeprecated, $deprecation_docs,
+    $newin, $bNoTypeCheck);
 }
 
 sub on_wrap_child_property($)
@@ -1645,10 +1651,11 @@ sub on_wrap_child_property($)
   return unless ($self->check_for_eof());
 
   my ($filename, $line_num, $argPropertyName, $argCppType, $argDeprecated,
-      $deprecation_docs, $newin) = $self->on_wrap_any_property();
+      $deprecation_docs, $newin, $bNoTypeCheck) = $self->on_wrap_any_property();
 
   $objOutputter->output_wrap_child_property($filename, $line_num, $argPropertyName,
-    $argCppType, $$self{c_class}, $$self{deprecated}, $argDeprecated, $deprecation_docs, $newin);
+    $argCppType, $$self{c_class}, $$self{deprecated}, $argDeprecated, $deprecation_docs,
+    $newin, $bNoTypeCheck);
 }
 
 sub output_wrap_check($$$$$$)


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