Support introspectable=no attribute, add warnings framework
authorColin Walters <walters@verbum.org>
Thu, 17 Jun 2010 00:34:18 +0000 (20:34 -0400)
committerColin Walters <walters@verbum.org>
Thu, 17 Jun 2010 01:58:18 +0000 (21:58 -0400)
This work allows us to move closer to replacing gtk-doc, among other
things.  We add a generic attribute "introspectable", and inside the
typelib compiler if we see "introspectable=no", we don't put it in the
typelib.  This replaces the hackish pre-filter for varargs with a much
more generic mechanism.

The varargs is now handled in the scanner, and we emit
introspectable=no for them.

Add generic metadata to Node with references to file/line/column,
which currently comes from symbols.

Add scanner options --Wall and --Werror.

gir/Makefile.am
girepository/girparser.c
girepository/girparser.h
giscanner/ast.py
giscanner/girwriter.py
giscanner/glibtransformer.py
giscanner/scannermain.py
giscanner/sourcescanner.py
giscanner/transformer.py
tests/scanner/Makefile.am
tests/scanner/foo-1.0-expected.gir

index 1d88accd6e39838f82f10d0d5cfafc46d73040c7..99b305cbede116c44f4022b1baaa65da8cc62089 100644 (file)
@@ -118,7 +118,7 @@ endif
 Gio-2.0.gir: GObject-2.0.gir
 
 Gio_2_0_gir_LIBS = $(GIO_LIBRARY)
-Gio_2_0_gir_SCANNERFLAGS = --noclosure --strip-prefix=g --c-include="gio/gio.h" --add-include-path=.
+Gio_2_0_gir_SCANNERFLAGS = --Wall --strip-prefix=g --c-include="gio/gio.h" --add-include-path=.
 Gio_2_0_gir_PACKAGES = gio-2.0 $(GIO_UNIX_PACKAGES)
 Gio_2_0_gir_INCLUDES = GObject-2.0
 Gio_2_0_gir_CFLAGS = \
index d0bd8aa36c2396470f8c37a9355d985e6a4930c3..a0c1e21ddff77234c7bf6f674ac8209661b00dac 100644 (file)
@@ -72,10 +72,10 @@ typedef enum
   STATE_NAMESPACE_CONSTANT,
   STATE_CLASS_CONSTANT,
   STATE_INTERFACE_CONSTANT,
-  STATE_ALIAS,
+  STATE_ALIAS, /* 30 */
   STATE_TYPE,
   STATE_ATTRIBUTE,
-  STATE_UNKNOWN
+  STATE_PASSTHROUGH
 } ParseState;
 
 typedef struct _ParseContext ParseContext;
@@ -93,12 +93,12 @@ struct _ParseContext
   GHashTable *aliases;
   GHashTable *disguised_structures;
 
+  const char *file_path;
   const char *namespace;
   const char *c_prefix;
   GIrModule *current_module;
   GSList *node_stack;
   GIrNode *current_typed;
-  gboolean is_varargs;
   GList *type_stack;
   GList *type_parameters;
   int type_depth;
@@ -317,7 +317,7 @@ find_attribute (const gchar  *name,
 static void
 state_switch (ParseContext *ctx, ParseState newstate)
 {
-  g_debug ("State: %d", newstate);
+  g_assert (ctx->state != newstate);
   ctx->prev_state = ctx->state;
   ctx->state = newstate;
 }
@@ -339,6 +339,7 @@ pop_node (ParseContext *ctx)
 static void
 push_node (ParseContext *ctx, GIrNode *node)
 {
+  g_assert (node != NULL);
   g_debug ("pushing node %d %s", node->type, node->name);
   ctx->node_stack = g_slist_prepend (ctx->node_stack, node);
 }
@@ -629,6 +630,32 @@ parse_type (ParseContext *ctx, const gchar *type)
   return node;
 }
 
+static gboolean
+introspectable_prelude (GMarkupParseContext *context,
+                   const gchar        **attribute_names,
+                   const gchar        **attribute_values,
+                   ParseContext        *ctx,
+                   ParseState           new_state)
+{
+  const gchar *introspectable_arg;
+  gboolean introspectable;
+
+  g_assert (ctx->state != STATE_PASSTHROUGH);
+
+  introspectable_arg = find_attribute ("introspectable", attribute_names, attribute_values);
+  introspectable = !(introspectable_arg && atoi (introspectable_arg) == 0);
+
+  if (introspectable)
+    state_switch (ctx, new_state);
+  else
+    {
+      state_switch (ctx, STATE_PASSTHROUGH);
+      ctx->unknown_depth = 1;
+    }
+
+  return introspectable;
+}
+
 static gboolean
 start_glib_boxed (GMarkupParseContext *context,
                  const gchar         *element_name,
@@ -647,6 +674,9 @@ start_glib_boxed (GMarkupParseContext *context,
        ctx->state == STATE_NAMESPACE))
     return FALSE;
 
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_BOXED))
+    return TRUE;
+
   name = find_attribute ("glib:name", attribute_names, attribute_values);
   typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
   typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
@@ -682,8 +712,6 @@ start_glib_boxed (GMarkupParseContext *context,
   ctx->current_module->entries =
     g_list_append (ctx->current_module->entries, boxed);
 
-  state_switch (ctx, STATE_BOXED);
-
   return TRUE;
 }
 
@@ -722,7 +750,6 @@ start_function (GMarkupParseContext *context,
               strcmp (element_name, "callback") == 0);
       break;
     case STATE_STRUCT_FIELD:
-      ctx->in_embedded_type = TRUE;
       found = (found || strcmp (element_name, "callback") == 0);
       break;
     default:
@@ -732,6 +759,12 @@ start_function (GMarkupParseContext *context,
   if (!found)
     return FALSE;
 
+  if (ctx->state == STATE_STRUCT_FIELD)
+    ctx->in_embedded_type = TRUE;
+
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION))
+    return TRUE;
+
   name = find_attribute ("name", attribute_names, attribute_values);
   symbol = find_attribute ("c:identifier", attribute_names, attribute_values);
   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
@@ -835,7 +868,6 @@ start_function (GMarkupParseContext *context,
       }
 
   push_node(ctx, (GIrNode *)function);
-  state_switch (ctx, STATE_FUNCTION);
 
   return TRUE;
 }
@@ -1218,47 +1250,47 @@ start_enum (GMarkupParseContext *context,
             ParseContext        *ctx,
             GError             **error)
 {
-  if ((strcmp (element_name, "enumeration") == 0 && ctx->state == STATE_NAMESPACE) ||
-      (strcmp (element_name, "bitfield") == 0 && ctx->state == STATE_NAMESPACE))
-    {
-      const gchar *name;
-      const gchar *typename;
-      const gchar *typeinit;
-      const gchar *deprecated;
+  const gchar *name;
+  const gchar *typename;
+  const gchar *typeinit;
+  const gchar *deprecated;
+  GIrNodeEnum *enum_;
 
-      name = find_attribute ("name", attribute_names, attribute_values);
-      typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
-      typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
-      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+  if (!((strcmp (element_name, "enumeration") == 0 && ctx->state == STATE_NAMESPACE) ||
+       (strcmp (element_name, "bitfield") == 0 && ctx->state == STATE_NAMESPACE)))
+    return FALSE;
 
-      if (name == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else
-       {
-         GIrNodeEnum *enum_;
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_ENUM))
+    return TRUE;
 
-         if (strcmp (element_name, "enumeration") == 0)
-           enum_ = (GIrNodeEnum *) g_ir_node_new (G_IR_NODE_ENUM);
-         else
-           enum_ = (GIrNodeEnum *) g_ir_node_new (G_IR_NODE_FLAGS);
-         ((GIrNode *)enum_)->name = g_strdup (name);
-         enum_->gtype_name = g_strdup (typename);
-         enum_->gtype_init = g_strdup (typeinit);
-         if (deprecated)
-           enum_->deprecated = TRUE;
-         else
-           enum_->deprecated = FALSE;
+  name = find_attribute ("name", attribute_names, attribute_values);
+  typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
+  typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
+  deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
 
-         push_node (ctx, (GIrNode *) enum_);
-         ctx->current_module->entries =
-           g_list_append (ctx->current_module->entries, enum_);
+  if (name == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
+    }
 
-         state_switch (ctx, STATE_ENUM);
-       }
+  if (strcmp (element_name, "enumeration") == 0)
+    enum_ = (GIrNodeEnum *) g_ir_node_new (G_IR_NODE_ENUM);
+  else
+    enum_ = (GIrNodeEnum *) g_ir_node_new (G_IR_NODE_FLAGS);
+  ((GIrNode *)enum_)->name = g_strdup (name);
+  enum_->gtype_name = g_strdup (typename);
+  enum_->gtype_init = g_strdup (typeinit);
+  if (deprecated)
+    enum_->deprecated = TRUE;
+  else
+    enum_->deprecated = FALSE;
 
-      return TRUE;
-    }
-  return FALSE;
+  push_node (ctx, (GIrNode *) enum_);
+  ctx->current_module->entries =
+    g_list_append (ctx->current_module->entries, enum_);
+
+  return TRUE;
 }
 
 static gboolean
@@ -1269,70 +1301,74 @@ start_property (GMarkupParseContext *context,
                ParseContext        *ctx,
                GError             **error)
 {
-  if (strcmp (element_name, "property") == 0 &&
-      (ctx->state == STATE_CLASS ||
-       ctx->state == STATE_INTERFACE))
-    {
-      const gchar *name;
-      const gchar *readable;
-      const gchar *writable;
-      const gchar *construct;
-      const gchar *construct_only;
-      const gchar *transfer;
+  ParseState target_state;
+  const gchar *name;
+  const gchar *readable;
+  const gchar *writable;
+  const gchar *construct;
+  const gchar *construct_only;
+  const gchar *transfer;
+  GIrNodeProperty *property;
+  GIrNodeInterface *iface;
 
-      name = find_attribute ("name", attribute_names, attribute_values);
-      readable = find_attribute ("readable", attribute_names, attribute_values);
-      writable = find_attribute ("writable", attribute_names, attribute_values);
-      construct = find_attribute ("construct", attribute_names, attribute_values);
-      construct_only = find_attribute ("construct-only", attribute_names, attribute_values);
-      transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
+  if (!(strcmp (element_name, "property") == 0 &&
+       (ctx->state == STATE_CLASS ||
+        ctx->state == STATE_INTERFACE)))
+    return FALSE;
 
-      if (name == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else
-       {
-         GIrNodeProperty *property;
-         GIrNodeInterface *iface;
+  if (ctx->state == STATE_CLASS)
+    target_state = STATE_CLASS_PROPERTY;
+  else if (ctx->state == STATE_INTERFACE)
+    target_state = STATE_INTERFACE_PROPERTY;
+  else
+    g_assert_not_reached ();
 
-         property = (GIrNodeProperty *) g_ir_node_new (G_IR_NODE_PROPERTY);
-         ctx->current_typed = (GIrNode*) property;
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, target_state))
+    return TRUE;
 
-         ((GIrNode *)property)->name = g_strdup (name);
 
-         /* Assume properties are readable */
-         if (readable == NULL || strcmp (readable, "1") == 0)
-           property->readable = TRUE;
-         else
-           property->readable = FALSE;
-         if (writable && strcmp (writable, "1") == 0)
-           property->writable = TRUE;
-         else
-           property->writable = FALSE;
-         if (construct && strcmp (construct, "1") == 0)
-           property->construct = TRUE;
-         else
-           property->construct = FALSE;
-         if (construct_only && strcmp (construct_only, "1") == 0)
-           property->construct_only = TRUE;
-         else
-           property->construct_only = FALSE;
+  name = find_attribute ("name", attribute_names, attribute_values);
+  readable = find_attribute ("readable", attribute_names, attribute_values);
+  writable = find_attribute ("writable", attribute_names, attribute_values);
+  construct = find_attribute ("construct", attribute_names, attribute_values);
+  construct_only = find_attribute ("construct-only", attribute_names, attribute_values);
+  transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
+
+  if (name == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
+    }
 
-          parse_property_transfer (property, transfer, ctx);
+  property = (GIrNodeProperty *) g_ir_node_new (G_IR_NODE_PROPERTY);
+  ctx->current_typed = (GIrNode*) property;
 
-         iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
-         iface->members = g_list_append (iface->members, property);
+  ((GIrNode *)property)->name = g_strdup (name);
 
-         if (ctx->state == STATE_CLASS)
-           state_switch (ctx, STATE_CLASS_PROPERTY);
-         else if (ctx->state == STATE_INTERFACE)
-           state_switch (ctx, STATE_INTERFACE_PROPERTY);
-         else
-           g_assert_not_reached ();
-       }
+  /* Assume properties are readable */
+  if (readable == NULL || strcmp (readable, "1") == 0)
+    property->readable = TRUE;
+  else
+    property->readable = FALSE;
+  if (writable && strcmp (writable, "1") == 0)
+    property->writable = TRUE;
+  else
+    property->writable = FALSE;
+  if (construct && strcmp (construct, "1") == 0)
+    property->construct = TRUE;
+  else
+    property->construct = FALSE;
+  if (construct_only && strcmp (construct_only, "1") == 0)
+    property->construct_only = TRUE;
+  else
+    property->construct_only = FALSE;
 
-      return TRUE;
-    }
-  return FALSE;
+  parse_property_transfer (property, transfer, ctx);
+
+  iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
+  iface->members = g_list_append (iface->members, property);
+
+  return TRUE;
 }
 
 static gint
@@ -1366,42 +1402,41 @@ start_member (GMarkupParseContext *context,
              ParseContext        *ctx,
              GError             **error)
 {
-  if (strcmp (element_name, "member") == 0 &&
-      ctx->state == STATE_ENUM)
-    {
-      const gchar *name;
-      const gchar *value;
-      const gchar *deprecated;
+  const gchar *name;
+  const gchar *value;
+  const gchar *deprecated;
+  GIrNodeEnum *enum_;
+  GIrNodeValue *value_;
 
-      name = find_attribute ("name", attribute_names, attribute_values);
-      value = find_attribute ("value", attribute_names, attribute_values);
-      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+  if (!(strcmp (element_name, "member") == 0 &&
+       ctx->state == STATE_ENUM))
+    return FALSE;
 
-      if (name == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else
-       {
-         GIrNodeEnum *enum_;
-         GIrNodeValue *value_;
+  name = find_attribute ("name", attribute_names, attribute_values);
+  value = find_attribute ("value", attribute_names, attribute_values);
+  deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+
+  if (name == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
+    }
 
-         value_ = (GIrNodeValue *) g_ir_node_new (G_IR_NODE_VALUE);
+  value_ = (GIrNodeValue *) g_ir_node_new (G_IR_NODE_VALUE);
 
-         ((GIrNode *)value_)->name = g_strdup (name);
+  ((GIrNode *)value_)->name = g_strdup (name);
 
-         value_->value = parse_value (value);
+  value_->value = parse_value (value);
 
-         if (deprecated)
-           value_->deprecated = TRUE;
-         else
-           value_->deprecated = FALSE;
+  if (deprecated)
+    value_->deprecated = TRUE;
+  else
+    value_->deprecated = FALSE;
 
-         enum_ = (GIrNodeEnum *)CURRENT_NODE (ctx);
-         enum_->values = g_list_append (enum_->values, value_);
-       }
+  enum_ = (GIrNodeEnum *)CURRENT_NODE (ctx);
+  enum_->values = g_list_append (enum_->values, value_);
 
-      return TRUE;
-    }
-  return FALSE;
+  return TRUE;
 }
 
 static gboolean
@@ -1412,73 +1447,81 @@ start_constant (GMarkupParseContext *context,
                ParseContext        *ctx,
                GError             **error)
 {
-  if (strcmp (element_name, "constant") == 0 &&
-      (ctx->state == STATE_NAMESPACE ||
-       ctx->state == STATE_CLASS ||
-       ctx->state == STATE_INTERFACE))
+  ParseState prev_state;
+  ParseState target_state;
+  const gchar *name;
+  const gchar *value;
+  const gchar *deprecated;
+  GIrNodeConstant *constant;
+
+  if (!(strcmp (element_name, "constant") == 0 &&
+       (ctx->state == STATE_NAMESPACE ||
+        ctx->state == STATE_CLASS ||
+        ctx->state == STATE_INTERFACE)))
+    return FALSE;
+  
+  switch (ctx->state)
     {
-      const gchar *name;
-      const gchar *value;
-      const gchar *deprecated;
+    case STATE_NAMESPACE:
+      target_state = STATE_NAMESPACE_CONSTANT;
+      break;
+    case STATE_CLASS:
+      target_state = STATE_CLASS_CONSTANT;
+      break;
+    case STATE_INTERFACE:
+      target_state = STATE_INTERFACE_CONSTANT;
+      break;
+    default:
+      g_assert_not_reached ();
+    }
 
-      name = find_attribute ("name", attribute_names, attribute_values);
-      value = find_attribute ("value", attribute_names, attribute_values);
-      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+  prev_state = ctx->state;
 
-      if (name == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else if (value == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "value");
-      else
-       {
-         GIrNodeConstant *constant;
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, target_state))
+    return TRUE;
 
-         constant = (GIrNodeConstant *) g_ir_node_new (G_IR_NODE_CONSTANT);
+  name = find_attribute ("name", attribute_names, attribute_values);
+  value = find_attribute ("value", attribute_names, attribute_values);
+  deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
 
-         ((GIrNode *)constant)->name = g_strdup (name);
-         constant->value = g_strdup (value);
+  if (name == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
+    }
+  else if (value == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "value");
+      return FALSE;
+    }
 
-         ctx->current_typed = (GIrNode*) constant;
+  constant = (GIrNodeConstant *) g_ir_node_new (G_IR_NODE_CONSTANT);
 
-         if (deprecated)
-           constant->deprecated = TRUE;
-         else
-           constant->deprecated = FALSE;
+  ((GIrNode *)constant)->name = g_strdup (name);
+  constant->value = g_strdup (value);
 
-         if (ctx->state == STATE_NAMESPACE)
-           {
-             push_node (ctx, (GIrNode *) constant);
-             ctx->current_module->entries =
-               g_list_append (ctx->current_module->entries, constant);
-           }
-         else
-           {
-             GIrNodeInterface *iface;
+  ctx->current_typed = (GIrNode*) constant;
 
-             iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
-             iface->members = g_list_append (iface->members, constant);
-           }
+  if (deprecated)
+    constant->deprecated = TRUE;
+  else
+    constant->deprecated = FALSE;
 
-         switch (ctx->state)
-           {
-           case STATE_NAMESPACE:
-             state_switch (ctx, STATE_NAMESPACE_CONSTANT);
-             break;
-           case STATE_CLASS:
-             state_switch (ctx, STATE_CLASS_CONSTANT);
-             break;
-           case STATE_INTERFACE:
-             state_switch (ctx, STATE_INTERFACE_CONSTANT);
-             break;
-           default:
-             g_assert_not_reached ();
-             break;
-           }
-       }
+  if (prev_state == STATE_NAMESPACE)
+    {
+      push_node (ctx, (GIrNode *) constant);
+      ctx->current_module->entries =
+       g_list_append (ctx->current_module->entries, constant);
+    }
+  else
+    {
+      GIrNodeInterface *iface;
 
-      return TRUE;
+      iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
+      iface->members = g_list_append (iface->members, constant);
     }
-  return FALSE;
+
+  return TRUE;
 }
 
 static gboolean
@@ -1489,50 +1532,57 @@ start_errordomain (GMarkupParseContext *context,
                   ParseContext        *ctx,
                   GError             **error)
 {
-  if (strcmp (element_name, "errordomain") == 0 &&
-      ctx->state == STATE_NAMESPACE)
-    {
-      const gchar *name;
-      const gchar *getquark;
-      const gchar *codes;
-      const gchar *deprecated;
+  const gchar *name;
+  const gchar *getquark;
+  const gchar *codes;
+  const gchar *deprecated;
+  GIrNodeErrorDomain *domain;
 
-      name = find_attribute ("name", attribute_names, attribute_values);
-      getquark = find_attribute ("get-quark", attribute_names, attribute_values);
-      codes = find_attribute ("codes", attribute_names, attribute_values);
-      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+  if (!(strcmp (element_name, "errordomain") == 0 &&
+       ctx->state == STATE_NAMESPACE))
+    return FALSE;
 
-      if (name == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else if (getquark == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "getquark");
-      else if (codes == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "codes");
-      else
-       {
-         GIrNodeErrorDomain *domain;
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_ERRORDOMAIN))
+    return TRUE;
 
-         domain = (GIrNodeErrorDomain *) g_ir_node_new (G_IR_NODE_ERROR_DOMAIN);
 
-         ((GIrNode *)domain)->name = g_strdup (name);
-         domain->getquark = g_strdup (getquark);
-         domain->codes = g_strdup (codes);
+  name = find_attribute ("name", attribute_names, attribute_values);
+  getquark = find_attribute ("get-quark", attribute_names, attribute_values);
+  codes = find_attribute ("codes", attribute_names, attribute_values);
+  deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
 
-         if (deprecated)
-           domain->deprecated = TRUE;
-         else
-           domain->deprecated = FALSE;
+  if (name == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
+    }
+  else if (getquark == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "getquark");
+      return FALSE;
+    }
+  else if (codes == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "codes");
+      return FALSE;
+    }
 
-         push_node (ctx, (GIrNode *) domain);
-         ctx->current_module->entries =
-           g_list_append (ctx->current_module->entries, domain);
+  domain = (GIrNodeErrorDomain *) g_ir_node_new (G_IR_NODE_ERROR_DOMAIN);
 
-         state_switch (ctx, STATE_ERRORDOMAIN);
-       }
+  ((GIrNode *)domain)->name = g_strdup (name);
+  domain->getquark = g_strdup (getquark);
+  domain->codes = g_strdup (codes);
 
-      return TRUE;
-    }
-  return FALSE;
+  if (deprecated)
+    domain->deprecated = TRUE;
+  else
+    domain->deprecated = FALSE;
+
+  push_node (ctx, (GIrNode *) domain);
+  ctx->current_module->entries =
+    g_list_append (ctx->current_module->entries, domain);
+
+  return TRUE;
 }
 
 static gboolean
@@ -1543,55 +1593,60 @@ start_interface (GMarkupParseContext *context,
                 ParseContext        *ctx,
                 GError             **error)
 {
-  if (strcmp (element_name, "interface") == 0 &&
-      ctx->state == STATE_NAMESPACE)
-    {
-      const gchar *name;
-      const gchar *typename;
-      const gchar *typeinit;
-      const gchar *deprecated;
-      const gchar *glib_type_struct;
-
-      name = find_attribute ("name", attribute_names, attribute_values);
-      typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
-      typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
-      glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values);
-      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
-
-      if (name == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else if (typename == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
-      else if (typeinit == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
-      else
-       {
-         GIrNodeInterface *iface;
-
-         iface = (GIrNodeInterface *) g_ir_node_new (G_IR_NODE_INTERFACE);
-         ((GIrNode *)iface)->name = g_strdup (name);
-         iface->gtype_name = g_strdup (typename);
-         iface->gtype_init = g_strdup (typeinit);
-          iface->glib_type_struct = g_strdup (glib_type_struct);
-         if (deprecated)
-           iface->deprecated = TRUE;
-         else
-           iface->deprecated = FALSE;
+  const gchar *name;
+  const gchar *typename;
+  const gchar *typeinit;
+  const gchar *deprecated;
+  const gchar *glib_type_struct;
+  GIrNodeInterface *iface;
 
-         push_node (ctx, (GIrNode *) iface);
-         ctx->current_module->entries =
-           g_list_append (ctx->current_module->entries, iface);
+  if (!(strcmp (element_name, "interface") == 0 &&
+       ctx->state == STATE_NAMESPACE))
+    return FALSE;
 
-         state_switch (ctx, STATE_INTERFACE);
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_INTERFACE))
+    return TRUE;
 
-       }
+  name = find_attribute ("name", attribute_names, attribute_values);
+  typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
+  typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
+  glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values);
+  deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
 
-      return TRUE;
+  if (name == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
     }
-  return FALSE;
-}
-
-static gboolean
+  else if (typename == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
+      return FALSE;
+    }
+  else if (typeinit == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
+      return FALSE;
+    }
+
+  iface = (GIrNodeInterface *) g_ir_node_new (G_IR_NODE_INTERFACE);
+  ((GIrNode *)iface)->name = g_strdup (name);
+  iface->gtype_name = g_strdup (typename);
+  iface->gtype_init = g_strdup (typeinit);
+  iface->glib_type_struct = g_strdup (glib_type_struct);
+  if (deprecated)
+    iface->deprecated = TRUE;
+  else
+    iface->deprecated = FALSE;
+
+  push_node (ctx, (GIrNode *) iface);
+  ctx->current_module->entries =
+    g_list_append (ctx->current_module->entries, iface);
+
+  return TRUE;
+}
+
+static gboolean
 start_class (GMarkupParseContext *context,
              const gchar         *element_name,
              const gchar        **attribute_names,
@@ -1599,58 +1654,64 @@ start_class (GMarkupParseContext *context,
              ParseContext        *ctx,
              GError             **error)
 {
-  if (strcmp (element_name, "class") == 0 &&
-      ctx->state == STATE_NAMESPACE)
-    {
-      const gchar *name;
-      const gchar *parent;
-      const gchar *glib_type_struct;
-      const gchar *typename;
-      const gchar *typeinit;
-      const gchar *deprecated;
-      const gchar *abstract;
+  const gchar *name;
+  const gchar *parent;
+  const gchar *glib_type_struct;
+  const gchar *typename;
+  const gchar *typeinit;
+  const gchar *deprecated;
+  const gchar *abstract;
+  GIrNodeInterface *iface;
 
-      name = find_attribute ("name", attribute_names, attribute_values);
-      parent = find_attribute ("parent", attribute_names, attribute_values);
-      glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values);
-      typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
-      typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
-      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
-      abstract = find_attribute ("abstract", attribute_names, attribute_values);
+  if (!(strcmp (element_name, "class") == 0 &&
+       ctx->state == STATE_NAMESPACE))
+    return FALSE;
 
-      if (name == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else if (typename == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
-      else if (typeinit == NULL && strcmp (typename, "GObject"))
-       MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
-      else
-       {
-         GIrNodeInterface *iface;
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_CLASS))
+    return TRUE;
 
-         iface = (GIrNodeInterface *) g_ir_node_new (G_IR_NODE_OBJECT);
-         ((GIrNode *)iface)->name = g_strdup (name);
-         iface->gtype_name = g_strdup (typename);
-         iface->gtype_init = g_strdup (typeinit);
-         iface->parent = g_strdup (parent);
-         iface->glib_type_struct = g_strdup (glib_type_struct);
-         if (deprecated)
-           iface->deprecated = TRUE;
-         else
-           iface->deprecated = FALSE;
+  name = find_attribute ("name", attribute_names, attribute_values);
+  parent = find_attribute ("parent", attribute_names, attribute_values);
+  glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values);
+  typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
+  typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
+  deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+  abstract = find_attribute ("abstract", attribute_names, attribute_values);
 
-         iface->abstract = abstract && strcmp (abstract, "1") == 0;
+  if (name == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
+    }
+  else if (typename == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
+      return FALSE;
+    }
+  else if (typeinit == NULL && strcmp (typename, "GObject"))
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
+      return FALSE;
+    }
 
-         push_node (ctx, (GIrNode *) iface);
-         ctx->current_module->entries =
-           g_list_append (ctx->current_module->entries, iface);
+  iface = (GIrNodeInterface *) g_ir_node_new (G_IR_NODE_OBJECT);
+  ((GIrNode *)iface)->name = g_strdup (name);
+  iface->gtype_name = g_strdup (typename);
+  iface->gtype_init = g_strdup (typeinit);
+  iface->parent = g_strdup (parent);
+  iface->glib_type_struct = g_strdup (glib_type_struct);
+  if (deprecated)
+    iface->deprecated = TRUE;
+  else
+    iface->deprecated = FALSE;
 
-         state_switch (ctx, STATE_CLASS);
-       }
+  iface->abstract = abstract && strcmp (abstract, "1") == 0;
 
-      return TRUE;
-    }
-  return  FALSE;
+  push_node (ctx, (GIrNode *) iface);
+  ctx->current_module->entries =
+    g_list_append (ctx->current_module->entries, iface);
+
+  return TRUE;
 }
 
 static gboolean
@@ -1695,47 +1756,6 @@ start_type (GMarkupParseContext *context,
     {
       state_switch (ctx, STATE_TYPE);
       ctx->type_depth = 1;
-      if (is_varargs)
-       {
-         switch (CURRENT_NODE (ctx)->type)
-           {
-           case G_IR_NODE_FUNCTION:
-           case G_IR_NODE_CALLBACK:
-             {
-               GIrNodeFunction *func = (GIrNodeFunction *)CURRENT_NODE (ctx);
-               func->is_varargs = TRUE;
-             }
-             break;
-           case G_IR_NODE_VFUNC:
-             {
-               GIrNodeVFunc *vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx);
-               vfunc->is_varargs = TRUE;
-             }
-             break;
-           /* list others individually rather than with default: so that compiler
-            * warns if new node types are added without adding them to the switch
-            */
-           case G_IR_NODE_INVALID:
-           case G_IR_NODE_ENUM:
-           case G_IR_NODE_FLAGS:
-           case G_IR_NODE_CONSTANT:
-           case G_IR_NODE_ERROR_DOMAIN:
-           case G_IR_NODE_PARAM:
-           case G_IR_NODE_TYPE:
-           case G_IR_NODE_PROPERTY:
-           case G_IR_NODE_SIGNAL:
-           case G_IR_NODE_VALUE:
-           case G_IR_NODE_FIELD:
-           case G_IR_NODE_XREF:
-           case G_IR_NODE_STRUCT:
-           case G_IR_NODE_BOXED:
-           case G_IR_NODE_OBJECT:
-           case G_IR_NODE_INTERFACE:
-           case G_IR_NODE_UNION:
-             g_assert_not_reached ();
-             break;
-           }
-       }
       ctx->type_stack = NULL;
       ctx->type_parameters = NULL;
     }
@@ -2005,53 +2025,51 @@ start_return_value (GMarkupParseContext *context,
                    ParseContext       *ctx,
                    GError             **error)
 {
-  if (strcmp (element_name, "return-value") == 0 &&
-      ctx->state == STATE_FUNCTION)
-    {
-      GIrNodeParam *param;
-      const gchar  *transfer;
+  GIrNodeParam *param;
+  const gchar  *transfer;
 
-      param = (GIrNodeParam *)g_ir_node_new (G_IR_NODE_PARAM);
-      param->in = FALSE;
-      param->out = FALSE;
-      param->retval = TRUE;
+  if (!(strcmp (element_name, "return-value") == 0 &&
+       ctx->state == STATE_FUNCTION))
+    return FALSE;
 
-      ctx->current_typed = (GIrNode*) param;
+  param = (GIrNodeParam *)g_ir_node_new (G_IR_NODE_PARAM);
+  param->in = FALSE;
+  param->out = FALSE;
+  param->retval = TRUE;
 
-      state_switch (ctx, STATE_FUNCTION_RETURN);
+  ctx->current_typed = (GIrNode*) param;
 
-      transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
-      parse_param_transfer (param, transfer, NULL);
+  state_switch (ctx, STATE_FUNCTION_RETURN);
 
-      switch (CURRENT_NODE (ctx)->type)
-       {
-       case G_IR_NODE_FUNCTION:
-       case G_IR_NODE_CALLBACK:
-         {
-           GIrNodeFunction *func = (GIrNodeFunction *)CURRENT_NODE (ctx);
-           func->result = param;
-         }
-         break;
-       case G_IR_NODE_SIGNAL:
-         {
-           GIrNodeSignal *signal = (GIrNodeSignal *)CURRENT_NODE (ctx);
-           signal->result = param;
-         }
-         break;
-       case G_IR_NODE_VFUNC:
-         {
-           GIrNodeVFunc *vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx);
-           vfunc->result = param;
-         }
-         break;
-       default:
-         g_assert_not_reached ();
-       }
+  transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
+  parse_param_transfer (param, transfer, NULL);
 
-      return TRUE;
+  switch (CURRENT_NODE (ctx)->type)
+    {
+    case G_IR_NODE_FUNCTION:
+    case G_IR_NODE_CALLBACK:
+      {
+       GIrNodeFunction *func = (GIrNodeFunction *)CURRENT_NODE (ctx);
+       func->result = param;
+      }
+      break;
+    case G_IR_NODE_SIGNAL:
+      {
+       GIrNodeSignal *signal = (GIrNodeSignal *)CURRENT_NODE (ctx);
+       signal->result = param;
+      }
+      break;
+    case G_IR_NODE_VFUNC:
+      {
+       GIrNodeVFunc *vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx);
+       vfunc->result = param;
+      }
+      break;
+    default:
+      g_assert_not_reached ();
     }
 
-  return FALSE;
+  return TRUE;
 }
 
 static gboolean
@@ -2092,78 +2110,78 @@ start_glib_signal (GMarkupParseContext *context,
                   ParseContext       *ctx,
                   GError             **error)
 {
-  if (strcmp (element_name, "glib:signal") == 0 &&
-      (ctx->state == STATE_CLASS ||
-       ctx->state == STATE_INTERFACE))
-    {
-      const gchar *name;
-      const gchar *when;
-      const gchar *no_recurse;
-      const gchar *detailed;
-      const gchar *action;
-      const gchar *no_hooks;
-      const gchar *has_class_closure;
+  const gchar *name;
+  const gchar *when;
+  const gchar *no_recurse;
+  const gchar *detailed;
+  const gchar *action;
+  const gchar *no_hooks;
+  const gchar *has_class_closure;
+  GIrNodeInterface *iface;
+  GIrNodeSignal *signal;
 
-      name = find_attribute ("name", attribute_names, attribute_values);
-      when = find_attribute ("when", attribute_names, attribute_values);
-      no_recurse = find_attribute ("no-recurse", attribute_names, attribute_values);
-      detailed = find_attribute ("detailed", attribute_names, attribute_values);
-      action = find_attribute ("action", attribute_names, attribute_values);
-      no_hooks = find_attribute ("no-hooks", attribute_names, attribute_values);
-      has_class_closure = find_attribute ("has-class-closure", attribute_names, attribute_values);
+  if (!(strcmp (element_name, "glib:signal") == 0 &&
+       (ctx->state == STATE_CLASS ||
+        ctx->state == STATE_INTERFACE)))
+    return FALSE;
 
-      if (name == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else
-       {
-         GIrNodeInterface *iface;
-         GIrNodeSignal *signal;
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION))
+    return TRUE;
 
-         signal = (GIrNodeSignal *)g_ir_node_new (G_IR_NODE_SIGNAL);
+  name = find_attribute ("name", attribute_names, attribute_values);
+  when = find_attribute ("when", attribute_names, attribute_values);
+  no_recurse = find_attribute ("no-recurse", attribute_names, attribute_values);
+  detailed = find_attribute ("detailed", attribute_names, attribute_values);
+  action = find_attribute ("action", attribute_names, attribute_values);
+  no_hooks = find_attribute ("no-hooks", attribute_names, attribute_values);
+  has_class_closure = find_attribute ("has-class-closure", attribute_names, attribute_values);
 
-         ((GIrNode *)signal)->name = g_strdup (name);
+  if (name == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
+    }
+  signal = (GIrNodeSignal *)g_ir_node_new (G_IR_NODE_SIGNAL);
 
-         signal->run_first = FALSE;
-         signal->run_last = FALSE;
-         signal->run_cleanup = FALSE;
-         if (when == NULL || strcmp (when, "LAST") == 0)
-           signal->run_last = TRUE;
-         else if (strcmp (when, "FIRST") == 0)
-           signal->run_first = TRUE;
-         else
-           signal->run_cleanup = TRUE;
+  ((GIrNode *)signal)->name = g_strdup (name);
 
-         if (no_recurse && strcmp (no_recurse, "1") == 0)
-           signal->no_recurse = TRUE;
-         else
-           signal->no_recurse = FALSE;
-         if (detailed && strcmp (detailed, "1") == 0)
-           signal->detailed = TRUE;
-         else
-           signal->detailed = FALSE;
-         if (action && strcmp (action, "1") == 0)
-           signal->action = TRUE;
-         else
-           signal->action = FALSE;
-         if (no_hooks && strcmp (no_hooks, "1") == 0)
-           signal->no_hooks = TRUE;
-         else
-           signal->no_hooks = FALSE;
-         if (has_class_closure && strcmp (has_class_closure, "1") == 0)
-           signal->has_class_closure = TRUE;
-         else
-           signal->has_class_closure = FALSE;
+  signal->run_first = FALSE;
+  signal->run_last = FALSE;
+  signal->run_cleanup = FALSE;
+  if (when == NULL || strcmp (when, "LAST") == 0)
+    signal->run_last = TRUE;
+  else if (strcmp (when, "FIRST") == 0)
+    signal->run_first = TRUE;
+  else
+    signal->run_cleanup = TRUE;
 
-         iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
-         iface->members = g_list_append (iface->members, signal);
+  if (no_recurse && strcmp (no_recurse, "1") == 0)
+    signal->no_recurse = TRUE;
+  else
+    signal->no_recurse = FALSE;
+  if (detailed && strcmp (detailed, "1") == 0)
+    signal->detailed = TRUE;
+  else
+    signal->detailed = FALSE;
+  if (action && strcmp (action, "1") == 0)
+    signal->action = TRUE;
+  else
+    signal->action = FALSE;
+  if (no_hooks && strcmp (no_hooks, "1") == 0)
+    signal->no_hooks = TRUE;
+  else
+    signal->no_hooks = FALSE;
+  if (has_class_closure && strcmp (has_class_closure, "1") == 0)
+    signal->has_class_closure = TRUE;
+  else
+    signal->has_class_closure = FALSE;
 
-         push_node (ctx, (GIrNode *)signal);
-         state_switch (ctx, STATE_FUNCTION);
-       }
+  iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
+  iface->members = g_list_append (iface->members, signal);
 
-      return TRUE;
-    }
-  return FALSE;
+  push_node (ctx, (GIrNode *)signal);
+
+  return TRUE;
 }
 
 static gboolean
@@ -2174,80 +2192,80 @@ start_vfunc (GMarkupParseContext *context,
             ParseContext       *ctx,
             GError             **error)
 {
-  if (strcmp (element_name, "virtual-method") == 0 &&
-      (ctx->state == STATE_CLASS ||
-       ctx->state == STATE_INTERFACE))
-    {
-      const gchar *name;
-      const gchar *must_chain_up;
-      const gchar *override;
-      const gchar *is_class_closure;
-      const gchar *offset;
-      const gchar *invoker;
+  const gchar *name;
+  const gchar *must_chain_up;
+  const gchar *override;
+  const gchar *is_class_closure;
+  const gchar *offset;
+  const gchar *invoker;
+  GIrNodeInterface *iface;
+  GIrNodeVFunc *vfunc;
 
-      name = find_attribute ("name", attribute_names, attribute_values);
-      must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values);
-      override = find_attribute ("override", attribute_names, attribute_values);
-      is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values);
-      offset = find_attribute ("offset", attribute_names, attribute_values);
-      invoker = find_attribute ("invoker", attribute_names, attribute_values);
+  if (!(strcmp (element_name, "virtual-method") == 0 &&
+       (ctx->state == STATE_CLASS ||
+        ctx->state == STATE_INTERFACE)))
+    return FALSE;
 
-      if (name == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else
-       {
-         GIrNodeInterface *iface;
-         GIrNodeVFunc *vfunc;
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION))
+    return TRUE;
 
-         vfunc = (GIrNodeVFunc *)g_ir_node_new (G_IR_NODE_VFUNC);
+  name = find_attribute ("name", attribute_names, attribute_values);
+  must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values);
+  override = find_attribute ("override", attribute_names, attribute_values);
+  is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values);
+  offset = find_attribute ("offset", attribute_names, attribute_values);
+  invoker = find_attribute ("invoker", attribute_names, attribute_values);
 
-         ((GIrNode *)vfunc)->name = g_strdup (name);
+  if (name == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
+    }
 
-         if (must_chain_up && strcmp (must_chain_up, "1") == 0)
-           vfunc->must_chain_up = TRUE;
-         else
-           vfunc->must_chain_up = FALSE;
+  vfunc = (GIrNodeVFunc *)g_ir_node_new (G_IR_NODE_VFUNC);
 
-         if (override && strcmp (override, "always") == 0)
-           {
-             vfunc->must_be_implemented = TRUE;
-             vfunc->must_not_be_implemented = FALSE;
-           }
-         else if (override && strcmp (override, "never") == 0)
-           {
-             vfunc->must_be_implemented = FALSE;
-             vfunc->must_not_be_implemented = TRUE;
-           }
-         else
-           {
-             vfunc->must_be_implemented = FALSE;
-             vfunc->must_not_be_implemented = FALSE;
-           }
+  ((GIrNode *)vfunc)->name = g_strdup (name);
 
-         if (is_class_closure && strcmp (is_class_closure, "1") == 0)
-           vfunc->is_class_closure = TRUE;
-         else
-           vfunc->is_class_closure = FALSE;
+  if (must_chain_up && strcmp (must_chain_up, "1") == 0)
+    vfunc->must_chain_up = TRUE;
+  else
+    vfunc->must_chain_up = FALSE;
 
-         if (offset)
-           vfunc->offset = atoi (offset);
-         else
-           vfunc->offset = 0;
+  if (override && strcmp (override, "always") == 0)
+    {
+      vfunc->must_be_implemented = TRUE;
+      vfunc->must_not_be_implemented = FALSE;
+    }
+  else if (override && strcmp (override, "never") == 0)
+    {
+      vfunc->must_be_implemented = FALSE;
+      vfunc->must_not_be_implemented = TRUE;
+    }
+  else
+    {
+      vfunc->must_be_implemented = FALSE;
+      vfunc->must_not_be_implemented = FALSE;
+    }
 
-         vfunc->invoker = g_strdup (invoker);
+  if (is_class_closure && strcmp (is_class_closure, "1") == 0)
+    vfunc->is_class_closure = TRUE;
+  else
+    vfunc->is_class_closure = FALSE;
 
-         iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
-         iface->members = g_list_append (iface->members, vfunc);
+  if (offset)
+    vfunc->offset = atoi (offset);
+  else
+    vfunc->offset = 0;
 
-         push_node (ctx, (GIrNode *)vfunc);
-         state_switch (ctx, STATE_FUNCTION);
-       }
+  vfunc->invoker = g_strdup (invoker);
 
-      return TRUE;
-    }
-  return FALSE;
-}
+  iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
+  iface->members = g_list_append (iface->members, vfunc);
+
+  push_node (ctx, (GIrNode *)vfunc);
 
+  return TRUE;
+}
 
 static gboolean
 start_struct (GMarkupParseContext *context,
@@ -2257,75 +2275,74 @@ start_struct (GMarkupParseContext *context,
              ParseContext       *ctx,
              GError             **error)
 {
-  if (strcmp (element_name, "record") == 0 &&
-      (ctx->state == STATE_NAMESPACE ||
-       ctx->state == STATE_UNION ||
-       ctx->state == STATE_STRUCT ||
-       ctx->state == STATE_CLASS))
-    {
-      const gchar *name;
-      const gchar *deprecated;
-      const gchar *disguised;
-      const gchar *gtype_name;
-      const gchar *gtype_init;
-      const gchar *gtype_struct;
-      const gchar *foreign;
-      GIrNodeStruct *struct_;
+  const gchar *name;
+  const gchar *deprecated;
+  const gchar *disguised;
+  const gchar *gtype_name;
+  const gchar *gtype_init;
+  const gchar *gtype_struct;
+  const gchar *foreign;
+  GIrNodeStruct *struct_;
+
+  if (!(strcmp (element_name, "record") == 0 &&
+       (ctx->state == STATE_NAMESPACE ||
+        ctx->state == STATE_UNION ||
+        ctx->state == STATE_STRUCT ||
+        ctx->state == STATE_CLASS)))
+    return FALSE;
 
-      name = find_attribute ("name", attribute_names, attribute_values);
-      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
-      disguised = find_attribute ("disguised", attribute_names, attribute_values);
-      gtype_name = find_attribute ("glib:type-name", attribute_names, attribute_values);
-      gtype_init = find_attribute ("glib:get-type", attribute_names, attribute_values);
-      gtype_struct = find_attribute ("glib:is-gtype-struct-for", attribute_names, attribute_values);
-      foreign = find_attribute ("foreign", attribute_names, attribute_values);
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_STRUCT))
+    return TRUE;
 
-      if (name == NULL && ctx->node_stack == NULL)
-       {
-         MISSING_ATTRIBUTE (context, error, element_name, "name");
-         return FALSE;
-       }
-      if ((gtype_name == NULL && gtype_init != NULL))
-       {
-         MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
-         return FALSE;
-       }
-      if ((gtype_name != NULL && gtype_init == NULL))
-       {
-         MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
-         return FALSE;
-       }
+  name = find_attribute ("name", attribute_names, attribute_values);
+  deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+  disguised = find_attribute ("disguised", attribute_names, attribute_values);
+  gtype_name = find_attribute ("glib:type-name", attribute_names, attribute_values);
+  gtype_init = find_attribute ("glib:get-type", attribute_names, attribute_values);
+  gtype_struct = find_attribute ("glib:is-gtype-struct-for", attribute_names, attribute_values);
+  foreign = find_attribute ("foreign", attribute_names, attribute_values);
 
-      struct_ = (GIrNodeStruct *) g_ir_node_new (G_IR_NODE_STRUCT);
+  if (name == NULL && ctx->node_stack == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
+    }
+  if ((gtype_name == NULL && gtype_init != NULL))
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
+      return FALSE;
+    }
+  if ((gtype_name != NULL && gtype_init == NULL))
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
+      return FALSE;
+    }
 
-      ((GIrNode *)struct_)->name = g_strdup (name ? name : "");
-      if (deprecated)
-       struct_->deprecated = TRUE;
-      else
-       struct_->deprecated = FALSE;
+  struct_ = (GIrNodeStruct *) g_ir_node_new (G_IR_NODE_STRUCT);
 
-      if (disguised && strcmp (disguised, "1") == 0)
-       struct_->disguised = TRUE;
+  ((GIrNode *)struct_)->name = g_strdup (name ? name : "");
+  if (deprecated)
+    struct_->deprecated = TRUE;
+  else
+    struct_->deprecated = FALSE;
 
-      struct_->is_gtype_struct = gtype_struct != NULL;
+  if (disguised && strcmp (disguised, "1") == 0)
+    struct_->disguised = TRUE;
 
-      struct_->gtype_name = g_strdup (gtype_name);
-      struct_->gtype_init = g_strdup (gtype_init);
+  struct_->is_gtype_struct = gtype_struct != NULL;
 
-      struct_->foreign = (g_strcmp0 (foreign, "1") == 0);
+  struct_->gtype_name = g_strdup (gtype_name);
+  struct_->gtype_init = g_strdup (gtype_init);
 
-      if (ctx->node_stack == NULL)
-        ctx->current_module->entries =
-          g_list_append (ctx->current_module->entries, struct_);
-      push_node (ctx, (GIrNode *)struct_);
+  struct_->foreign = (g_strcmp0 (foreign, "1") == 0);
 
-      state_switch (ctx, STATE_STRUCT);
-      return TRUE;
-    }
-  return FALSE;
+  if (ctx->node_stack == NULL)
+    ctx->current_module->entries =
+      g_list_append (ctx->current_module->entries, struct_);
+  push_node (ctx, (GIrNode *)struct_);
+  return TRUE;
 }
 
-
 static gboolean
 start_union (GMarkupParseContext *context,
             const gchar         *element_name,
@@ -2334,48 +2351,48 @@ start_union (GMarkupParseContext *context,
             ParseContext       *ctx,
             GError             **error)
 {
-  if (strcmp (element_name, "union") == 0 &&
-      (ctx->state == STATE_NAMESPACE ||
-       ctx->state == STATE_UNION ||
-       ctx->state == STATE_STRUCT ||
-       ctx->state == STATE_CLASS))
-    {
-      const gchar *name;
-      const gchar *deprecated;
-      const gchar *typename;
-      const gchar *typeinit;
+  const gchar *name;
+  const gchar *deprecated;
+  const gchar *typename;
+  const gchar *typeinit;
+  GIrNodeUnion *union_;
 
-      name = find_attribute ("name", attribute_names, attribute_values);
-      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
-      typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
-      typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
+  if (!(strcmp (element_name, "union") == 0 &&
+       (ctx->state == STATE_NAMESPACE ||
+        ctx->state == STATE_UNION ||
+        ctx->state == STATE_STRUCT ||
+        ctx->state == STATE_CLASS)))
+    return FALSE;
+    
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_UNION))
+    return TRUE;
 
-      if (name == NULL && ctx->node_stack == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else
-       {
-         GIrNodeUnion *union_;
+  name = find_attribute ("name", attribute_names, attribute_values);
+  deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+  typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
+  typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
 
-         union_ = (GIrNodeUnion *) g_ir_node_new (G_IR_NODE_UNION);
+  if (name == NULL && ctx->node_stack == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
+    }
 
-         ((GIrNode *)union_)->name = g_strdup (name ? name : "");
-         union_->gtype_name = g_strdup (typename);
-         union_->gtype_init = g_strdup (typeinit);
-         if (deprecated)
-           union_->deprecated = TRUE;
-         else
-           union_->deprecated = FALSE;
+  union_ = (GIrNodeUnion *) g_ir_node_new (G_IR_NODE_UNION);
 
-          if (ctx->node_stack == NULL)
-            ctx->current_module->entries =
-              g_list_append (ctx->current_module->entries, union_);
-         push_node (ctx, (GIrNode *)union_);
+  ((GIrNode *)union_)->name = g_strdup (name ? name : "");
+  union_->gtype_name = g_strdup (typename);
+  union_->gtype_init = g_strdup (typeinit);
+  if (deprecated)
+    union_->deprecated = TRUE;
+  else
+    union_->deprecated = FALSE;
 
-         state_switch (ctx, STATE_UNION);
-       }
-      return TRUE;
-    }
-  return FALSE;
+  if (ctx->node_stack == NULL)
+    ctx->current_module->entries =
+      g_list_append (ctx->current_module->entries, union_);
+  push_node (ctx, (GIrNode *)union_);
+  return TRUE;
 }
 
 static gboolean
@@ -2386,42 +2403,43 @@ start_discriminator (GMarkupParseContext *context,
                     ParseContext       *ctx,
                     GError             **error)
 {
-  if (strcmp (element_name, "discriminator") == 0 &&
-      ctx->state == STATE_UNION)
-    {
-      const gchar *type;
-      const gchar *offset;
-
-      type = find_attribute ("type", attribute_names, attribute_values);
-      offset = find_attribute ("offset", attribute_names, attribute_values);
-      if (type == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "type");
-      else if (offset == NULL)
-       MISSING_ATTRIBUTE (context, error, element_name, "offset");
-       {
-         ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_type
-           = parse_type (ctx, type);
-         ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_offset
-           = atoi (offset);
-       }
+  const gchar *type;
+  const gchar *offset;
+  if (!(strcmp (element_name, "discriminator") == 0 &&
+       ctx->state == STATE_UNION))
+    return FALSE;
 
-      return TRUE;
+  type = find_attribute ("type", attribute_names, attribute_values);
+  offset = find_attribute ("offset", attribute_names, attribute_values);
+  if (type == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "type");
+      return FALSE;
+    }
+  else if (offset == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "offset");
+      return FALSE;
     }
 
-  return FALSE;
+  ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_type
+    = parse_type (ctx, type);
+  ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_offset
+    = atoi (offset);
+
+  return TRUE;
 }
 
 static gboolean
 parse_include (GMarkupParseContext *context,
               ParseContext        *ctx,
               const char          *name,
-              const char          *version,
-              GError             **error)
+              const char          *version)
 {
+  GError *error = NULL;
   gchar *buffer;
   gsize length;
   gchar *girpath, *girname;
-  gboolean success = FALSE;
   GList *modules;
   GList *l;
 
@@ -2439,11 +2457,8 @@ parse_include (GMarkupParseContext *context,
            }
          else
            {
-             g_set_error (error,
-                          G_MARKUP_ERROR,
-                          G_MARKUP_ERROR_INVALID_CONTENT,
-                          "Module '%s' imported with conflicting versions '%s' and '%s'",
-                          name, m->version, version);
+             g_printerr ("Module '%s' imported with conflicting versions '%s' and '%s'\n",
+                         name, m->version, version);
              return FALSE;
            }
        }
@@ -2454,10 +2469,7 @@ parse_include (GMarkupParseContext *context,
 
   if (girpath == NULL)
     {
-      g_set_error (error,
-                  G_MARKUP_ERROR,
-                  G_MARKUP_ERROR_INVALID_CONTENT,
-                  "Could not find GIR file '%s'; check XDG_DATA_DIRS or use --includedir",
+      g_printerr ("Could not find GIR file '%s'; check XDG_DATA_DIRS or use --includedir\n",
                   girname);
       g_free (girname);
       return FALSE;
@@ -2466,22 +2478,31 @@ parse_include (GMarkupParseContext *context,
 
   g_debug ("Parsing include %s", girpath);
 
-  if (!g_file_get_contents (girpath, &buffer, &length, error))
+  if (!g_file_get_contents (girpath, &buffer, &length, &error))
     {
+      g_printerr ("%s: %s\n", girpath, error->message);
+      g_clear_error (&error);
       g_free (girpath);
       return FALSE;
     }
-  g_free (girpath);
 
-  modules = g_ir_parser_parse_string (ctx->parser, name, buffer, length, error);
-  success = error != NULL;
+  modules = g_ir_parser_parse_string (ctx->parser, name, girpath, buffer, length, &error);
+  g_free (buffer);
+  if (error != NULL)
+    {
+      int line_number, char_number;
+      g_markup_parse_context_get_position (context, &line_number, &char_number);
+      g_printerr ("%s:%d:%d: error: %s\n", girpath, line_number, char_number, error->message);
+      g_clear_error (&error);
+      g_free (girpath);
+      return FALSE;
+    }
+  g_free (girpath);
 
   ctx->include_modules = g_list_concat (ctx->include_modules,
                                        modules);
 
-  g_free (buffer);
-
-  return success;
+  return TRUE;
 }
 
 extern GLogLevelFlags logged_levels;
@@ -2515,6 +2536,12 @@ start_element_handler (GMarkupParseContext *context,
       g_string_free (tags, TRUE);
     }
 
+  if (ctx->state == STATE_PASSTHROUGH)
+    {
+      ctx->unknown_depth += 1;
+      return;
+    }
+
   switch (element_name[0])
     {
     case 'a':
@@ -2614,8 +2641,16 @@ start_element_handler (GMarkupParseContext *context,
              break;
            }
 
-         if (!parse_include (context, ctx, name, version, error))
-           break;
+         if (!parse_include (context, ctx, name, version))
+           {
+             g_set_error (error,
+                          G_MARKUP_ERROR,
+                          G_MARKUP_ERROR_INVALID_CONTENT,
+                          "Failed to parse included gir %s-%s",
+                          name,
+                          version);
+             return;
+           }
 
          ctx->dependencies = g_list_prepend (ctx->dependencies,
                                              g_strdup_printf ("%s-%s", name, version));
@@ -2801,22 +2836,22 @@ start_element_handler (GMarkupParseContext *context,
       break;
     }
 
-  if (ctx->state != STATE_UNKNOWN)
+  if (ctx->state != STATE_PASSTHROUGH)
     {
-      state_switch (ctx, STATE_UNKNOWN);
+      g_markup_parse_context_get_position (context, &line_number, &char_number);
+      if (!g_str_has_prefix (element_name, "c:"))
+       g_printerr ("%s:%d:%d: warning: dropping to PASSTHROUGH\n",
+                   ctx->file_path, line_number, char_number);
+      state_switch (ctx, STATE_PASSTHROUGH);
       ctx->unknown_depth = 1;
     }
-  else
-    {
-      ctx->unknown_depth += 1;
-    }
 
  out:
   if (*error)
     {
       g_markup_parse_context_get_position (context, &line_number, &char_number);
 
-      fprintf (stderr, "Error at line %d, character %d: %s\n", line_number, char_number, (*error)->message);
+      g_printerr ("%s:%d:%d: error: %s\n", ctx->file_path, line_number, char_number, (*error)->message);
       backtrace_stderr ();
     }
 }
@@ -3189,7 +3224,7 @@ end_element_handler (GMarkupParseContext *context,
         }
       break;
 
-    case STATE_UNKNOWN:
+    case STATE_PASSTHROUGH:
       ctx->unknown_depth -= 1;
       if (ctx->unknown_depth == 0)
         state_switch (ctx, ctx->prev_state);
@@ -3225,149 +3260,11 @@ cleanup (GMarkupParseContext *context,
   ctx->current_module = NULL;
 }
 
-static GList *
-post_filter_toplevel_varargs_functions (GList *list,
-                                       GList **varargs_callbacks_out)
-{
-  GList *iter;
-  GList *varargs_callbacks = *varargs_callbacks_out;
-
-  iter = list;
-  while (iter)
-    {
-      GList *link = iter;
-      GIrNode *node = iter->data;
-
-      iter = iter->next;
-
-      if (node->type == G_IR_NODE_FUNCTION)
-       {
-         if (((GIrNodeFunction*)node)->is_varargs)
-           {
-             list = g_list_delete_link (list, link);
-           }
-       }
-      if (node->type == G_IR_NODE_CALLBACK)
-       {
-         if (((GIrNodeFunction*)node)->is_varargs)
-           {
-             varargs_callbacks = g_list_append (varargs_callbacks,
-                                                node);
-             list = g_list_delete_link (list, link);
-           }
-       }
-    }
-
-  *varargs_callbacks_out = varargs_callbacks;
-
-  return list;
-}
-
-static GList *
-post_filter_varargs_functions (GList *list, GList ** varargs_callbacks_out)
-{
-  GList *iter;
-  GList *varargs_callbacks;
-
-  list = post_filter_toplevel_varargs_functions (list, varargs_callbacks_out);
-
-  varargs_callbacks = *varargs_callbacks_out;
-
-  iter = list;
-  while (iter)
-    {
-      GList *link = iter;
-      GIrNode *node = iter->data;
-
-      iter = iter->next;
-
-      if (node->type == G_IR_NODE_FUNCTION)
-       {
-         GList *param;
-         gboolean function_done = FALSE;
-
-         for (param = ((GIrNodeFunction *)node)->parameters;
-              param;
-              param = param->next)
-           {
-             GIrNodeParam *node = (GIrNodeParam *)param->data;
-
-             if (function_done)
-               break;
-
-             if (node->type->is_interface)
-               {
-                 GList *callback;
-                 for (callback = varargs_callbacks;
-                      callback;
-                      callback = callback->next)
-                   {
-                     if (!strcmp (node->type->interface,
-                                  ((GIrNode *)varargs_callbacks->data)->name))
-                       {
-                         list = g_list_delete_link (list, link);
-                         function_done = TRUE;
-                         break;
-                       }
-                   }
-               }
-           }
-       }
-    }
-
-  *varargs_callbacks_out = varargs_callbacks;
-
-  return list;
-}
-
-static void
-post_filter (GIrModule *module)
-{
-  GList *iter;
-  GList *varargs_callbacks = NULL;
-
-  module->entries = post_filter_varargs_functions (module->entries,
-                                                  &varargs_callbacks);
-  iter = module->entries;
-  while (iter)
-    {
-      GIrNode *node = iter->data;
-
-      iter = iter->next;
-
-      if (node->type == G_IR_NODE_OBJECT ||
-         node->type == G_IR_NODE_INTERFACE)
-       {
-         GIrNodeInterface *iface = (GIrNodeInterface*)node;
-         iface->members = post_filter_varargs_functions (iface->members,
-                                                         &varargs_callbacks);
-       }
-      else if (node->type == G_IR_NODE_BOXED)
-       {
-         GIrNodeBoxed *boxed = (GIrNodeBoxed*)node;
-         boxed->members = post_filter_varargs_functions (boxed->members,
-                                                         &varargs_callbacks);
-       }
-      else if (node->type == G_IR_NODE_STRUCT)
-       {
-         GIrNodeStruct *iface = (GIrNodeStruct*)node;
-         iface->members = post_filter_varargs_functions (iface->members,
-                                                         &varargs_callbacks);
-       }
-      else if (node->type == G_IR_NODE_UNION)
-       {
-         GIrNodeUnion *iface = (GIrNodeUnion*)node;
-         iface->members = post_filter_varargs_functions (iface->members,
-                                                         &varargs_callbacks);
-       }
-    }
-  g_list_free (varargs_callbacks);
-}
-
 /**
  * g_ir_parser_parse_string:
  * @parser: a #GIrParser
  * @namespace: the namespace of the string
+ * @filename: (allow-none): Path to parsed file, or %NULL
  * @buffer: the data containing the XML
  * @length: length of the data
  * @error: return location for a #GError, or %NULL
@@ -3381,6 +3278,7 @@ post_filter (GIrModule *module)
 GList *
 g_ir_parser_parse_string (GIrParser           *parser,
                          const gchar         *namespace,
+                         const gchar         *filename,
                          const gchar         *buffer,
                          gssize               length,
                          GError             **error)
@@ -3390,6 +3288,7 @@ g_ir_parser_parse_string (GIrParser           *parser,
 
   ctx.parser = parser;
   ctx.state = STATE_START;
+  ctx.file_path = filename;
   ctx.namespace = namespace;
   ctx.include_modules = NULL;
   ctx.aliases = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
@@ -3457,7 +3356,6 @@ g_ir_parser_parse_file (GIrParser   *parser,
   gchar *buffer;
   gsize length;
   GList *modules;
-  GList *iter;
   const char *slash;
   char *dash;
   char *namespace;
@@ -3488,12 +3386,7 @@ g_ir_parser_parse_file (GIrParser   *parser,
   if (!g_file_get_contents (filename, &buffer, &length, error))
     return NULL;
 
-  modules = g_ir_parser_parse_string (parser, namespace, buffer, length, error);
-
-  for (iter = modules; iter; iter = iter->next)
-    {
-      post_filter ((GIrModule*)iter->data);
-    }
+  modules = g_ir_parser_parse_string (parser, namespace, filename, buffer, length, error);
 
   g_free (namespace);
 
index ac0d216b2ac33d1e55b20b28bba4a89ac9ff6d1e..6fca1b3dac88cf28c5f5674d9d77265609cb0038 100644 (file)
@@ -34,6 +34,7 @@ void       g_ir_parser_set_includes (GIrParser          *parser,
 
 GList *g_ir_parser_parse_string (GIrParser    *parser,
                                 const gchar  *namespace,
+                                const gchar  *filename,
                                 const gchar  *buffer,
                                 gssize        length,
                                 GError      **error);
index 0e9f112d1b8812f65b5a16fd0bd5b4053d99ceb9..a70f2d8baa4eecae17a62133fb8f7134079115f7 100644 (file)
@@ -173,12 +173,14 @@ class Node(object):
 
     def __init__(self, name=None):
         self.name = name
-        self.attributes = [] # (key, value)*
         self.skip = False
+        self.introspectable = True
+        self.attributes = [] # (key, value)*
         self.deprecated = None
         self.deprecated_version = None
         self.version = None
         self.foreign = False
+        self.file_positions = set()
 
     def __cmp__(self, other):
         return cmp(self.name, other.name)
@@ -189,6 +191,16 @@ class Node(object):
     def remove_matching_children(self, pred):
         pass
 
+    def inherit_file_positions(self, node):
+        self.file_positions.update(node.file_positions)
+
+    def add_file_position(self, filename, line, column):
+        self.file_positions.add((filename, line, column))
+
+    def add_symbol_reference(self, symbol):
+        if symbol.source_filename:
+            self.add_file_position(symbol.source_filename, symbol.line, -1)
+
 class Namespace(Node):
 
     def __init__(self, name, version):
index 2dff4fe2a6fd9732b9e9b07d83e25217f253476a..c8a81e892d873d73725cf01637bcadd305daeb5b 100644 (file)
@@ -96,8 +96,7 @@ and/or use gtk-doc annotations. ''')
                 else:
                     return cmp(a, b)
             for node in sorted(namespace.nodes, cmp=nscmp):
-                if not node.skip:
-                    self._write_node(node)
+                self._write_node(node)
 
     def _write_node(self, node):
         if isinstance(node, Function):
@@ -134,7 +133,9 @@ and/or use gtk-doc annotations. ''')
         for key, value in node.attributes:
             self.write_tag('attribute', [('name', key), ('value', value)])
 
-    def _append_deprecated(self, node, attrs):
+    def _append_node_generic(self, node, attrs):
+        if node.skip or not node.introspectable:
+            attrs.append(('introspectable', '0'))
         if node.deprecated:
             attrs.append(('deprecated', node.deprecated))
             if node.deprecated_version:
@@ -152,14 +153,12 @@ and/or use gtk-doc annotations. ''')
         self.write_tag('alias', attrs)
 
     def _write_callable(self, callable, tag_name, extra_attrs):
-        if callable.skip:
-            return
         attrs = [('name', callable.name)]
         attrs.extend(extra_attrs)
         if callable.doc:
             attrs.append(('doc', callable.doc))
         self._append_version(callable, attrs)
-        self._append_deprecated(callable, attrs)
+        self._append_node_generic(callable, attrs)
         self._append_throws(callable, attrs)
         with self.tagcontext(tag_name, attrs):
             self._write_attributes(callable)
@@ -279,7 +278,7 @@ and/or use gtk-doc annotations. ''')
         if enum.doc:
             attrs.append(('doc', enum.doc))
         self._append_version(enum, attrs)
-        self._append_deprecated(enum, attrs)
+        self._append_node_generic(enum, attrs)
         if isinstance(enum, GLibEnum):
             attrs.extend([('glib:type-name', enum.type_name),
                           ('glib:get-type', enum.get_type),
@@ -299,7 +298,7 @@ and/or use gtk-doc annotations. ''')
         if bitfield.doc:
             attrs.append(('doc', bitfield.doc))
         self._append_version(bitfield, attrs)
-        self._append_deprecated(bitfield, attrs)
+        self._append_node_generic(bitfield, attrs)
         if isinstance(bitfield, GLibFlags):
             attrs.extend([('glib:type-name', bitfield.type_name),
                           ('glib:get-type', bitfield.get_type),
@@ -312,8 +311,6 @@ and/or use gtk-doc annotations. ''')
                 self._write_member(member)
 
     def _write_member(self, member):
-        if member.skip:
-            return
         attrs = [('name', member.name),
                  ('value', str(member.value)),
                  ('c:identifier', member.symbol)]
@@ -333,7 +330,7 @@ and/or use gtk-doc annotations. ''')
         if node.doc:
             attrs.append(('doc', node.doc))
         self._append_version(node, attrs)
-        self._append_deprecated(node, attrs)
+        self._append_node_generic(node, attrs)
         if isinstance(node, Class):
             tag_name = 'class'
             if node.parent is not None:
@@ -386,11 +383,9 @@ and/or use gtk-doc annotations. ''')
                 self._write_method(method)
 
     def _write_property(self, prop):
-        if prop.skip:
-            return
         attrs = [('name', prop.name)]
         self._append_version(prop, attrs)
-        self._append_deprecated(prop, attrs)
+        self._append_node_generic(prop, attrs)
         # Properties are assumed to be readable (see also generate.c)
         if not prop.readable:
             attrs.append(('readable', '0'))
@@ -440,7 +435,7 @@ and/or use gtk-doc annotations. ''')
         if record.doc:
             attrs.append(('doc', record.doc))
         self._append_version(record, attrs)
-        self._append_deprecated(record, attrs)
+        self._append_node_generic(record, attrs)
         if isinstance(record, GLibBoxed):
             attrs.extend(self._boxed_attrs(record))
         with self.tagcontext('record', attrs):
@@ -462,7 +457,7 @@ and/or use gtk-doc annotations. ''')
         if union.doc:
             attrs.append(('doc', union.doc))
         self._append_version(union, attrs)
-        self._append_deprecated(union, attrs)
+        self._append_node_generic(union, attrs)
         if isinstance(union, GLibBoxed):
             attrs.extend(self._boxed_attrs(union))
         with self.tagcontext('union', attrs):
@@ -508,13 +503,11 @@ and/or use gtk-doc annotations. ''')
                 self._write_type(field.type)
 
     def _write_signal(self, signal):
-        if signal.skip:
-            return
         attrs = [('name', signal.name)]
         if signal.doc:
             attrs.append(('doc', signal.doc))
         self._append_version(signal, attrs)
-        self._append_deprecated(signal, attrs)
+        self._append_node_generic(signal, attrs)
         with self.tagcontext('glib:signal', attrs):
             self._write_attributes(signal)
             self._write_return_type(signal.retval)
index 42488251f37ed7a38d66eba6593c0a781e8fed4c..192690ceeb164dd2cbdf85f157c309d2dc0128b7 100644 (file)
@@ -25,10 +25,12 @@ import tempfile
 import shutil
 import subprocess
 
-from .ast import (Alias, Bitfield, Callback, Constant, Enum, Function, Member,
-                  Namespace, Parameter, Property, Record, Return, Type, Union,
-                  Field, VFunction, type_name_from_ctype,
-                  default_array_types, TYPE_UINT8, PARAM_TRANSFER_FULL, Array)
+from .ast import (Alias, Bitfield, Callable, Callback, Class, Constant, Enum,
+                  Function, Interface, Member, Namespace, Node, Parameter,
+                  Property, Record, Return, Type, TypeContainer, Union,
+                  Field, VFunction, type_name_from_ctype, default_array_types,
+                  TYPE_UINT8, PARAM_TRANSFER_FULL, Array, List,
+                  Map, Varargs)
 from .transformer import Names
 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
                       GLibInterface, GLibObject, GLibSignal, GLibBoxedStruct,
@@ -112,18 +114,6 @@ class GLibTransformer(object):
 
     # Public API
 
-    def _print_statistics(self):
-        nodes = list(self._names.names.itervalues())
-
-        def count_type(otype):
-            return len([x for x in nodes
-                        if isinstance(x[1], otype)])
-        objectcount = count_type(GLibObject)
-        ifacecount = count_type(GLibInterface)
-        enumcount = count_type(GLibEnum)
-        print " %d nodes; %d objects, %d interfaces, %d enums" \
-            % (len(nodes), objectcount, ifacecount, enumcount)
-
     def init_parse(self):
         """Do parsing steps that don't involve the introspection binary
 
@@ -170,7 +160,8 @@ class GLibTransformer(object):
             try:
                 self._resolve_node(node)
             except KeyError, e:
-                #print "WARNING: DELETING node %s: %s" % (node.name, e)
+                self._transformer._log_node_warning(node,
+"""Unresolvable entry %r""" % (e, ))
                 self._remove_attribute(node.name)
         # Another pass, since we need to have the methods parsed
         # in order to correctly modify them after class/record
@@ -181,12 +172,11 @@ class GLibTransformer(object):
                 self._pair_class_record(node)
         for (ns, alias) in self._names.aliases.itervalues():
             self._resolve_alias(alias)
+
         self._resolve_quarks()
-        # Fourth pass: ensure all types are known
-        if not self._noclosure:
-            self._resolve_types(nodes)
 
-        #self._validate(nodes)
+        # Our final pass replacing types
+        self._resolve_types(nodes)
 
         # Create a new namespace with what we found
         namespace = Namespace(self._namespace_name, self._namespace_version)
@@ -272,9 +262,8 @@ class GLibTransformer(object):
             if enum is not None:
                 enum.error_quark = node.symbol
             else:
-                print "WARNING: " + \
-                      "Couldn't find corresponding enumeration for %s" % \
-                          (node.symbol, )
+                self._transformer._log_node_warning(node,
+"""Couldn't find corresponding enumeration""")
 
     # Helper functions
 
@@ -425,7 +414,7 @@ class GLibTransformer(object):
                                          'GType',
                                          'GObject.Type',
                                          'Gtk.Type']:
-            print ("Warning: *_get_type function returns '%r'"
+            self._transformer.log_("Warning: *_get_type function returns '%r'"
                    ", not GObject.Type") % (func.retval.type.name, )
             return False
 
@@ -668,6 +657,7 @@ class GLibTransformer(object):
             if matched_signal:
                 continue
             vfunc = VFunction.from_callback(field)
+            vfunc.inherit_file_positions(field)
             pair_class.virtual_methods.append(vfunc)
 
         # Take the set of virtual methods we found, and try
@@ -685,6 +675,7 @@ class GLibTransformer(object):
         self._remove_attribute(class_struct.name)
         self._add_attribute(gclass_struct, True)
         pair_class.glib_type_struct = gclass_struct
+        pair_class.inherit_file_positions(class_struct)
         gclass_struct.is_gtype_struct_for = name
 
     # Introspection
@@ -829,6 +820,90 @@ class GLibTransformer(object):
                 # (see also _pair_class_record and transformer.py)
                 field.writable = False
 
+    def _pair_boxed_type(self, boxed):
+        name = self._transformer.remove_prefix(boxed.type_name)
+        pair_node = self._get_attribute(name)
+        if not pair_node:
+            boxed_item = GLibBoxedOther(name, boxed.type_name,
+                                        boxed.get_type)
+        elif isinstance(pair_node, Record):
+            boxed_item = GLibBoxedStruct(pair_node.name, boxed.type_name,
+                                         boxed.get_type)
+            boxed_item.inherit_file_positions(pair_node)
+            boxed_item.fields = pair_node.fields
+        elif isinstance(pair_node, Union):
+            boxed_item = GLibBoxedUnion(pair_node.name, boxed.type_name,
+                                         boxed.get_type)
+            boxed_item.inherit_file_positions(pair_node)
+            boxed_item.fields = pair_node.fields
+        else:
+            return False
+        self._add_attribute(boxed_item, replace=True)
+
+    # Node walking
+
+    def _walk(self, node, callback, chain):
+        if not isinstance(node, Node):
+            return
+        if not callback(node, chain):
+            return
+        chain.append(node)
+        def _subwalk(subnode):
+            self._walk(subnode, callback, chain)
+        if isinstance(node, (Callback, Callable)):
+            _subwalk(node.retval)
+            for parameter in node.parameters:
+                _subwalk(parameter)
+        elif isinstance(node, (Array, List)):
+            _subwalk(node.element_type)
+        elif isinstance(node, Map):
+            _subwalk(node.key_type)
+            _subwalk(node.value_type)
+        elif isinstance(node, Bitfield):
+            pass
+        elif isinstance(node, Record):
+            for ctor in node.constructors:
+                _subwalk(ctor)
+            for func in node.methods:
+                _subwalk(func)
+        elif isinstance(node, Field):
+            _subwalk(node.type)
+        elif isinstance(node, Class):
+            for meth in node.methods:
+                _subwalk(meth)
+            for meth in node.virtual_methods:
+                _subwalk(meth)
+            for meth in node.static_methods:
+                _subwalk(meth)
+            for ctor in node.constructors:
+                _subwalk(ctor)
+            for prop in node.properties:
+                _subwalk(prop)
+            for field in node.fields:
+                _subwalk(field)
+        elif isinstance(node, Interface):
+            for meth in node.methods:
+                _subwalk(meth)
+            for meth in node.virtual_methods:
+                _subwalk(meth)
+            for prop in node.properties:
+                _subwalk(prop)
+            for field in node.fields:
+                _subwalk(field)
+        elif isinstance(node, Constant):
+            _subwalk(node.type)
+        elif isinstance(node, Union):
+            for ctor in node.constructors:
+                _subwalk(ctor)
+            for meth in node.methods:
+                _subwalk(meth)
+
+        if isinstance(node, (GLibObject, GLibInterface)):
+            for sig in node.signals:
+                _subwalk(sig)
+
+        chain.pop()
+
     # Resolver
 
     def _resolve_type_name(self, type_name, ctype=None):
@@ -879,24 +954,6 @@ class GLibTransformer(object):
                 return
         self._resolve_function(func)
 
-    def _pair_boxed_type(self, boxed):
-        name = self._transformer.remove_prefix(boxed.type_name)
-        pair_node = self._get_attribute(name)
-        if not pair_node:
-            boxed_item = GLibBoxedOther(name, boxed.type_name,
-                                        boxed.get_type)
-        elif isinstance(pair_node, Record):
-            boxed_item = GLibBoxedStruct(pair_node.name, boxed.type_name,
-                                         boxed.get_type)
-            boxed_item.fields = pair_node.fields
-        elif isinstance(pair_node, Union):
-            boxed_item = GLibBoxedUnion(pair_node.name, boxed.type_name,
-                                         boxed.get_type)
-            boxed_item.fields = pair_node.fields
-        else:
-            return False
-        self._add_attribute(boxed_item, replace=True)
-
     def _resolve_record(self, node):
         for field in node.fields:
             self._resolve_field(field)
@@ -914,8 +971,8 @@ class GLibTransformer(object):
                                                              self._names)
             except KeyError, e:
                 if allow_unknown:
-                    print "WARNING: Skipping unknown interface %s" % \
-                        (item.target, )
+                    self._transformer._log_warning(
+"""Skipping unknown interface %s""" % (item.target, ))
                     return None
                 else:
                     raise
@@ -1028,7 +1085,6 @@ class GLibTransformer(object):
         while True:
             initlen = len(nodes)
 
-            #print "Type resolution; pass=%d" % (i, )
             nodes = list(self._names.names.itervalues())
             for node in nodes:
                 try:
@@ -1039,20 +1095,62 @@ class GLibTransformer(object):
             if len(nodes) == initlen:
                 break
             i += 1
-            self._print_statistics()
         self._validating = False
 
     # Validation
 
-    def _validate_interface(self, iface):
-        for vfunc in iface.virtual_methods:
-            if not vfunc.invoker:
-                print ("warning: Interface %r virtual function %r " + \
-                       "has no known invoker") % (iface.name, vfunc.name)
+    def _interface_vfunc_check(self, node, stack):
+        if isinstance(node, GLibInterface):
+            for vfunc in node.virtual_methods:
+                if not vfunc.invoker:
+                    self._transformer._log_node_warning(vfunc,
+"""Virtual function %r has no known invoker""" % (vfunc.name, ),
+                    context=node)
+
+    def _introspectable_analysis(self, node, stack):
+        if isinstance(node, TypeContainer):
+            parent = stack[-1]
+            if isinstance(node.type, Varargs):
+                parent.introspectable = False
+            elif not isinstance(node.type, List) and \
+                 (node.type.name == 'GLib.List' or
+                  (self._transformer._namespace.name == 'GLib'
+                   and node.type.name == 'List')):
+                if isinstance(node, Parameter):
+                    self._transformer._log_node_warning(parent,
+"""Missing (element-type) annotation on argument %r""" % (node.name, ),
+                                                    context=parent)
+                else:
+                    self._transformer._log_node_warning(parent,
+"""Missing (element-type) annotation on return value""", context=parent)
+                parent.introspectable = False
+
+    def _analyze_node(self, node, stack):
+        if node.skip:
+            return False
+        # Combine one-pass checks here
+        self._interface_vfunc_check(node, stack)
+        # Our first pass for scriptability
+        self._introspectable_analysis(node, stack)
+        return True
+
+    def _introspectable_pass2(self, node, stack):
+        if node.skip:
+            return False
+        # In the second introspectable pass, we propagate introspectablity;
+        # for example, a varargs callback as an argument to a function
+        # makes the whole function unintrospectable
+        if isinstance(node, TypeContainer):
+            parent = stack[-1]
+            target = self._lookup_node(node.type.name)
+            if target and not target.introspectable:
+                parent.introspectable = False
+        return True
 
     # This function is called at the very end, before we hand back the
     # completed namespace to the writer.  Add static analysis checks here.
-    def _validate(self, nodes):
-        for (name, node) in nodes:
-            if isinstance(node, GLibInterface):
-                self._validate_interface(node)
+    def final_analyze(self):
+        for (ns, node) in self._names.names.itervalues():
+            self._walk(node, self._analyze_node, [])
+        for (ns, node) in self._names.names.itervalues():
+            self._walk(node, self._introspectable_pass2, [])
index 44c0287db7aab31d84b1c96e48a1e181a05bd8f0..fef4d474eb715792770bd97225d06a306ef7ed7b 100644 (file)
@@ -87,6 +87,12 @@ def _get_option_parser():
     parser.add_option("", "--pkg-export",
                       action="append", dest="packages_export", default=[],
                       help="Associated pkg-config packages for this library")
+    parser.add_option('', "--Wall",
+                      action="store_true", dest="warn_all", default=False,
+                      help="If true, enable all warnings for introspection")
+    parser.add_option('', "--Werror",
+                      action="store_true", dest="warn_fatal",
+                      help="Turn warnings into fatal errors")
     parser.add_option("-v", "--verbose",
                       action="store_true", dest="verbose",
                       help="be verbose")
@@ -271,6 +277,8 @@ def scanner_main(args):
         transformer.set_strip_prefix(options.strip_prefix)
     else:
         transformer.set_strip_prefix(options.namespace_name)
+    if options.warn_all:
+        transformer.enable_warnings(True)
     transformer.set_include_paths(options.include_paths)
     shown_include_warning = False
     for include in options.includes:
@@ -328,6 +336,11 @@ def scanner_main(args):
     except InvalidAnnotationError, e:
         raise SystemExit("ERROR in annotation: %s" % (str(e), ))
 
+    glibtransformer.final_analyze()
+
+    if options.warn_fatal and transformer.did_warn():
+        return 1
+
     # Write out AST
     if options.packages_export:
         exported_packages = options.packages_export
index 7b06478da80225b722e554ea6da61338613b9a60..acfc048558c1f5f5c64edd3232ddde2cb9b0c801 100644 (file)
@@ -188,6 +188,10 @@ class SourceSymbol(object):
     def source_filename(self):
         return self._symbol.source_filename
 
+    @property
+    def line(self):
+        return self._symbol.line
+
 
 class SourceScanner(object):
 
index fbc38d5b936379e5340ec9cee36646d86d5905e1..01dfdeb693acfe3b416990c51727c2263545c0d9 100644 (file)
@@ -65,6 +65,7 @@ class Names(object):
 class Transformer(object):
 
     def __init__(self, cachestore, namespace_name, namespace_version):
+        self.__cwd = os.getcwd() + os.sep
         self._cachestore = cachestore
         self.generator = None
         self._namespace = Namespace(namespace_name, namespace_version)
@@ -72,6 +73,8 @@ class Transformer(object):
         self._pkg_config_packages = set()
         self._typedefs_ns = {}
         self._strip_prefix = ''
+        self._enable_warnings = False
+        self._warned = False
         self._includes = set()
         self._includepaths = []
 
@@ -87,6 +90,12 @@ class Transformer(object):
     def get_strip_prefix(self):
         return self._strip_prefix
 
+    def enable_warnings(self, enable):
+        self._enable_warnings = enable
+
+    def did_warn(self):
+        return self._warned
+
     def get_pkgconfig_packages(self):
         return self._pkg_config_packages
 
@@ -115,6 +124,58 @@ class Transformer(object):
 
     # Private
 
+    def _log_warning(self, string, file_positions=[], prefix=None):
+        """Log a warning, using optional file positioning information.
+If the warning is related to a Node type, see _log_node_warning()."""
+        if not self._enable_warnings:
+            return
+
+        if len(file_positions) == 0:
+            target_file_positions = [('<unknown>', -1, -1)]
+        else:
+            target_file_positions = file_positions
+
+        for (filename, line, column) in target_file_positions:
+            if filename.startswith(self.__cwd):
+                filename = filename[len(self.__cwd):]
+            if column != -1:
+                position = '%s:%d:%d' % (filename, line, column)
+            elif line != -1:
+                position = '%s:%d' % (filename, line, )
+            else:
+                position = '%s:' % (filename, )
+
+        if prefix:
+            print >>sys.stderr, \
+'''%s: warning: ns=%r %s: %s''' % (position, self._namespace.name,
+                                   prefix, string)
+        else:
+            print >>sys.stderr, \
+'''%s: warning: ns=%r: %s''' % (position, self._namespace.name, string)
+
+    def _log_symbol_warning(self, symbol, string):
+        """Log a warning in the context of the given symbol."""
+        file_positions = [(symbol.source_filename, symbol.line, -1)]
+        prefix = "symbol=%r" % (symbol.ident, )
+        self._log_warning(string, file_positions, prefix=prefix)
+
+    def _log_node_warning(self, node, string, context=None):
+        """Log a warning, using information about file positions from
+the given node.  The optional context argument, if given, should be
+another Node type which will also be displayed.  If no file position
+information is available from the node, the position data from the
+context will be used."""
+        if len(node.file_positions) == 0 and \
+                (context is not None) and len(context.file_positions) > 0:
+            file_positions = context.file_positions
+        else:
+            file_positions = node.file_positions
+
+        if context:
+            string = "context=%r %s" % (context.name, string)
+
+        self._log_warning(string, file_positions)
+
     def _find_include(self, include):
         searchdirs = self._includepaths[:]
         for path in _xdg_data_dirs:
@@ -261,12 +322,15 @@ class Transformer(object):
         else:
             klass = Enum
         node = klass(enum_name, symbol.ident, members)
+        node.add_symbol_reference(symbol)
         self._names.type_names[symbol.ident] = (None, node)
         return node
 
     def _create_object(self, symbol):
-        return Member(symbol.ident, symbol.base_type.name,
+        node = Member(symbol.ident, symbol.base_type.name,
                       symbol.ident)
+        node.add_symbol_reference(symbol)
+        return node
 
     def _type_is_callback(self, type):
         if isinstance(type, Callback):
@@ -327,6 +391,7 @@ class Transformer(object):
         self._augment_callback_params(parameters)
         name = self._strip_namespace_func(symbol.ident)
         func = Function(name, return_, parameters, symbol.ident)
+        func.add_symbol_reference(symbol)
         return func
 
     def _create_source_type(self, source_type):
@@ -386,6 +451,7 @@ class Transformer(object):
             # (except for Objects, see also glibtransformer.py)
             node = Field(symbol.ident, ftype, ftype.name,
                          readable=True, writable=True, bits=symbol.const_int)
+            node.add_symbol_reference(symbol)
         return node
 
     def _create_typedef(self, symbol):
@@ -523,11 +589,13 @@ class Transformer(object):
             raise AssertionError()
 
         const = Constant(name, type_name, value)
+        const.add_symbol_reference(symbol)
         return const
 
     def _create_typedef_struct(self, symbol, disguised=False):
         name = self.remove_prefix(symbol.ident)
         struct = Struct(name, symbol.ident, disguised)
+        struct.add_symbol_reference(symbol)
         self._typedefs_ns[symbol.ident] = struct
         self._create_struct(symbol)
         return struct
@@ -535,6 +603,7 @@ class Transformer(object):
     def _create_typedef_union(self, symbol):
         name = self.remove_prefix(symbol.ident)
         union = Union(name, symbol.ident)
+        union.add_symbol_reference(symbol)
         self._typedefs_ns[symbol.ident] = union
         self._create_union(symbol)
         return union
@@ -570,6 +639,7 @@ class Transformer(object):
             if field:
                 compound.fields.append(field)
 
+        compound.add_symbol_reference(symbol)
         return compound
 
     def _create_struct(self, symbol, anonymous=False):
@@ -593,6 +663,7 @@ class Transformer(object):
         else:
             name = self.remove_prefix(symbol.ident)
         callback = Callback(name, retval, parameters, symbol.ident)
+        callback.add_symbol_reference(symbol)
 
         return callback
 
index 483e5417a1b7d1bc40bc84d13200b2049af2a920..b156b446dfa1789a01b4bc9bc197fe67be415ae7 100644 (file)
@@ -1,6 +1,8 @@
 include $(top_srcdir)/common.mk
 include $(top_srcdir)/Makefile.introspection
 
+INTROSPECTION_SCANNER_ARGS += --Wall --Werror
+
 # We need to build a shared library, which can be dlopened
 # it does not work with noinst_LTLIBRARIES
 testlib_LTLIBRARIES = \
index eee3c643e3a66c548de226c2317cbfcd94eff532..e1e6cf86b655a1ae190dbcf0084eef6d736453b5 100644 (file)
@@ -360,7 +360,9 @@ uses a C sugar return type.">
           </parameter>
         </parameters>
       </method>
-      <method name="take_all" c:identifier="foo_object_take_all">
+      <method name="take_all"
+              c:identifier="foo_object_take_all"
+              introspectable="0">
         <return-value transfer-ownership="none">
           <type name="none" c:type="void"/>
         </return-value>
@@ -449,6 +451,14 @@ uses a C sugar return type.">
           </parameter>
         </parameters>
       </method>
+      <method name="skipped_method"
+              c:identifier="foo_object_skipped_method"
+              doc="This is only useful from C."
+              introspectable="0">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+      </method>
       <property name="string"
                 writable="1"
                 construct="1"
@@ -569,6 +579,14 @@ uses a C sugar return type.">
     <constant name="SUCCESS_INT" value="4408">
       <type name="int"/>
     </constant>
+    <enumeration name="Skippable"
+                 doc="Some type that is only interesting from C and should not be
+exposed to language bindings."
+                 introspectable="0"
+                 c:type="FooSkippable">
+      <member name="one" value="0" c:identifier="FOO_SKIPPABLE_ONE"/>
+      <member name="two" value="1" c:identifier="FOO_SKIPPABLE_TWO"/>
+    </enumeration>
     <enumeration name="StackLayer" c:type="FooStackLayer">
       <member name="desktop" value="0" c:identifier="FOO_LAYER_DESKTOP"/>
       <member name="bottom" value="1" c:identifier="FOO_LAYER_BOTTOM"/>
@@ -697,7 +715,9 @@ uses a C sugar return type.">
         <type name="utility.Struct" c:type="UtilityStruct"/>
       </field>
     </record>
-    <callback name="VarargsCallback" c:type="FooVarargsCallback">
+    <callback name="VarargsCallback"
+              c:type="FooVarargsCallback"
+              introspectable="0">
       <return-value transfer-ownership="none">
         <type name="none" c:type="void"/>
       </return-value>
@@ -797,6 +817,20 @@ uses a C sugar return type.">
         </parameter>
       </parameters>
     </function>
+    <function name="skip_me"
+              c:identifier="foo_skip_me"
+              doc="Does something that&apos;s only interesting from C and should not be
+exposed to language bindings."
+              introspectable="0">
+      <return-value transfer-ownership="none">
+        <type name="none" c:type="void"/>
+      </return-value>
+      <parameters>
+        <parameter name="fs" transfer-ownership="none">
+          <type name="Skippable" c:type="FooSkippable"/>
+        </parameter>
+      </parameters>
+    </function>
     <function name="test_array" c:identifier="foo_test_array">
       <return-value transfer-ownership="container">
         <array name="GLib.Array" c:type="GArray*">
@@ -885,7 +919,8 @@ uses a C sugar return type.">
       </parameters>
     </function>
     <function name="test_varargs_callback"
-              c:identifier="foo_test_varargs_callback">
+              c:identifier="foo_test_varargs_callback"
+              introspectable="0">
       <return-value transfer-ownership="none">
         <type name="none" c:type="void"/>
       </return-value>
@@ -899,7 +934,8 @@ uses a C sugar return type.">
       </parameters>
     </function>
     <function name="test_varargs_callback2"
-              c:identifier="foo_test_varargs_callback2">
+              c:identifier="foo_test_varargs_callback2"
+              introspectable="0">
       <return-value transfer-ownership="none">
         <type name="none" c:type="void"/>
       </return-value>
@@ -910,7 +946,8 @@ uses a C sugar return type.">
       </parameters>
     </function>
     <function name="test_varargs_callback3"
-              c:identifier="foo_test_varargs_callback3">
+              c:identifier="foo_test_varargs_callback3"
+              introspectable="0">
       <return-value transfer-ownership="none">
         <type name="none" c:type="void"/>
       </return-value>