[gjs/march-maintenance: 7/11] wrapperutils: Move is_custom_js_class()



commit 81b81abdf992637e11d41db8bf4ecace5a9e7ff4
Author: Philip Chimento <philip chimento gmail com>
Date:   Wed Mar 11 22:32:22 2020 -0700

    wrapperutils: Move is_custom_js_class()
    
    This name of GIWrapperBase::is_custom_js_class() is misleading. If there
    is no GI introspection info, then the class may be a custom JS class,
    but it could also be an internal class not exposed through
    introspection, like GLocalFile.
    
    In most cases is_custom_js_class() can just be replaced with !info().
    
    In one case of existing usage of is_custom_js_class(), we really do mean
    it, in add_property_impl(). For this we check the custom_type_quark() on
    the GType. For better readability, this adds an is_custom_js_class()
    method to ObjectBase which actually does what it says.
    
    See also #299 and commit 74171bf3ae91ff64337b6261fe024e34e073f86f.

 gi/interface.cpp  |  2 +-
 gi/object.cpp     | 33 ++++++++++++++++++---------------
 gi/object.h       |  1 +
 gi/wrapperutils.h | 31 +++++++++++++++----------------
 4 files changed, 35 insertions(+), 32 deletions(-)
---
diff --git a/gi/interface.cpp b/gi/interface.cpp
index 7ad150ec..3dc0a362 100644
--- a/gi/interface.cpp
+++ b/gi/interface.cpp
@@ -56,7 +56,7 @@ bool InterfacePrototype::resolve_impl(JSContext* context, JS::HandleObject obj,
     /* If we have no GIRepository information then this interface was defined
      * from within GJS. In that case, it has no properties that need to be
      * resolved from within C code, as interfaces cannot inherit. */
-    if (is_custom_js_class()) {
+    if (!info()) {
         *resolved = false;
         return true;
     }
diff --git a/gi/object.cpp b/gi/object.cpp
index 7bc942b9..96e2062a 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -107,6 +107,10 @@ gjs_object_priv_quark (void)
     return val;
 }
 
+bool ObjectBase::is_custom_js_class() {
+    return !!g_type_get_qdata(gtype(), ObjectBase::custom_type_quark());
+}
+
 // Plain g_type_query fails and leaves @query uninitialized for dynamic types.
 // See https://gitlab.gnome.org/GNOME/glib/issues/623
 void ObjectBase::type_query_dynamic_safe(GTypeQuery* query) {
@@ -673,8 +677,7 @@ bool ObjectPrototype::resolve_no_info(JSContext* cx, JS::HandleObject obj,
 
     /* Fallback to GType system for non custom GObjects with no GI information
      */
-    if (canonical_name && G_TYPE_IS_CLASSED(m_gtype) &&
-        !g_type_get_qdata(m_gtype, ObjectInstance::custom_type_quark())) {
+    if (canonical_name && G_TYPE_IS_CLASSED(m_gtype) && !is_custom_js_class()) {
         GjsAutoTypeClass<GObjectClass> oclass(m_gtype);
 
         if (g_object_class_find_property(oclass, canonical_name))
@@ -786,10 +789,11 @@ bool ObjectPrototype::resolve_impl(JSContext* context, JS::HandleObject obj,
 bool ObjectPrototype::uncached_resolve(JSContext* context, JS::HandleObject obj,
                                        JS::HandleId id, const char* name,
                                        bool* resolved) {
-    /* If we have no GIRepository information (we're a JS GObject subclass),
-     * we need to look at exposing interfaces. Look up our interfaces through
-     * GType data, and then hope that *those* are introspectable. */
-    if (is_custom_js_class())
+    // If we have no GIRepository information (we're a JS GObject subclass or an
+    // internal non-introspected class such as GLocalFile), we need to look at
+    // exposing interfaces. Look up our interfaces through GType data, and then
+    // hope that *those* are introspectable.
+    if (!info())
         return resolve_no_info(context, obj, id, resolved, name,
                                ConsiderMethodsAndProperties);
 
@@ -962,7 +966,7 @@ bool ObjectPrototype::new_enumerate_impl(JSContext* cx, JS::HandleObject,
 
     g_free(interfaces);
 
-    if (!is_custom_js_class()) {
+    if (info()) {
         // Methods
         int n_methods = g_object_info_get_n_methods(info());
         for (int i = 0; i < n_methods; i++) {
@@ -1517,11 +1521,9 @@ ObjectInstance::init_impl(JSContext              *context,
         return false;
     }
 
-    /* Mark this object in the construction stack, it
-       will be popped in gjs_object_custom_init() later
-       down.
-    */
-    if (g_type_get_qdata(gtype(), ObjectInstance::custom_type_quark())) {
+    // Mark this object in the construction stack, it will be popped in
+    // gjs_object_custom_init() in gi/gobject.cpp.
+    if (is_custom_js_class()) {
         GjsContextPrivate* gjs = GjsContextPrivate::from_cx(context);
         if (!gjs->object_init_list().append(object)) {
             JS_ReportOutOfMemory(context);
@@ -1763,9 +1765,10 @@ gjs_lookup_object_prototype(JSContext *context,
 // The caller does not own the return value, and it can never be null.
 GIFieldInfo* ObjectPrototype::lookup_cached_field_info(JSContext* cx,
                                                        JS::HandleString key) {
-    if (is_custom_js_class()) {
-        // Custom JS classes can't have fields. We must be looking up a field on
-        // a GObject-introspected parent.
+    if (!info()) {
+        // Custom JS classes can't have fields, and fields on internal classes
+        // are not available. We must be looking up a field on a
+        // GObject-introspected parent.
         GType parent_gtype = g_type_parent(m_gtype);
         g_assert(parent_gtype != G_TYPE_INVALID &&
                  "Custom JS class must have parent");
diff --git a/gi/object.h b/gi/object.h
index 583ba1d4..b6f11e5c 100644
--- a/gi/object.h
+++ b/gi/object.h
@@ -137,6 +137,7 @@ class ObjectBase
     }
 
     bool id_is_never_lazy(jsid name, const GjsAtoms& atoms);
+    GJS_USE bool is_custom_js_class();
 
  public:
     void type_query_dynamic_safe(GTypeQuery* query);
diff --git a/gi/wrapperutils.h b/gi/wrapperutils.h
index bcb3203a..e8f1f430 100644
--- a/gi/wrapperutils.h
+++ b/gi/wrapperutils.h
@@ -287,18 +287,16 @@ class GIWrapperBase {
     GJS_USE GIBaseInfo* info(void) const { return get_prototype()->info(); }
     GJS_USE GType gtype(void) const { return get_prototype()->gtype(); }
 
-    // The next four methods are operations derived from the GIFooInfo.
+    // The next three methods are operations derived from the GIFooInfo.
 
-    GJS_USE bool is_custom_js_class(void) const { return !info(); }
     GJS_USE const char* type_name(void) const { return g_type_name(gtype()); }
     GJS_USE
     const char* ns(void) const {
-        return is_custom_js_class() ? "" : g_base_info_get_namespace(info());
+        return info() ? g_base_info_get_namespace(info()) : "";
     }
     GJS_USE
     const char* name(void) const {
-        return is_custom_js_class() ? type_name()
-                                    : g_base_info_get_name(info());
+        return info() ? g_base_info_get_name(info()) : type_name();
     }
 
  private:
@@ -739,9 +737,10 @@ template <class Base, class Prototype, class Instance,
           typename Info = GIObjectInfo>
 class GIWrapperPrototype : public Base {
  protected:
-    // m_info may be null in the case of JS-defined types, although not all
-    // subclasses will allow this. Object and Interface allow it in any case.
-    // Use the method Base::is_custom_js_class() for clarity.
+    // m_info may be null in the case of JS-defined types, or internal types
+    // not exposed through introspection, such as GLocalFile. Not all subclasses
+    // of GIWrapperPrototype support this. Object and Interface support it in
+    // any case.
     Info* m_info;
     GType m_gtype;
 
@@ -856,10 +855,10 @@ class GIWrapperPrototype : public Base {
                         JS::MutableHandleObject prototype) {
         // The GI namespace is only used to set the JSClass->name field (exposed
         // by Object.prototype.toString, for example). We can safely set
-        // "unknown" if this is a custom JS class with no GI namespace, as in
-        // that case the name is already globally unique (it's a GType name).
-        const char* gi_namespace =
-            Base::is_custom_js_class() ? "unknown" : Base::ns();
+        // "unknown" if this is a custom or internal JS class with no GI
+        // namespace, as in that case the name is already globally unique (it's
+        // a GType name).
+        const char* gi_namespace = Base::info() ? Base::ns() : "unknown";
 
         unsigned nargs = static_cast<Prototype*>(this)->constructor_nargs();
 
@@ -892,6 +891,8 @@ class GIWrapperPrototype : public Base {
      */
     GJS_JSAPI_RETURN_CONVENTION
     bool define_static_methods(JSContext* cx, JS::HandleObject constructor) {
+        if (!info())
+            return true;  // no introspection means no methods to define
         return gjs_define_static_methods<Prototype::info_type_tag>(
             cx, constructor, m_gtype, m_info);
     }
@@ -963,10 +964,8 @@ class GIWrapperPrototype : public Base {
                 return nullptr;
         }
 
-        if (!priv->is_custom_js_class()) {
-            if (!priv->define_static_methods(cx, constructor))
-                return nullptr;
-        }
+        if (!priv->define_static_methods(cx, constructor))
+            return nullptr;
 
         return priv;
     }


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