From 074192b89c6afcdd7f062f03989972e44334b8bf Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 16 Jun 2010 20:34:18 -0400 Subject: 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 --Wall and --Werror. --- gir/Makefile.am | 2 +- girepository/girparser.c | 1489 +++++++++++++++++------------------- girepository/girparser.h | 1 + giscanner/ast.py | 14 +- giscanner/girwriter.py | 31 +- 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 +- 11 files changed, 1005 insertions(+), 881 deletions(-) diff --git a/gir/Makefile.am b/gir/Makefile.am index 1d88accd..99b305cb 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 = --Wall --strip-prefix=g --c-include="gio/gio.h" --add-include-path=. Gio_2_0_gir_PACKAGES = gio-2.0 $(GIO_UNIX_PACKAGES) Gio_2_0_gir_INCLUDES = GObject-2.0 Gio_2_0_gir_CFLAGS = \ diff --git a/girepository/girparser.c b/girepository/girparser.c index d0bd8aa3..a0c1e21d 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -72,10 +72,10 @@ typedef enum STATE_NAMESPACE_CONSTANT, STATE_CLASS_CONSTANT, STATE_INTERFACE_CONSTANT, - STATE_ALIAS, + STATE_ALIAS, /* 30 */ STATE_TYPE, STATE_ATTRIBUTE, - STATE_UNKNOWN + STATE_PASSTHROUGH } ParseState; typedef struct _ParseContext ParseContext; @@ -93,12 +93,12 @@ struct _ParseContext GHashTable *aliases; GHashTable *disguised_structures; + const char *file_path; const char *namespace; const char *c_prefix; GIrModule *current_module; GSList *node_stack; GIrNode *current_typed; - gboolean is_varargs; GList *type_stack; GList *type_parameters; int type_depth; @@ -317,7 +317,7 @@ find_attribute (const gchar *name, static void state_switch (ParseContext *ctx, ParseState newstate) { - g_debug ("State: %d", newstate); + g_assert (ctx->state != newstate); ctx->prev_state = ctx->state; ctx->state = newstate; } @@ -339,6 +339,7 @@ pop_node (ParseContext *ctx) static void push_node (ParseContext *ctx, GIrNode *node) { + g_assert (node != NULL); g_debug ("pushing node %d %s", node->type, node->name); ctx->node_stack = g_slist_prepend (ctx->node_stack, node); } @@ -629,6 +630,32 @@ parse_type (ParseContext *ctx, const gchar *type) return node; } +static gboolean +introspectable_prelude (GMarkupParseContext *context, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + ParseState new_state) +{ + const gchar *introspectable_arg; + gboolean introspectable; + + g_assert (ctx->state != STATE_PASSTHROUGH); + + introspectable_arg = find_attribute ("introspectable", attribute_names, attribute_values); + introspectable = !(introspectable_arg && atoi (introspectable_arg) == 0); + + if (introspectable) + state_switch (ctx, new_state); + else + { + state_switch (ctx, STATE_PASSTHROUGH); + ctx->unknown_depth = 1; + } + + return introspectable; +} + static gboolean start_glib_boxed (GMarkupParseContext *context, const gchar *element_name, @@ -647,6 +674,9 @@ start_glib_boxed (GMarkupParseContext *context, ctx->state == STATE_NAMESPACE)) return FALSE; + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_BOXED)) + return TRUE; + name = find_attribute ("glib:name", attribute_names, attribute_values); typename = find_attribute ("glib:type-name", attribute_names, attribute_values); typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); @@ -682,8 +712,6 @@ start_glib_boxed (GMarkupParseContext *context, ctx->current_module->entries = g_list_append (ctx->current_module->entries, boxed); - state_switch (ctx, STATE_BOXED); - return TRUE; } @@ -722,7 +750,6 @@ start_function (GMarkupParseContext *context, strcmp (element_name, "callback") == 0); break; case STATE_STRUCT_FIELD: - ctx->in_embedded_type = TRUE; found = (found || strcmp (element_name, "callback") == 0); break; default: @@ -732,6 +759,12 @@ start_function (GMarkupParseContext *context, if (!found) return FALSE; + if (ctx->state == STATE_STRUCT_FIELD) + ctx->in_embedded_type = TRUE; + + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION)) + return TRUE; + name = find_attribute ("name", attribute_names, attribute_values); symbol = find_attribute ("c:identifier", attribute_names, attribute_values); deprecated = find_attribute ("deprecated", attribute_names, attribute_values); @@ -835,7 +868,6 @@ start_function (GMarkupParseContext *context, } push_node(ctx, (GIrNode *)function); - state_switch (ctx, STATE_FUNCTION); return TRUE; } @@ -1218,47 +1250,47 @@ start_enum (GMarkupParseContext *context, ParseContext *ctx, GError **error) { - if ((strcmp (element_name, "enumeration") == 0 && ctx->state == STATE_NAMESPACE) || - (strcmp (element_name, "bitfield") == 0 && ctx->state == STATE_NAMESPACE)) - { - const gchar *name; - const gchar *typename; - const gchar *typeinit; - const gchar *deprecated; + const gchar *name; + const gchar *typename; + const gchar *typeinit; + const gchar *deprecated; + GIrNodeEnum *enum_; - name = find_attribute ("name", attribute_names, attribute_values); - typename = find_attribute ("glib:type-name", attribute_names, attribute_values); - typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); - deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + if (!((strcmp (element_name, "enumeration") == 0 && ctx->state == STATE_NAMESPACE) || + (strcmp (element_name, "bitfield") == 0 && ctx->state == STATE_NAMESPACE))) + return FALSE; - if (name == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "name"); - else - { - GIrNodeEnum *enum_; + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_ENUM)) + return TRUE; - if (strcmp (element_name, "enumeration") == 0) - enum_ = (GIrNodeEnum *) g_ir_node_new (G_IR_NODE_ENUM); - else - enum_ = (GIrNodeEnum *) g_ir_node_new (G_IR_NODE_FLAGS); - ((GIrNode *)enum_)->name = g_strdup (name); - enum_->gtype_name = g_strdup (typename); - enum_->gtype_init = g_strdup (typeinit); - if (deprecated) - enum_->deprecated = TRUE; - else - enum_->deprecated = FALSE; + name = find_attribute ("name", attribute_names, attribute_values); + typename = find_attribute ("glib:type-name", attribute_names, attribute_values); + typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); - push_node (ctx, (GIrNode *) enum_); - ctx->current_module->entries = - g_list_append (ctx->current_module->entries, enum_); + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } - state_switch (ctx, STATE_ENUM); - } + if (strcmp (element_name, "enumeration") == 0) + enum_ = (GIrNodeEnum *) g_ir_node_new (G_IR_NODE_ENUM); + else + enum_ = (GIrNodeEnum *) g_ir_node_new (G_IR_NODE_FLAGS); + ((GIrNode *)enum_)->name = g_strdup (name); + enum_->gtype_name = g_strdup (typename); + enum_->gtype_init = g_strdup (typeinit); + if (deprecated) + enum_->deprecated = TRUE; + else + enum_->deprecated = FALSE; - return TRUE; - } - return FALSE; + push_node (ctx, (GIrNode *) enum_); + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, enum_); + + return TRUE; } static gboolean @@ -1269,70 +1301,74 @@ start_property (GMarkupParseContext *context, ParseContext *ctx, GError **error) { - if (strcmp (element_name, "property") == 0 && - (ctx->state == STATE_CLASS || - ctx->state == STATE_INTERFACE)) - { - const gchar *name; - const gchar *readable; - const gchar *writable; - const gchar *construct; - const gchar *construct_only; - const gchar *transfer; + ParseState target_state; + const gchar *name; + const gchar *readable; + const gchar *writable; + const gchar *construct; + const gchar *construct_only; + const gchar *transfer; + GIrNodeProperty *property; + GIrNodeInterface *iface; - name = find_attribute ("name", attribute_names, attribute_values); - readable = find_attribute ("readable", attribute_names, attribute_values); - writable = find_attribute ("writable", attribute_names, attribute_values); - construct = find_attribute ("construct", attribute_names, attribute_values); - construct_only = find_attribute ("construct-only", attribute_names, attribute_values); - transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values); + if (!(strcmp (element_name, "property") == 0 && + (ctx->state == STATE_CLASS || + ctx->state == STATE_INTERFACE))) + return FALSE; - if (name == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "name"); - else - { - GIrNodeProperty *property; - GIrNodeInterface *iface; + if (ctx->state == STATE_CLASS) + target_state = STATE_CLASS_PROPERTY; + else if (ctx->state == STATE_INTERFACE) + target_state = STATE_INTERFACE_PROPERTY; + else + g_assert_not_reached (); - property = (GIrNodeProperty *) g_ir_node_new (G_IR_NODE_PROPERTY); - ctx->current_typed = (GIrNode*) property; + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, target_state)) + return TRUE; - ((GIrNode *)property)->name = g_strdup (name); - /* Assume properties are readable */ - if (readable == NULL || strcmp (readable, "1") == 0) - property->readable = TRUE; - else - property->readable = FALSE; - if (writable && strcmp (writable, "1") == 0) - property->writable = TRUE; - else - property->writable = FALSE; - if (construct && strcmp (construct, "1") == 0) - property->construct = TRUE; - else - property->construct = FALSE; - if (construct_only && strcmp (construct_only, "1") == 0) - property->construct_only = TRUE; - else - property->construct_only = FALSE; + name = find_attribute ("name", attribute_names, attribute_values); + readable = find_attribute ("readable", attribute_names, attribute_values); + writable = find_attribute ("writable", attribute_names, attribute_values); + construct = find_attribute ("construct", attribute_names, attribute_values); + construct_only = find_attribute ("construct-only", attribute_names, attribute_values); + transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } - parse_property_transfer (property, transfer, ctx); + property = (GIrNodeProperty *) g_ir_node_new (G_IR_NODE_PROPERTY); + ctx->current_typed = (GIrNode*) property; - iface = (GIrNodeInterface *)CURRENT_NODE (ctx); - iface->members = g_list_append (iface->members, property); + ((GIrNode *)property)->name = g_strdup (name); - if (ctx->state == STATE_CLASS) - state_switch (ctx, STATE_CLASS_PROPERTY); - else if (ctx->state == STATE_INTERFACE) - state_switch (ctx, STATE_INTERFACE_PROPERTY); - else - g_assert_not_reached (); - } + /* Assume properties are readable */ + if (readable == NULL || strcmp (readable, "1") == 0) + property->readable = TRUE; + else + property->readable = FALSE; + if (writable && strcmp (writable, "1") == 0) + property->writable = TRUE; + else + property->writable = FALSE; + if (construct && strcmp (construct, "1") == 0) + property->construct = TRUE; + else + property->construct = FALSE; + if (construct_only && strcmp (construct_only, "1") == 0) + property->construct_only = TRUE; + else + property->construct_only = FALSE; - return TRUE; - } - return FALSE; + parse_property_transfer (property, transfer, ctx); + + iface = (GIrNodeInterface *)CURRENT_NODE (ctx); + iface->members = g_list_append (iface->members, property); + + return TRUE; } static gint @@ -1366,42 +1402,41 @@ start_member (GMarkupParseContext *context, ParseContext *ctx, GError **error) { - if (strcmp (element_name, "member") == 0 && - ctx->state == STATE_ENUM) - { - const gchar *name; - const gchar *value; - const gchar *deprecated; + const gchar *name; + const gchar *value; + const gchar *deprecated; + GIrNodeEnum *enum_; + GIrNodeValue *value_; - name = find_attribute ("name", attribute_names, attribute_values); - value = find_attribute ("value", attribute_names, attribute_values); - deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + if (!(strcmp (element_name, "member") == 0 && + ctx->state == STATE_ENUM)) + return FALSE; - if (name == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "name"); - else - { - GIrNodeEnum *enum_; - GIrNodeValue *value_; + name = find_attribute ("name", attribute_names, attribute_values); + value = find_attribute ("value", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } - value_ = (GIrNodeValue *) g_ir_node_new (G_IR_NODE_VALUE); + value_ = (GIrNodeValue *) g_ir_node_new (G_IR_NODE_VALUE); - ((GIrNode *)value_)->name = g_strdup (name); + ((GIrNode *)value_)->name = g_strdup (name); - value_->value = parse_value (value); + value_->value = parse_value (value); - if (deprecated) - value_->deprecated = TRUE; - else - value_->deprecated = FALSE; + if (deprecated) + value_->deprecated = TRUE; + else + value_->deprecated = FALSE; - enum_ = (GIrNodeEnum *)CURRENT_NODE (ctx); - enum_->values = g_list_append (enum_->values, value_); - } + enum_ = (GIrNodeEnum *)CURRENT_NODE (ctx); + enum_->values = g_list_append (enum_->values, value_); - return TRUE; - } - return FALSE; + return TRUE; } static gboolean @@ -1412,73 +1447,81 @@ start_constant (GMarkupParseContext *context, ParseContext *ctx, GError **error) { - if (strcmp (element_name, "constant") == 0 && - (ctx->state == STATE_NAMESPACE || - ctx->state == STATE_CLASS || - ctx->state == STATE_INTERFACE)) + ParseState prev_state; + ParseState target_state; + const gchar *name; + const gchar *value; + const gchar *deprecated; + GIrNodeConstant *constant; + + if (!(strcmp (element_name, "constant") == 0 && + (ctx->state == STATE_NAMESPACE || + ctx->state == STATE_CLASS || + ctx->state == STATE_INTERFACE))) + return FALSE; + + switch (ctx->state) { - const gchar *name; - const gchar *value; - const gchar *deprecated; + case STATE_NAMESPACE: + target_state = STATE_NAMESPACE_CONSTANT; + break; + case STATE_CLASS: + target_state = STATE_CLASS_CONSTANT; + break; + case STATE_INTERFACE: + target_state = STATE_INTERFACE_CONSTANT; + break; + default: + g_assert_not_reached (); + } - name = find_attribute ("name", attribute_names, attribute_values); - value = find_attribute ("value", attribute_names, attribute_values); - deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + prev_state = ctx->state; - if (name == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "name"); - else if (value == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "value"); - else - { - GIrNodeConstant *constant; + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, target_state)) + return TRUE; - constant = (GIrNodeConstant *) g_ir_node_new (G_IR_NODE_CONSTANT); + name = find_attribute ("name", attribute_names, attribute_values); + value = find_attribute ("value", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); - ((GIrNode *)constant)->name = g_strdup (name); - constant->value = g_strdup (value); + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + else if (value == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "value"); + return FALSE; + } - ctx->current_typed = (GIrNode*) constant; + constant = (GIrNodeConstant *) g_ir_node_new (G_IR_NODE_CONSTANT); - if (deprecated) - constant->deprecated = TRUE; - else - constant->deprecated = FALSE; + ((GIrNode *)constant)->name = g_strdup (name); + constant->value = g_strdup (value); - if (ctx->state == STATE_NAMESPACE) - { - push_node (ctx, (GIrNode *) constant); - ctx->current_module->entries = - g_list_append (ctx->current_module->entries, constant); - } - else - { - GIrNodeInterface *iface; + ctx->current_typed = (GIrNode*) constant; - iface = (GIrNodeInterface *)CURRENT_NODE (ctx); - iface->members = g_list_append (iface->members, constant); - } + if (deprecated) + constant->deprecated = TRUE; + else + constant->deprecated = FALSE; - switch (ctx->state) - { - case STATE_NAMESPACE: - state_switch (ctx, STATE_NAMESPACE_CONSTANT); - break; - case STATE_CLASS: - state_switch (ctx, STATE_CLASS_CONSTANT); - break; - case STATE_INTERFACE: - state_switch (ctx, STATE_INTERFACE_CONSTANT); - break; - default: - g_assert_not_reached (); - break; - } - } + if (prev_state == STATE_NAMESPACE) + { + push_node (ctx, (GIrNode *) constant); + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, constant); + } + else + { + GIrNodeInterface *iface; - return TRUE; + iface = (GIrNodeInterface *)CURRENT_NODE (ctx); + iface->members = g_list_append (iface->members, constant); } - return FALSE; + + return TRUE; } static gboolean @@ -1489,50 +1532,57 @@ start_errordomain (GMarkupParseContext *context, ParseContext *ctx, GError **error) { - if (strcmp (element_name, "errordomain") == 0 && - ctx->state == STATE_NAMESPACE) - { - const gchar *name; - const gchar *getquark; - const gchar *codes; - const gchar *deprecated; + const gchar *name; + const gchar *getquark; + const gchar *codes; + const gchar *deprecated; + GIrNodeErrorDomain *domain; - name = find_attribute ("name", attribute_names, attribute_values); - getquark = find_attribute ("get-quark", attribute_names, attribute_values); - codes = find_attribute ("codes", attribute_names, attribute_values); - deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + if (!(strcmp (element_name, "errordomain") == 0 && + ctx->state == STATE_NAMESPACE)) + return FALSE; - if (name == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "name"); - else if (getquark == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "getquark"); - else if (codes == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "codes"); - else - { - GIrNodeErrorDomain *domain; + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_ERRORDOMAIN)) + return TRUE; - domain = (GIrNodeErrorDomain *) g_ir_node_new (G_IR_NODE_ERROR_DOMAIN); - ((GIrNode *)domain)->name = g_strdup (name); - domain->getquark = g_strdup (getquark); - domain->codes = g_strdup (codes); + name = find_attribute ("name", attribute_names, attribute_values); + getquark = find_attribute ("get-quark", attribute_names, attribute_values); + codes = find_attribute ("codes", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); - if (deprecated) - domain->deprecated = TRUE; - else - domain->deprecated = FALSE; + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + else if (getquark == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "getquark"); + return FALSE; + } + else if (codes == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "codes"); + return FALSE; + } - push_node (ctx, (GIrNode *) domain); - ctx->current_module->entries = - g_list_append (ctx->current_module->entries, domain); + domain = (GIrNodeErrorDomain *) g_ir_node_new (G_IR_NODE_ERROR_DOMAIN); - state_switch (ctx, STATE_ERRORDOMAIN); - } + ((GIrNode *)domain)->name = g_strdup (name); + domain->getquark = g_strdup (getquark); + domain->codes = g_strdup (codes); - return TRUE; - } - return FALSE; + if (deprecated) + domain->deprecated = TRUE; + else + domain->deprecated = FALSE; + + push_node (ctx, (GIrNode *) domain); + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, domain); + + return TRUE; } static gboolean @@ -1543,55 +1593,60 @@ start_interface (GMarkupParseContext *context, ParseContext *ctx, GError **error) { - if (strcmp (element_name, "interface") == 0 && - ctx->state == STATE_NAMESPACE) - { - const gchar *name; - const gchar *typename; - const gchar *typeinit; - const gchar *deprecated; - const gchar *glib_type_struct; - - name = find_attribute ("name", attribute_names, attribute_values); - typename = find_attribute ("glib:type-name", attribute_names, attribute_values); - typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); - glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values); - deprecated = find_attribute ("deprecated", attribute_names, attribute_values); - - if (name == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "name"); - else if (typename == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name"); - else if (typeinit == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type"); - else - { - GIrNodeInterface *iface; - - iface = (GIrNodeInterface *) g_ir_node_new (G_IR_NODE_INTERFACE); - ((GIrNode *)iface)->name = g_strdup (name); - iface->gtype_name = g_strdup (typename); - iface->gtype_init = g_strdup (typeinit); - iface->glib_type_struct = g_strdup (glib_type_struct); - if (deprecated) - iface->deprecated = TRUE; - else - iface->deprecated = FALSE; + const gchar *name; + const gchar *typename; + const gchar *typeinit; + const gchar *deprecated; + const gchar *glib_type_struct; + GIrNodeInterface *iface; - push_node (ctx, (GIrNode *) iface); - ctx->current_module->entries = - g_list_append (ctx->current_module->entries, iface); + if (!(strcmp (element_name, "interface") == 0 && + ctx->state == STATE_NAMESPACE)) + return FALSE; - state_switch (ctx, STATE_INTERFACE); + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_INTERFACE)) + return TRUE; - } + name = find_attribute ("name", attribute_names, attribute_values); + typename = find_attribute ("glib:type-name", attribute_names, attribute_values); + typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); + glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); - return TRUE; + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; } - return FALSE; -} - -static gboolean + else if (typename == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name"); + return FALSE; + } + else if (typeinit == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type"); + return FALSE; + } + + iface = (GIrNodeInterface *) g_ir_node_new (G_IR_NODE_INTERFACE); + ((GIrNode *)iface)->name = g_strdup (name); + iface->gtype_name = g_strdup (typename); + iface->gtype_init = g_strdup (typeinit); + iface->glib_type_struct = g_strdup (glib_type_struct); + if (deprecated) + iface->deprecated = TRUE; + else + iface->deprecated = FALSE; + + push_node (ctx, (GIrNode *) iface); + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, iface); + + return TRUE; +} + +static gboolean start_class (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, @@ -1599,58 +1654,64 @@ start_class (GMarkupParseContext *context, ParseContext *ctx, GError **error) { - if (strcmp (element_name, "class") == 0 && - ctx->state == STATE_NAMESPACE) - { - const gchar *name; - const gchar *parent; - const gchar *glib_type_struct; - const gchar *typename; - const gchar *typeinit; - const gchar *deprecated; - const gchar *abstract; + const gchar *name; + const gchar *parent; + const gchar *glib_type_struct; + const gchar *typename; + const gchar *typeinit; + const gchar *deprecated; + const gchar *abstract; + GIrNodeInterface *iface; - name = find_attribute ("name", attribute_names, attribute_values); - parent = find_attribute ("parent", attribute_names, attribute_values); - glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values); - typename = find_attribute ("glib:type-name", attribute_names, attribute_values); - typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); - deprecated = find_attribute ("deprecated", attribute_names, attribute_values); - abstract = find_attribute ("abstract", attribute_names, attribute_values); + if (!(strcmp (element_name, "class") == 0 && + ctx->state == STATE_NAMESPACE)) + return FALSE; - if (name == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "name"); - else if (typename == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name"); - else if (typeinit == NULL && strcmp (typename, "GObject")) - MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type"); - else - { - GIrNodeInterface *iface; + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_CLASS)) + return TRUE; - iface = (GIrNodeInterface *) g_ir_node_new (G_IR_NODE_OBJECT); - ((GIrNode *)iface)->name = g_strdup (name); - iface->gtype_name = g_strdup (typename); - iface->gtype_init = g_strdup (typeinit); - iface->parent = g_strdup (parent); - iface->glib_type_struct = g_strdup (glib_type_struct); - if (deprecated) - iface->deprecated = TRUE; - else - iface->deprecated = FALSE; + name = find_attribute ("name", attribute_names, attribute_values); + parent = find_attribute ("parent", attribute_names, attribute_values); + glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values); + typename = find_attribute ("glib:type-name", attribute_names, attribute_values); + typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + abstract = find_attribute ("abstract", attribute_names, attribute_values); - iface->abstract = abstract && strcmp (abstract, "1") == 0; + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + else if (typename == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name"); + return FALSE; + } + else if (typeinit == NULL && strcmp (typename, "GObject")) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type"); + return FALSE; + } - push_node (ctx, (GIrNode *) iface); - ctx->current_module->entries = - g_list_append (ctx->current_module->entries, iface); + iface = (GIrNodeInterface *) g_ir_node_new (G_IR_NODE_OBJECT); + ((GIrNode *)iface)->name = g_strdup (name); + iface->gtype_name = g_strdup (typename); + iface->gtype_init = g_strdup (typeinit); + iface->parent = g_strdup (parent); + iface->glib_type_struct = g_strdup (glib_type_struct); + if (deprecated) + iface->deprecated = TRUE; + else + iface->deprecated = FALSE; - state_switch (ctx, STATE_CLASS); - } + iface->abstract = abstract && strcmp (abstract, "1") == 0; - return TRUE; - } - return FALSE; + push_node (ctx, (GIrNode *) iface); + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, iface); + + return TRUE; } static gboolean @@ -1695,47 +1756,6 @@ start_type (GMarkupParseContext *context, { state_switch (ctx, STATE_TYPE); ctx->type_depth = 1; - if (is_varargs) - { - switch (CURRENT_NODE (ctx)->type) - { - case G_IR_NODE_FUNCTION: - case G_IR_NODE_CALLBACK: - { - GIrNodeFunction *func = (GIrNodeFunction *)CURRENT_NODE (ctx); - func->is_varargs = TRUE; - } - break; - case G_IR_NODE_VFUNC: - { - GIrNodeVFunc *vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx); - vfunc->is_varargs = TRUE; - } - break; - /* list others individually rather than with default: so that compiler - * warns if new node types are added without adding them to the switch - */ - case G_IR_NODE_INVALID: - case G_IR_NODE_ENUM: - case G_IR_NODE_FLAGS: - case G_IR_NODE_CONSTANT: - case G_IR_NODE_ERROR_DOMAIN: - case G_IR_NODE_PARAM: - case G_IR_NODE_TYPE: - case G_IR_NODE_PROPERTY: - case G_IR_NODE_SIGNAL: - case G_IR_NODE_VALUE: - case G_IR_NODE_FIELD: - case G_IR_NODE_XREF: - case G_IR_NODE_STRUCT: - case G_IR_NODE_BOXED: - case G_IR_NODE_OBJECT: - case G_IR_NODE_INTERFACE: - case G_IR_NODE_UNION: - g_assert_not_reached (); - break; - } - } ctx->type_stack = NULL; ctx->type_parameters = NULL; } @@ -2005,53 +2025,51 @@ start_return_value (GMarkupParseContext *context, ParseContext *ctx, GError **error) { - if (strcmp (element_name, "return-value") == 0 && - ctx->state == STATE_FUNCTION) - { - GIrNodeParam *param; - const gchar *transfer; + GIrNodeParam *param; + const gchar *transfer; - param = (GIrNodeParam *)g_ir_node_new (G_IR_NODE_PARAM); - param->in = FALSE; - param->out = FALSE; - param->retval = TRUE; + if (!(strcmp (element_name, "return-value") == 0 && + ctx->state == STATE_FUNCTION)) + return FALSE; - ctx->current_typed = (GIrNode*) param; + param = (GIrNodeParam *)g_ir_node_new (G_IR_NODE_PARAM); + param->in = FALSE; + param->out = FALSE; + param->retval = TRUE; - state_switch (ctx, STATE_FUNCTION_RETURN); + ctx->current_typed = (GIrNode*) param; - transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values); - parse_param_transfer (param, transfer, NULL); + state_switch (ctx, STATE_FUNCTION_RETURN); - switch (CURRENT_NODE (ctx)->type) - { - case G_IR_NODE_FUNCTION: - case G_IR_NODE_CALLBACK: - { - GIrNodeFunction *func = (GIrNodeFunction *)CURRENT_NODE (ctx); - func->result = param; - } - break; - case G_IR_NODE_SIGNAL: - { - GIrNodeSignal *signal = (GIrNodeSignal *)CURRENT_NODE (ctx); - signal->result = param; - } - break; - case G_IR_NODE_VFUNC: - { - GIrNodeVFunc *vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx); - vfunc->result = param; - } - break; - default: - g_assert_not_reached (); - } + transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values); + parse_param_transfer (param, transfer, NULL); - return TRUE; + switch (CURRENT_NODE (ctx)->type) + { + case G_IR_NODE_FUNCTION: + case G_IR_NODE_CALLBACK: + { + GIrNodeFunction *func = (GIrNodeFunction *)CURRENT_NODE (ctx); + func->result = param; + } + break; + case G_IR_NODE_SIGNAL: + { + GIrNodeSignal *signal = (GIrNodeSignal *)CURRENT_NODE (ctx); + signal->result = param; + } + break; + case G_IR_NODE_VFUNC: + { + GIrNodeVFunc *vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx); + vfunc->result = param; + } + break; + default: + g_assert_not_reached (); } - return FALSE; + return TRUE; } static gboolean @@ -2092,78 +2110,78 @@ start_glib_signal (GMarkupParseContext *context, ParseContext *ctx, GError **error) { - if (strcmp (element_name, "glib:signal") == 0 && - (ctx->state == STATE_CLASS || - ctx->state == STATE_INTERFACE)) - { - const gchar *name; - const gchar *when; - const gchar *no_recurse; - const gchar *detailed; - const gchar *action; - const gchar *no_hooks; - const gchar *has_class_closure; + const gchar *name; + const gchar *when; + const gchar *no_recurse; + const gchar *detailed; + const gchar *action; + const gchar *no_hooks; + const gchar *has_class_closure; + GIrNodeInterface *iface; + GIrNodeSignal *signal; - name = find_attribute ("name", attribute_names, attribute_values); - when = find_attribute ("when", attribute_names, attribute_values); - no_recurse = find_attribute ("no-recurse", attribute_names, attribute_values); - detailed = find_attribute ("detailed", attribute_names, attribute_values); - action = find_attribute ("action", attribute_names, attribute_values); - no_hooks = find_attribute ("no-hooks", attribute_names, attribute_values); - has_class_closure = find_attribute ("has-class-closure", attribute_names, attribute_values); + if (!(strcmp (element_name, "glib:signal") == 0 && + (ctx->state == STATE_CLASS || + ctx->state == STATE_INTERFACE))) + return FALSE; - if (name == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "name"); - else - { - GIrNodeInterface *iface; - GIrNodeSignal *signal; + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION)) + return TRUE; - signal = (GIrNodeSignal *)g_ir_node_new (G_IR_NODE_SIGNAL); + name = find_attribute ("name", attribute_names, attribute_values); + when = find_attribute ("when", attribute_names, attribute_values); + no_recurse = find_attribute ("no-recurse", attribute_names, attribute_values); + detailed = find_attribute ("detailed", attribute_names, attribute_values); + action = find_attribute ("action", attribute_names, attribute_values); + no_hooks = find_attribute ("no-hooks", attribute_names, attribute_values); + has_class_closure = find_attribute ("has-class-closure", attribute_names, attribute_values); - ((GIrNode *)signal)->name = g_strdup (name); + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + signal = (GIrNodeSignal *)g_ir_node_new (G_IR_NODE_SIGNAL); - signal->run_first = FALSE; - signal->run_last = FALSE; - signal->run_cleanup = FALSE; - if (when == NULL || strcmp (when, "LAST") == 0) - signal->run_last = TRUE; - else if (strcmp (when, "FIRST") == 0) - signal->run_first = TRUE; - else - signal->run_cleanup = TRUE; + ((GIrNode *)signal)->name = g_strdup (name); - if (no_recurse && strcmp (no_recurse, "1") == 0) - signal->no_recurse = TRUE; - else - signal->no_recurse = FALSE; - if (detailed && strcmp (detailed, "1") == 0) - signal->detailed = TRUE; - else - signal->detailed = FALSE; - if (action && strcmp (action, "1") == 0) - signal->action = TRUE; - else - signal->action = FALSE; - if (no_hooks && strcmp (no_hooks, "1") == 0) - signal->no_hooks = TRUE; - else - signal->no_hooks = FALSE; - if (has_class_closure && strcmp (has_class_closure, "1") == 0) - signal->has_class_closure = TRUE; - else - signal->has_class_closure = FALSE; + signal->run_first = FALSE; + signal->run_last = FALSE; + signal->run_cleanup = FALSE; + if (when == NULL || strcmp (when, "LAST") == 0) + signal->run_last = TRUE; + else if (strcmp (when, "FIRST") == 0) + signal->run_first = TRUE; + else + signal->run_cleanup = TRUE; - iface = (GIrNodeInterface *)CURRENT_NODE (ctx); - iface->members = g_list_append (iface->members, signal); + if (no_recurse && strcmp (no_recurse, "1") == 0) + signal->no_recurse = TRUE; + else + signal->no_recurse = FALSE; + if (detailed && strcmp (detailed, "1") == 0) + signal->detailed = TRUE; + else + signal->detailed = FALSE; + if (action && strcmp (action, "1") == 0) + signal->action = TRUE; + else + signal->action = FALSE; + if (no_hooks && strcmp (no_hooks, "1") == 0) + signal->no_hooks = TRUE; + else + signal->no_hooks = FALSE; + if (has_class_closure && strcmp (has_class_closure, "1") == 0) + signal->has_class_closure = TRUE; + else + signal->has_class_closure = FALSE; - push_node (ctx, (GIrNode *)signal); - state_switch (ctx, STATE_FUNCTION); - } + iface = (GIrNodeInterface *)CURRENT_NODE (ctx); + iface->members = g_list_append (iface->members, signal); - return TRUE; - } - return FALSE; + push_node (ctx, (GIrNode *)signal); + + return TRUE; } static gboolean @@ -2174,80 +2192,80 @@ start_vfunc (GMarkupParseContext *context, ParseContext *ctx, GError **error) { - if (strcmp (element_name, "virtual-method") == 0 && - (ctx->state == STATE_CLASS || - ctx->state == STATE_INTERFACE)) - { - const gchar *name; - const gchar *must_chain_up; - const gchar *override; - const gchar *is_class_closure; - const gchar *offset; - const gchar *invoker; + const gchar *name; + const gchar *must_chain_up; + const gchar *override; + const gchar *is_class_closure; + const gchar *offset; + const gchar *invoker; + GIrNodeInterface *iface; + GIrNodeVFunc *vfunc; - name = find_attribute ("name", attribute_names, attribute_values); - must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values); - override = find_attribute ("override", attribute_names, attribute_values); - is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values); - offset = find_attribute ("offset", attribute_names, attribute_values); - invoker = find_attribute ("invoker", attribute_names, attribute_values); + if (!(strcmp (element_name, "virtual-method") == 0 && + (ctx->state == STATE_CLASS || + ctx->state == STATE_INTERFACE))) + return FALSE; - if (name == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "name"); - else - { - GIrNodeInterface *iface; - GIrNodeVFunc *vfunc; + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION)) + return TRUE; - vfunc = (GIrNodeVFunc *)g_ir_node_new (G_IR_NODE_VFUNC); + name = find_attribute ("name", attribute_names, attribute_values); + must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values); + override = find_attribute ("override", attribute_names, attribute_values); + is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values); + offset = find_attribute ("offset", attribute_names, attribute_values); + invoker = find_attribute ("invoker", attribute_names, attribute_values); - ((GIrNode *)vfunc)->name = g_strdup (name); + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } - if (must_chain_up && strcmp (must_chain_up, "1") == 0) - vfunc->must_chain_up = TRUE; - else - vfunc->must_chain_up = FALSE; + vfunc = (GIrNodeVFunc *)g_ir_node_new (G_IR_NODE_VFUNC); - if (override && strcmp (override, "always") == 0) - { - vfunc->must_be_implemented = TRUE; - vfunc->must_not_be_implemented = FALSE; - } - else if (override && strcmp (override, "never") == 0) - { - vfunc->must_be_implemented = FALSE; - vfunc->must_not_be_implemented = TRUE; - } - else - { - vfunc->must_be_implemented = FALSE; - vfunc->must_not_be_implemented = FALSE; - } + ((GIrNode *)vfunc)->name = g_strdup (name); - if (is_class_closure && strcmp (is_class_closure, "1") == 0) - vfunc->is_class_closure = TRUE; - else - vfunc->is_class_closure = FALSE; + if (must_chain_up && strcmp (must_chain_up, "1") == 0) + vfunc->must_chain_up = TRUE; + else + vfunc->must_chain_up = FALSE; - if (offset) - vfunc->offset = atoi (offset); - else - vfunc->offset = 0; + if (override && strcmp (override, "always") == 0) + { + vfunc->must_be_implemented = TRUE; + vfunc->must_not_be_implemented = FALSE; + } + else if (override && strcmp (override, "never") == 0) + { + vfunc->must_be_implemented = FALSE; + vfunc->must_not_be_implemented = TRUE; + } + else + { + vfunc->must_be_implemented = FALSE; + vfunc->must_not_be_implemented = FALSE; + } - vfunc->invoker = g_strdup (invoker); + if (is_class_closure && strcmp (is_class_closure, "1") == 0) + vfunc->is_class_closure = TRUE; + else + vfunc->is_class_closure = FALSE; - iface = (GIrNodeInterface *)CURRENT_NODE (ctx); - iface->members = g_list_append (iface->members, vfunc); + if (offset) + vfunc->offset = atoi (offset); + else + vfunc->offset = 0; - push_node (ctx, (GIrNode *)vfunc); - state_switch (ctx, STATE_FUNCTION); - } + vfunc->invoker = g_strdup (invoker); - return TRUE; - } - return FALSE; -} + iface = (GIrNodeInterface *)CURRENT_NODE (ctx); + iface->members = g_list_append (iface->members, vfunc); + + push_node (ctx, (GIrNode *)vfunc); + return TRUE; +} static gboolean start_struct (GMarkupParseContext *context, @@ -2257,75 +2275,74 @@ start_struct (GMarkupParseContext *context, ParseContext *ctx, GError **error) { - if (strcmp (element_name, "record") == 0 && - (ctx->state == STATE_NAMESPACE || - ctx->state == STATE_UNION || - ctx->state == STATE_STRUCT || - ctx->state == STATE_CLASS)) - { - const gchar *name; - const gchar *deprecated; - const gchar *disguised; - const gchar *gtype_name; - const gchar *gtype_init; - const gchar *gtype_struct; - const gchar *foreign; - GIrNodeStruct *struct_; + const gchar *name; + const gchar *deprecated; + const gchar *disguised; + const gchar *gtype_name; + const gchar *gtype_init; + const gchar *gtype_struct; + const gchar *foreign; + GIrNodeStruct *struct_; + + if (!(strcmp (element_name, "record") == 0 && + (ctx->state == STATE_NAMESPACE || + ctx->state == STATE_UNION || + ctx->state == STATE_STRUCT || + ctx->state == STATE_CLASS))) + return FALSE; - name = find_attribute ("name", attribute_names, attribute_values); - deprecated = find_attribute ("deprecated", attribute_names, attribute_values); - disguised = find_attribute ("disguised", attribute_names, attribute_values); - gtype_name = find_attribute ("glib:type-name", attribute_names, attribute_values); - gtype_init = find_attribute ("glib:get-type", attribute_names, attribute_values); - gtype_struct = find_attribute ("glib:is-gtype-struct-for", attribute_names, attribute_values); - foreign = find_attribute ("foreign", attribute_names, attribute_values); + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_STRUCT)) + return TRUE; - if (name == NULL && ctx->node_stack == NULL) - { - MISSING_ATTRIBUTE (context, error, element_name, "name"); - return FALSE; - } - if ((gtype_name == NULL && gtype_init != NULL)) - { - MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name"); - return FALSE; - } - if ((gtype_name != NULL && gtype_init == NULL)) - { - MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type"); - return FALSE; - } + name = find_attribute ("name", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + disguised = find_attribute ("disguised", attribute_names, attribute_values); + gtype_name = find_attribute ("glib:type-name", attribute_names, attribute_values); + gtype_init = find_attribute ("glib:get-type", attribute_names, attribute_values); + gtype_struct = find_attribute ("glib:is-gtype-struct-for", attribute_names, attribute_values); + foreign = find_attribute ("foreign", attribute_names, attribute_values); - struct_ = (GIrNodeStruct *) g_ir_node_new (G_IR_NODE_STRUCT); + if (name == NULL && ctx->node_stack == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + if ((gtype_name == NULL && gtype_init != NULL)) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name"); + return FALSE; + } + if ((gtype_name != NULL && gtype_init == NULL)) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type"); + return FALSE; + } - ((GIrNode *)struct_)->name = g_strdup (name ? name : ""); - if (deprecated) - struct_->deprecated = TRUE; - else - struct_->deprecated = FALSE; + struct_ = (GIrNodeStruct *) g_ir_node_new (G_IR_NODE_STRUCT); - if (disguised && strcmp (disguised, "1") == 0) - struct_->disguised = TRUE; + ((GIrNode *)struct_)->name = g_strdup (name ? name : ""); + if (deprecated) + struct_->deprecated = TRUE; + else + struct_->deprecated = FALSE; - struct_->is_gtype_struct = gtype_struct != NULL; + if (disguised && strcmp (disguised, "1") == 0) + struct_->disguised = TRUE; - struct_->gtype_name = g_strdup (gtype_name); - struct_->gtype_init = g_strdup (gtype_init); + struct_->is_gtype_struct = gtype_struct != NULL; - struct_->foreign = (g_strcmp0 (foreign, "1") == 0); + struct_->gtype_name = g_strdup (gtype_name); + struct_->gtype_init = g_strdup (gtype_init); - if (ctx->node_stack == NULL) - ctx->current_module->entries = - g_list_append (ctx->current_module->entries, struct_); - push_node (ctx, (GIrNode *)struct_); + struct_->foreign = (g_strcmp0 (foreign, "1") == 0); - state_switch (ctx, STATE_STRUCT); - return TRUE; - } - return FALSE; + if (ctx->node_stack == NULL) + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, struct_); + push_node (ctx, (GIrNode *)struct_); + return TRUE; } - static gboolean start_union (GMarkupParseContext *context, const gchar *element_name, @@ -2334,48 +2351,48 @@ start_union (GMarkupParseContext *context, ParseContext *ctx, GError **error) { - if (strcmp (element_name, "union") == 0 && - (ctx->state == STATE_NAMESPACE || - ctx->state == STATE_UNION || - ctx->state == STATE_STRUCT || - ctx->state == STATE_CLASS)) - { - const gchar *name; - const gchar *deprecated; - const gchar *typename; - const gchar *typeinit; + const gchar *name; + const gchar *deprecated; + const gchar *typename; + const gchar *typeinit; + GIrNodeUnion *union_; - name = find_attribute ("name", attribute_names, attribute_values); - deprecated = find_attribute ("deprecated", attribute_names, attribute_values); - typename = find_attribute ("glib:type-name", attribute_names, attribute_values); - typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); + if (!(strcmp (element_name, "union") == 0 && + (ctx->state == STATE_NAMESPACE || + ctx->state == STATE_UNION || + ctx->state == STATE_STRUCT || + ctx->state == STATE_CLASS))) + return FALSE; + + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_UNION)) + return TRUE; - if (name == NULL && ctx->node_stack == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "name"); - else - { - GIrNodeUnion *union_; + name = find_attribute ("name", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + typename = find_attribute ("glib:type-name", attribute_names, attribute_values); + typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); - union_ = (GIrNodeUnion *) g_ir_node_new (G_IR_NODE_UNION); + if (name == NULL && ctx->node_stack == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } - ((GIrNode *)union_)->name = g_strdup (name ? name : ""); - union_->gtype_name = g_strdup (typename); - union_->gtype_init = g_strdup (typeinit); - if (deprecated) - union_->deprecated = TRUE; - else - union_->deprecated = FALSE; + union_ = (GIrNodeUnion *) g_ir_node_new (G_IR_NODE_UNION); - if (ctx->node_stack == NULL) - ctx->current_module->entries = - g_list_append (ctx->current_module->entries, union_); - push_node (ctx, (GIrNode *)union_); + ((GIrNode *)union_)->name = g_strdup (name ? name : ""); + union_->gtype_name = g_strdup (typename); + union_->gtype_init = g_strdup (typeinit); + if (deprecated) + union_->deprecated = TRUE; + else + union_->deprecated = FALSE; - state_switch (ctx, STATE_UNION); - } - return TRUE; - } - return FALSE; + if (ctx->node_stack == NULL) + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, union_); + push_node (ctx, (GIrNode *)union_); + return TRUE; } static gboolean @@ -2386,42 +2403,43 @@ start_discriminator (GMarkupParseContext *context, ParseContext *ctx, GError **error) { - if (strcmp (element_name, "discriminator") == 0 && - ctx->state == STATE_UNION) - { - const gchar *type; - const gchar *offset; - - type = find_attribute ("type", attribute_names, attribute_values); - offset = find_attribute ("offset", attribute_names, attribute_values); - if (type == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "type"); - else if (offset == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "offset"); - { - ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_type - = parse_type (ctx, type); - ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_offset - = atoi (offset); - } + const gchar *type; + const gchar *offset; + if (!(strcmp (element_name, "discriminator") == 0 && + ctx->state == STATE_UNION)) + return FALSE; - return TRUE; + type = find_attribute ("type", attribute_names, attribute_values); + offset = find_attribute ("offset", attribute_names, attribute_values); + if (type == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "type"); + return FALSE; + } + else if (offset == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "offset"); + return FALSE; } - return FALSE; + ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_type + = parse_type (ctx, type); + ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_offset + = atoi (offset); + + return TRUE; } static gboolean parse_include (GMarkupParseContext *context, ParseContext *ctx, const char *name, - const char *version, - GError **error) + const char *version) { + GError *error = NULL; gchar *buffer; gsize length; gchar *girpath, *girname; - gboolean success = FALSE; GList *modules; GList *l; @@ -2439,11 +2457,8 @@ parse_include (GMarkupParseContext *context, } else { - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - "Module '%s' imported with conflicting versions '%s' and '%s'", - name, m->version, version); + g_printerr ("Module '%s' imported with conflicting versions '%s' and '%s'\n", + name, m->version, version); return FALSE; } } @@ -2454,10 +2469,7 @@ parse_include (GMarkupParseContext *context, if (girpath == NULL) { - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - "Could not find GIR file '%s'; check XDG_DATA_DIRS or use --includedir", + g_printerr ("Could not find GIR file '%s'; check XDG_DATA_DIRS or use --includedir\n", girname); g_free (girname); return FALSE; @@ -2466,22 +2478,31 @@ parse_include (GMarkupParseContext *context, g_debug ("Parsing include %s", girpath); - if (!g_file_get_contents (girpath, &buffer, &length, error)) + if (!g_file_get_contents (girpath, &buffer, &length, &error)) { + g_printerr ("%s: %s\n", girpath, error->message); + g_clear_error (&error); g_free (girpath); return FALSE; } - g_free (girpath); - modules = g_ir_parser_parse_string (ctx->parser, name, buffer, length, error); - success = error != NULL; + modules = g_ir_parser_parse_string (ctx->parser, name, girpath, buffer, length, &error); + g_free (buffer); + if (error != NULL) + { + int line_number, char_number; + g_markup_parse_context_get_position (context, &line_number, &char_number); + g_printerr ("%s:%d:%d: error: %s\n", girpath, line_number, char_number, error->message); + g_clear_error (&error); + g_free (girpath); + return FALSE; + } + g_free (girpath); ctx->include_modules = g_list_concat (ctx->include_modules, modules); - g_free (buffer); - - return success; + return TRUE; } extern GLogLevelFlags logged_levels; @@ -2515,6 +2536,12 @@ start_element_handler (GMarkupParseContext *context, g_string_free (tags, TRUE); } + if (ctx->state == STATE_PASSTHROUGH) + { + ctx->unknown_depth += 1; + return; + } + switch (element_name[0]) { case 'a': @@ -2614,8 +2641,16 @@ start_element_handler (GMarkupParseContext *context, break; } - if (!parse_include (context, ctx, name, version, error)) - break; + if (!parse_include (context, ctx, name, version)) + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "Failed to parse included gir %s-%s", + name, + version); + return; + } ctx->dependencies = g_list_prepend (ctx->dependencies, g_strdup_printf ("%s-%s", name, version)); @@ -2801,22 +2836,22 @@ start_element_handler (GMarkupParseContext *context, break; } - if (ctx->state != STATE_UNKNOWN) + if (ctx->state != STATE_PASSTHROUGH) { - state_switch (ctx, STATE_UNKNOWN); + g_markup_parse_context_get_position (context, &line_number, &char_number); + if (!g_str_has_prefix (element_name, "c:")) + g_printerr ("%s:%d:%d: warning: dropping to PASSTHROUGH\n", + ctx->file_path, line_number, char_number); + state_switch (ctx, STATE_PASSTHROUGH); ctx->unknown_depth = 1; } - else - { - ctx->unknown_depth += 1; - } out: if (*error) { g_markup_parse_context_get_position (context, &line_number, &char_number); - fprintf (stderr, "Error at line %d, character %d: %s\n", line_number, char_number, (*error)->message); + g_printerr ("%s:%d:%d: error: %s\n", ctx->file_path, line_number, char_number, (*error)->message); backtrace_stderr (); } } @@ -3189,7 +3224,7 @@ end_element_handler (GMarkupParseContext *context, } break; - case STATE_UNKNOWN: + case STATE_PASSTHROUGH: ctx->unknown_depth -= 1; if (ctx->unknown_depth == 0) state_switch (ctx, ctx->prev_state); @@ -3225,149 +3260,11 @@ cleanup (GMarkupParseContext *context, ctx->current_module = NULL; } -static GList * -post_filter_toplevel_varargs_functions (GList *list, - GList **varargs_callbacks_out) -{ - GList *iter; - GList *varargs_callbacks = *varargs_callbacks_out; - - iter = list; - while (iter) - { - GList *link = iter; - GIrNode *node = iter->data; - - iter = iter->next; - - if (node->type == G_IR_NODE_FUNCTION) - { - if (((GIrNodeFunction*)node)->is_varargs) - { - list = g_list_delete_link (list, link); - } - } - if (node->type == G_IR_NODE_CALLBACK) - { - if (((GIrNodeFunction*)node)->is_varargs) - { - varargs_callbacks = g_list_append (varargs_callbacks, - node); - list = g_list_delete_link (list, link); - } - } - } - - *varargs_callbacks_out = varargs_callbacks; - - return list; -} - -static GList * -post_filter_varargs_functions (GList *list, GList ** varargs_callbacks_out) -{ - GList *iter; - GList *varargs_callbacks; - - list = post_filter_toplevel_varargs_functions (list, varargs_callbacks_out); - - varargs_callbacks = *varargs_callbacks_out; - - iter = list; - while (iter) - { - GList *link = iter; - GIrNode *node = iter->data; - - iter = iter->next; - - if (node->type == G_IR_NODE_FUNCTION) - { - GList *param; - gboolean function_done = FALSE; - - for (param = ((GIrNodeFunction *)node)->parameters; - param; - param = param->next) - { - GIrNodeParam *node = (GIrNodeParam *)param->data; - - if (function_done) - break; - - if (node->type->is_interface) - { - GList *callback; - for (callback = varargs_callbacks; - callback; - callback = callback->next) - { - if (!strcmp (node->type->interface, - ((GIrNode *)varargs_callbacks->data)->name)) - { - list = g_list_delete_link (list, link); - function_done = TRUE; - break; - } - } - } - } - } - } - - *varargs_callbacks_out = varargs_callbacks; - - return list; -} - -static void -post_filter (GIrModule *module) -{ - GList *iter; - GList *varargs_callbacks = NULL; - - module->entries = post_filter_varargs_functions (module->entries, - &varargs_callbacks); - iter = module->entries; - while (iter) - { - GIrNode *node = iter->data; - - iter = iter->next; - - if (node->type == G_IR_NODE_OBJECT || - node->type == G_IR_NODE_INTERFACE) - { - GIrNodeInterface *iface = (GIrNodeInterface*)node; - iface->members = post_filter_varargs_functions (iface->members, - &varargs_callbacks); - } - else if (node->type == G_IR_NODE_BOXED) - { - GIrNodeBoxed *boxed = (GIrNodeBoxed*)node; - boxed->members = post_filter_varargs_functions (boxed->members, - &varargs_callbacks); - } - else if (node->type == G_IR_NODE_STRUCT) - { - GIrNodeStruct *iface = (GIrNodeStruct*)node; - iface->members = post_filter_varargs_functions (iface->members, - &varargs_callbacks); - } - else if (node->type == G_IR_NODE_UNION) - { - GIrNodeUnion *iface = (GIrNodeUnion*)node; - iface->members = post_filter_varargs_functions (iface->members, - &varargs_callbacks); - } - } - g_list_free (varargs_callbacks); -} - /** * g_ir_parser_parse_string: * @parser: a #GIrParser * @namespace: the namespace of the string + * @filename: (allow-none): Path to parsed file, or %NULL * @buffer: the data containing the XML * @length: length of the data * @error: return location for a #GError, or %NULL @@ -3381,6 +3278,7 @@ post_filter (GIrModule *module) GList * g_ir_parser_parse_string (GIrParser *parser, const gchar *namespace, + const gchar *filename, const gchar *buffer, gssize length, GError **error) @@ -3390,6 +3288,7 @@ g_ir_parser_parse_string (GIrParser *parser, ctx.parser = parser; ctx.state = STATE_START; + ctx.file_path = filename; ctx.namespace = namespace; ctx.include_modules = NULL; ctx.aliases = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); @@ -3457,7 +3356,6 @@ g_ir_parser_parse_file (GIrParser *parser, gchar *buffer; gsize length; GList *modules; - GList *iter; const char *slash; char *dash; char *namespace; @@ -3488,12 +3386,7 @@ g_ir_parser_parse_file (GIrParser *parser, if (!g_file_get_contents (filename, &buffer, &length, error)) return NULL; - modules = g_ir_parser_parse_string (parser, namespace, buffer, length, error); - - for (iter = modules; iter; iter = iter->next) - { - post_filter ((GIrModule*)iter->data); - } + modules = g_ir_parser_parse_string (parser, namespace, filename, buffer, length, error); g_free (namespace); diff --git a/girepository/girparser.h b/girepository/girparser.h index ac0d216b..6fca1b3d 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 0e9f112d..a70f2d8b 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 2dff4fe2..c8a81e89 100644 --- a/giscanner/girwriter.py +++ b/giscanner/girwriter.py @@ -96,8 +96,7 @@ and/or use gtk-doc annotations. ''') else: return cmp(a, b) for node in sorted(namespace.nodes, cmp=nscmp): - if not node.skip: - self._write_node(node) + self._write_node(node) def _write_node(self, node): if isinstance(node, Function): @@ -134,7 +133,9 @@ and/or use gtk-doc annotations. ''') for key, value in node.attributes: self.write_tag('attribute', [('name', key), ('value', value)]) - def _append_deprecated(self, node, attrs): + def _append_node_generic(self, node, attrs): + if node.skip or not node.introspectable: + attrs.append(('introspectable', '0')) if node.deprecated: attrs.append(('deprecated', node.deprecated)) if node.deprecated_version: @@ -152,14 +153,12 @@ and/or use gtk-doc annotations. ''') self.write_tag('alias', attrs) def _write_callable(self, callable, tag_name, extra_attrs): - if callable.skip: - return attrs = [('name', callable.name)] attrs.extend(extra_attrs) if callable.doc: attrs.append(('doc', callable.doc)) self._append_version(callable, attrs) - self._append_deprecated(callable, attrs) + self._append_node_generic(callable, attrs) self._append_throws(callable, attrs) with self.tagcontext(tag_name, attrs): self._write_attributes(callable) @@ -279,7 +278,7 @@ and/or use gtk-doc annotations. ''') if enum.doc: attrs.append(('doc', enum.doc)) self._append_version(enum, attrs) - self._append_deprecated(enum, attrs) + self._append_node_generic(enum, attrs) if isinstance(enum, GLibEnum): attrs.extend([('glib:type-name', enum.type_name), ('glib:get-type', enum.get_type), @@ -299,7 +298,7 @@ and/or use gtk-doc annotations. ''') if bitfield.doc: attrs.append(('doc', bitfield.doc)) self._append_version(bitfield, attrs) - self._append_deprecated(bitfield, attrs) + self._append_node_generic(bitfield, attrs) if isinstance(bitfield, GLibFlags): attrs.extend([('glib:type-name', bitfield.type_name), ('glib:get-type', bitfield.get_type), @@ -312,8 +311,6 @@ and/or use gtk-doc annotations. ''') self._write_member(member) def _write_member(self, member): - if member.skip: - return attrs = [('name', member.name), ('value', str(member.value)), ('c:identifier', member.symbol)] @@ -333,7 +330,7 @@ and/or use gtk-doc annotations. ''') if node.doc: attrs.append(('doc', node.doc)) self._append_version(node, attrs) - self._append_deprecated(node, attrs) + self._append_node_generic(node, attrs) if isinstance(node, Class): tag_name = 'class' if node.parent is not None: @@ -386,11 +383,9 @@ and/or use gtk-doc annotations. ''') self._write_method(method) def _write_property(self, prop): - if prop.skip: - return attrs = [('name', prop.name)] self._append_version(prop, attrs) - self._append_deprecated(prop, attrs) + self._append_node_generic(prop, attrs) # Properties are assumed to be readable (see also generate.c) if not prop.readable: attrs.append(('readable', '0')) @@ -440,7 +435,7 @@ and/or use gtk-doc annotations. ''') if record.doc: attrs.append(('doc', record.doc)) self._append_version(record, attrs) - self._append_deprecated(record, attrs) + self._append_node_generic(record, attrs) if isinstance(record, GLibBoxed): attrs.extend(self._boxed_attrs(record)) with self.tagcontext('record', attrs): @@ -462,7 +457,7 @@ and/or use gtk-doc annotations. ''') if union.doc: attrs.append(('doc', union.doc)) self._append_version(union, attrs) - self._append_deprecated(union, attrs) + self._append_node_generic(union, attrs) if isinstance(union, GLibBoxed): attrs.extend(self._boxed_attrs(union)) with self.tagcontext('union', attrs): @@ -508,13 +503,11 @@ and/or use gtk-doc annotations. ''') self._write_type(field.type) def _write_signal(self, signal): - if signal.skip: - return attrs = [('name', signal.name)] if signal.doc: attrs.append(('doc', signal.doc)) self._append_version(signal, attrs) - self._append_deprecated(signal, attrs) + self._append_node_generic(signal, attrs) with self.tagcontext('glib:signal', attrs): self._write_attributes(signal) self._write_return_type(signal.retval) diff --git a/giscanner/glibtransformer.py b/giscanner/glibtransformer.py index 42488251..192690ce 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 44c0287d..fef4d474 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('', "--Wall", + action="store_true", dest="warn_all", default=False, + help="If true, enable all warnings for introspection") + parser.add_option('', "--Werror", + action="store_true", dest="warn_fatal", + help="Turn warnings into fatal errors") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="be verbose") @@ -271,6 +277,8 @@ def scanner_main(args): transformer.set_strip_prefix(options.strip_prefix) else: transformer.set_strip_prefix(options.namespace_name) + if options.warn_all: + transformer.enable_warnings(True) transformer.set_include_paths(options.include_paths) shown_include_warning = False for include in options.includes: @@ -328,6 +336,11 @@ def scanner_main(args): except InvalidAnnotationError, e: raise SystemExit("ERROR in annotation: %s" % (str(e), )) + glibtransformer.final_analyze() + + if options.warn_fatal and transformer.did_warn(): + return 1 + # Write out AST if options.packages_export: exported_packages = options.packages_export diff --git a/giscanner/sourcescanner.py b/giscanner/sourcescanner.py index 7b06478d..acfc0485 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 fbc38d5b..01dfdeb6 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, string, file_positions=[], prefix=None): + """Log a warning, using optional file positioning information. +If the warning is related to a Node type, see _log_node_warning().""" + if not self._enable_warnings: + return + + if len(file_positions) == 0: + target_file_positions = [('', -1, -1)] + else: + target_file_positions = file_positions + + for (filename, line, column) in target_file_positions: + if filename.startswith(self.__cwd): + filename = filename[len(self.__cwd):] + if column != -1: + position = '%s:%d:%d' % (filename, line, column) + elif line != -1: + position = '%s:%d' % (filename, line, ) + else: + position = '%s:' % (filename, ) + + if prefix: + print >>sys.stderr, \ +'''%s: warning: ns=%r %s: %s''' % (position, self._namespace.name, + prefix, string) + else: + print >>sys.stderr, \ +'''%s: warning: ns=%r: %s''' % (position, self._namespace.name, string) + + def _log_symbol_warning(self, symbol, string): + """Log a warning in the context of the given symbol.""" + file_positions = [(symbol.source_filename, symbol.line, -1)] + prefix = "symbol=%r" % (symbol.ident, ) + self._log_warning(string, file_positions, prefix=prefix) + + def _log_node_warning(self, node, string, context=None): + """Log a warning, using information about file positions from +the given node. The optional context argument, if given, should be +another Node type which will also be displayed. If no file position +information is available from the node, the position data from the +context will be used.""" + if len(node.file_positions) == 0 and \ + (context is not None) and len(context.file_positions) > 0: + file_positions = context.file_positions + else: + file_positions = node.file_positions + + if context: + string = "context=%r %s" % (context.name, string) + + self._log_warning(string, file_positions) + def _find_include(self, include): searchdirs = self._includepaths[:] for path in _xdg_data_dirs: @@ -261,12 +322,15 @@ class Transformer(object): else: klass = Enum node = klass(enum_name, symbol.ident, members) + node.add_symbol_reference(symbol) self._names.type_names[symbol.ident] = (None, node) return node def _create_object(self, symbol): - return Member(symbol.ident, symbol.base_type.name, + node = Member(symbol.ident, symbol.base_type.name, symbol.ident) + node.add_symbol_reference(symbol) + return node def _type_is_callback(self, type): if isinstance(type, Callback): @@ -327,6 +391,7 @@ class Transformer(object): self._augment_callback_params(parameters) name = self._strip_namespace_func(symbol.ident) func = Function(name, return_, parameters, symbol.ident) + func.add_symbol_reference(symbol) return func def _create_source_type(self, source_type): @@ -386,6 +451,7 @@ class Transformer(object): # (except for Objects, see also glibtransformer.py) node = Field(symbol.ident, ftype, ftype.name, readable=True, writable=True, bits=symbol.const_int) + node.add_symbol_reference(symbol) return node def _create_typedef(self, symbol): @@ -523,11 +589,13 @@ class Transformer(object): raise AssertionError() const = Constant(name, type_name, value) + const.add_symbol_reference(symbol) return const def _create_typedef_struct(self, symbol, disguised=False): name = self.remove_prefix(symbol.ident) struct = Struct(name, symbol.ident, disguised) + struct.add_symbol_reference(symbol) self._typedefs_ns[symbol.ident] = struct self._create_struct(symbol) return struct @@ -535,6 +603,7 @@ class Transformer(object): def _create_typedef_union(self, symbol): name = self.remove_prefix(symbol.ident) union = Union(name, symbol.ident) + union.add_symbol_reference(symbol) self._typedefs_ns[symbol.ident] = union self._create_union(symbol) return union @@ -570,6 +639,7 @@ class Transformer(object): if field: compound.fields.append(field) + compound.add_symbol_reference(symbol) return compound def _create_struct(self, symbol, anonymous=False): @@ -593,6 +663,7 @@ class Transformer(object): else: name = self.remove_prefix(symbol.ident) callback = Callback(name, retval, parameters, symbol.ident) + callback.add_symbol_reference(symbol) return callback diff --git a/tests/scanner/Makefile.am b/tests/scanner/Makefile.am index 483e5417..b156b446 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 += --Wall --Werror + # 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 eee3c643..e1e6cf86 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."> - + @@ -449,6 +451,14 @@ uses a C sugar return type."> + + + + + + + + + @@ -697,7 +715,9 @@ uses a C sugar return type."> - + @@ -797,6 +817,20 @@ uses a C sugar return type."> + + + + + + + + + + @@ -885,7 +919,8 @@ uses a C sugar return type."> + c:identifier="foo_test_varargs_callback" + introspectable="0"> @@ -899,7 +934,8 @@ uses a C sugar return type."> + c:identifier="foo_test_varargs_callback2" + introspectable="0"> @@ -910,7 +946,8 @@ uses a C sugar return type."> + c:identifier="foo_test_varargs_callback3" + introspectable="0"> -- cgit v1.2.1