[gobject-introspection] Support introspectable=no attribute, add warnings framework



commit 5a4fa2bf5648d60d9fc0feb69080c9153b2abe02
Author: Colin Walters <walters verbum org>
Date:   Wed Jun 16 20:34:18 2010 -0400

    Support introspectable=no attribute, add warnings framework
    
    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 --warn-all and --warn-error.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=621570

 docs/g-ir-scanner.1                |    6 +
 gir/Makefile.am                    |    2 +-
 girepository/girparser.c           | 1481 +++++++++++++++++-------------------
 girepository/girparser.h           |    1 +
 giscanner/ast.py                   |   14 +-
 giscanner/girwriter.py             |   33 +-
 giscanner/glibtransformer.py       |  210 ++++--
 giscanner/scannermain.py           |   13 +
 giscanner/sourcescanner.py         |    4 +
 giscanner/transformer.py           |   73 ++-
 tests/scanner/Makefile.am          |    2 +
 tests/scanner/foo-1.0-expected.gir |   47 +-
 12 files changed, 1008 insertions(+), 878 deletions(-)
---
diff --git a/docs/g-ir-scanner.1 b/docs/g-ir-scanner.1
index f5224bb..5089e6b 100644
--- a/docs/g-ir-scanner.1
+++ b/docs/g-ir-scanner.1
@@ -18,6 +18,12 @@ header file (.h). Currently only C based libraries are supported by the scanner.
 .B \--help
 Show help options
 .TP
+.B \--warn-all
+Display warnings for public API which is not introspectable.
+.TP
+.B \--warn-error
+Make warnings be fatal errors.
+.TP
 .B \--format=FORMAT
 This parameters decides which the resulting format will be used.
 The default value is gir.
diff --git a/gir/Makefile.am b/gir/Makefile.am
index 1d88acc..c07a239 100644
--- a/gir/Makefile.am
+++ b/gir/Makefile.am
@@ -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 = --warn-all --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 = \
diff --git a/girepository/girparser.c b/girepository/girparser.c
index f9c1fb6..1badfd7 100644
--- a/girepository/girparser.c
+++ b/girepository/girparser.c
@@ -33,7 +33,7 @@
 /* This is a "major" version in the sense that it's only bumped
  * for incompatible changes.
  */
-#define SUPPORTED_GIR_VERSION "1.0"
+#define SUPPORTED_GIR_VERSION "1.1"
 
 #if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
 # include <execinfo.h>
@@ -77,10 +77,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;
@@ -98,12 +98,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;
@@ -322,7 +322,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;
 }
@@ -344,6 +344,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);
 }
@@ -635,6 +636,32 @@ parse_type (ParseContext *ctx, const gchar *type)
 }
 
 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,
 		  const gchar        **attribute_names,
@@ -652,6 +679,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);
@@ -687,8 +717,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;
 }
 
@@ -727,7 +755,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:
@@ -737,6 +764,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);
@@ -840,7 +873,6 @@ start_function (GMarkupParseContext *context,
       }
 
   push_node(ctx, (GIrNode *)function);
-  state_switch (ctx, STATE_FUNCTION);
 
   return TRUE;
 }
@@ -1223,47 +1255,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
@@ -1274,70 +1306,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);
 
-          parse_property_transfer (property, transfer, ctx);
+  if (name == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
+    }
 
-	  iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
-	  iface->members = g_list_append (iface->members, property);
+  property = (GIrNodeProperty *) g_ir_node_new (G_IR_NODE_PROPERTY);
+  ctx->current_typed = (GIrNode*) property;
 
-	  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 ();
-	}
+  ((GIrNode *)property)->name = g_strdup (name);
 
-      return TRUE;
-    }
-  return FALSE;
+  /* 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;
+
+  parse_property_transfer (property, transfer, ctx);
+
+  iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
+  iface->members = g_list_append (iface->members, property);
+
+  return TRUE;
 }
 
 static gint
@@ -1371,42 +1407,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
@@ -1417,73 +1452,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
@@ -1494,50 +1537,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
@@ -1548,52 +1598,57 @@ 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;
+  const gchar *name;
+  const gchar *typename;
+  const gchar *typeinit;
+  const gchar *deprecated;
+  const gchar *glib_type_struct;
+  GIrNodeInterface *iface;
 
-      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 (!(strcmp (element_name, "interface") == 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)
-	MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
-      else
-	{
-	  GIrNodeInterface *iface;
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_INTERFACE))
+    return TRUE;
 
-	  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;
+  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);
 
-	  push_node (ctx, (GIrNode *) iface);
-	  ctx->current_module->entries =
-	    g_list_append (ctx->current_module->entries, iface);
+  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)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
+      return FALSE;
+    }
 
-	  state_switch (ctx, STATE_INTERFACE);
+  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;
-    }
-  return FALSE;
+  return TRUE;
 }
 
 static gboolean
@@ -1604,58 +1659,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
@@ -1700,47 +1761,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;
     }
@@ -2010,53 +2030,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
@@ -2097,78 +2115,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
@@ -2179,80 +2197,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,
@@ -2262,75 +2280,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,
@@ -2339,48 +2356,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 (name == NULL && ctx->node_stack == NULL)
-	MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else
-	{
-	  GIrNodeUnion *union_;
+  if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_UNION))
+    return TRUE;
 
-	  union_ = (GIrNodeUnion *) g_ir_node_new (G_IR_NODE_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);
 
-	  ((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;
+  if (name == NULL && ctx->node_stack == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
+    }
 
-          if (ctx->node_stack == NULL)
-            ctx->current_module->entries =
-              g_list_append (ctx->current_module->entries, union_);
-	  push_node (ctx, (GIrNode *)union_);
+  union_ = (GIrNodeUnion *) g_ir_node_new (G_IR_NODE_UNION);
 
-	  state_switch (ctx, STATE_UNION);
-	}
-      return TRUE;
-    }
-  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;
+
+  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
@@ -2391,42 +2408,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;
 
@@ -2444,11 +2462,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;
 	    }
 	}
@@ -2459,10 +2474,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;
@@ -2471,22 +2483,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;
@@ -2520,6 +2541,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':
@@ -2619,8 +2646,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));
@@ -2806,22 +2841,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 ();
     }
 }
@@ -3194,7 +3229,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);
@@ -3230,149 +3265,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
@@ -3386,6 +3283,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)
@@ -3395,6 +3293,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);
@@ -3462,7 +3361,6 @@ g_ir_parser_parse_file (GIrParser   *parser,
   gchar *buffer;
   gsize length;
   GList *modules;
-  GList *iter;
   const char *slash;
   char *dash;
   char *namespace;
@@ -3493,12 +3391,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);
 
diff --git a/girepository/girparser.h b/girepository/girparser.h
index ac0d216..6fca1b3 100644
--- a/girepository/girparser.h
+++ b/girepository/girparser.h
@@ -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);
diff --git a/giscanner/ast.py b/giscanner/ast.py
index 0e9f112..a70f2d8 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -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):
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
index 11f9dbe..9b48d4e 100644
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -31,7 +31,7 @@ from .xmlwriter import XMLWriter
 
 # Bump this for *incompatible* changes to the .gir.
 # Compatible changes we just make inline
-COMPATIBLE_GIR_VERSION = '1.0'
+COMPATIBLE_GIR_VERSION = '1.1'
 
 class GIRWriter(XMLWriter):
 
@@ -99,8 +99,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):
@@ -137,7 +136,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:
@@ -155,14 +156,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)
@@ -282,7 +281,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),
@@ -302,7 +301,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),
@@ -315,8 +314,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)]
@@ -336,7 +333,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:
@@ -389,11 +386,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'))
@@ -443,7 +438,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):
@@ -465,7 +460,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):
@@ -511,13 +506,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)
diff --git a/giscanner/glibtransformer.py b/giscanner/glibtransformer.py
index 4248825..7035eb3 100644
--- a/giscanner/glibtransformer.py
+++ b/giscanner/glibtransformer.py
@@ -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, [])
diff --git a/giscanner/scannermain.py b/giscanner/scannermain.py
index 44c0287..be590f1 100644
--- a/giscanner/scannermain.py
+++ b/giscanner/scannermain.py
@@ -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('', "--warn-all",
+                      action="store_true", dest="warn_all", default=False,
+                      help="If true, enable all warnings for introspection")
+    parser.add_option('', "--warn-error",
+                      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
diff --git a/giscanner/sourcescanner.py b/giscanner/sourcescanner.py
index 7b06478..acfc048 100644
--- a/giscanner/sourcescanner.py
+++ b/giscanner/sourcescanner.py
@@ -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):
 
diff --git a/giscanner/transformer.py b/giscanner/transformer.py
index fbc38d5..319e43c 100644
--- a/giscanner/transformer.py
+++ b/giscanner/transformer.py
@@ -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, text, file_positions=None, 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 file_positions is None or 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, text)
+        else:
+            print >>sys.stderr, \
+'''%s: warning: ns=%r: %s''' % (position, self._namespace.name, text)
+
+    def log_symbol_warning(self, symbol, text):
+        """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(text, file_positions, prefix=prefix)
+
+    def log_node_warning(self, node, text, 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:
+            text = "context=%r %s" % (context.name, text)
+
+        self.log_warning(text, 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
 
diff --git a/tests/scanner/Makefile.am b/tests/scanner/Makefile.am
index 483e541..522f8a5 100644
--- a/tests/scanner/Makefile.am
+++ b/tests/scanner/Makefile.am
@@ -1,6 +1,8 @@
 include $(top_srcdir)/common.mk
 include $(top_srcdir)/Makefile.introspection
 
+INTROSPECTION_SCANNER_ARGS += --warn-all --warn-error
+
 # We need to build a shared library, which can be dlopened
 # it does not work with noinst_LTLIBRARIES
 testlib_LTLIBRARIES = \
diff --git a/tests/scanner/foo-1.0-expected.gir b/tests/scanner/foo-1.0-expected.gir
index 07a2efe..68896c1 100644
--- a/tests/scanner/foo-1.0-expected.gir
+++ b/tests/scanner/foo-1.0-expected.gir
@@ -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>



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