[gnome-builder/wip/slaf/xml-pack: 244/254] xml-pack: handling of partial nodes
- From: Sébastien Lafargue <slafargue src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/slaf/xml-pack: 244/254] xml-pack: handling of partial nodes
- Date: Thu, 13 Jul 2017 09:09:43 +0000 (UTC)
commit e244b9d564f01594001b6033bc4302e6b052dbc8
Author: Sebastien Lafargue <slafargue gnome org>
Date: Tue Jun 27 23:44:10 2017 +0200
xml-pack: handling of partial nodes
plugins/xml-pack/ide-xml-parser-private.h | 2 +
plugins/xml-pack/ide-xml-parser.c | 84 ++++++++++++++++++++++++++---
plugins/xml-pack/ide-xml-sax.c | 59 +++++++++++++++++---
plugins/xml-pack/ide-xml-sax.h | 3 +
4 files changed, 131 insertions(+), 17 deletions(-)
---
diff --git a/plugins/xml-pack/ide-xml-parser-private.h b/plugins/xml-pack/ide-xml-parser-private.h
index d93eadb..d48589a 100644
--- a/plugins/xml-pack/ide-xml-parser-private.h
+++ b/plugins/xml-pack/ide-xml-parser-private.h
@@ -76,6 +76,8 @@ typedef struct _ParserState
gint current_depth;
GPtrArray *schemas;
gint64 sequence;
+
+ guint error_missing_tag_end : 1;
} ParserState;
void ide_xml_parser_set_post_processing_callback (IdeXmlParser *self,
diff --git a/plugins/xml-pack/ide-xml-parser.c b/plugins/xml-pack/ide-xml-parser.c
index a0662fb..11c8f7b 100644
--- a/plugins/xml-pack/ide-xml-parser.c
+++ b/plugins/xml-pack/ide-xml-parser.c
@@ -19,6 +19,8 @@
#include <glib/gi18n.h>
#include <glib-object.h>
+#include <libxml/xmlerror.h>
+
#include "ide-xml-parser.h"
#include "ide-xml-parser-generic.h"
#include "ide-xml-parser-ui.h"
@@ -182,6 +184,7 @@ ide_xml_parser_state_processing (IdeXmlParser *self,
IdeXmlSymbolNode *parent_node;
G_GNUC_UNUSED IdeXmlSymbolNode *popped_node;
g_autofree gchar *popped_element_name = NULL;
+ const gchar *erroneous_element_name;
const gchar *content;
gint start_line;
gint start_line_offset;
@@ -198,9 +201,28 @@ ide_xml_parser_state_processing (IdeXmlParser *self,
return;
}
+ if (state->error_missing_tag_end)
+ {
+ erroneous_element_name = ide_xml_symbol_node_get_element_name (state->parent_node);
+ /* TODO: we need better node comparaison (ns) here */
+ if (!ide_str_equal0 (erroneous_element_name, element_name))
+ {
+ if (ide_xml_stack_is_empty (self->stack))
+ goto error;
+
+ popped_node = ide_xml_stack_pop (self->stack, &popped_element_name, &parent_node, &depth);
+ ide_xml_symbol_node_set_state (popped_node, IDE_XML_SYMBOL_NODE_STATE_NOT_CLOSED);
+ g_clear_pointer (&popped_element_name, g_free);
+
+ state->parent_node = parent_node;
+ g_assert (state->parent_node != NULL);
+ }
+ }
+
depth = ide_xml_sax_get_depth (self->sax_parser);
ide_xml_sax_get_location (self->sax_parser, &start_line, &start_line_offset, &end_line, &end_line_offset,
&content, &size);
+ /* No node mean not created by one of the specific parser */
if (node == NULL)
{
if (callback_type == IDE_XML_SAX_CALLBACK_TYPE_START_ELEMENT)
@@ -223,10 +245,7 @@ ide_xml_parser_state_processing (IdeXmlParser *self,
while (TRUE)
{
if (ide_xml_stack_is_empty (self->stack))
- {
- g_warning ("Xml nodes stack empty\n");
- return;
- }
+ goto error;
popped_node = ide_xml_stack_pop (self->stack, &popped_element_name, &parent_node, &depth);
if (ide_str_equal0 (popped_element_name, element_name))
@@ -245,6 +264,8 @@ ide_xml_parser_state_processing (IdeXmlParser *self,
state->current_depth = depth;
state->current_node = node;
+ state->error_missing_tag_end = FALSE;
+
return;
}
@@ -279,10 +300,7 @@ ide_xml_parser_state_processing (IdeXmlParser *self,
{
/* TODO: compare current with popped */
if (ide_xml_stack_is_empty (self->stack))
- {
- g_warning ("Xml nodes stack empty\n");
- return;
- }
+ goto error;
popped_node = ide_xml_stack_pop (self->stack, &popped_element_name, &parent_node, &depth);
state->parent_node = parent_node;
@@ -293,6 +311,13 @@ ide_xml_parser_state_processing (IdeXmlParser *self,
state->current_depth = depth;
state->current_node = node;
+ state->error_missing_tag_end = FALSE;
+
+ return;
+
+error:
+ g_warning ("Xml nodes stack empty\n");
+ return;
}
void
@@ -336,6 +361,10 @@ ide_xml_parser_error_sax_cb (ParserState *state,
{
IdeXmlParser *self = (IdeXmlParser *)state->self;
IdeDiagnostic *diagnostic;
+ xmlParserCtxt *context;
+ xmlError *error;
+ const gchar *base;
+ const gchar *current;
g_autofree gchar *msg = NULL;
va_list var_args;
@@ -347,6 +376,45 @@ ide_xml_parser_error_sax_cb (ParserState *state,
diagnostic = ide_xml_parser_create_diagnostic (state, msg, IDE_DIAGNOSTIC_ERROR);
g_ptr_array_add (state->diagnostics_array, diagnostic);
+
+ context = ide_xml_sax_get_context (self->sax_parser);
+ base = (const gchar *)context->input->base;
+ current = (const gchar *)context->input->cur;
+ error = xmlCtxtGetLastError (context);
+ if (error != NULL && error->domain == XML_FROM_PARSER)
+ {
+ if (error->code == XML_ERR_GT_REQUIRED)
+ {
+ /* If a tag is not closed, we want the following nodes to be siblings, not children */
+ state->error_missing_tag_end = TRUE;
+ }
+ else if (error->code == XML_ERR_NAME_REQUIRED && context->instate == XML_PARSER_CONTENT)
+ {
+ const gchar *prev;
+ IdeXmlSymbolNode *node;
+ gint start_line, start_line_offset;
+ gint end_line, end_line_offset;
+ gsize size;
+
+ prev = current - 1;
+ if (prev >= base && *prev == '<')
+ {
+ /* '<' only case, no name tag, node not created, we need to do it ourself */
+ node = ide_xml_symbol_node_new ("internal", NULL, NULL, IDE_SYMBOL_XML_ELEMENT);
+ ide_xml_symbol_node_set_state (node, IDE_XML_SYMBOL_NODE_STATE_NOT_CLOSED);
+ ide_xml_symbol_node_take_internal_child (state->parent_node, node);
+
+ ide_xml_sax_get_location (self->sax_parser,
+ &start_line, &start_line_offset,
+ &end_line, &end_line_offset,
+ NULL, &size);
+ ide_xml_symbol_node_set_location (node, g_object_ref (state->file),
+ start_line, start_line_offset,
+ end_line, end_line_offset,
+ size);
+ }
+ }
+ }
}
void
diff --git a/plugins/xml-pack/ide-xml-sax.c b/plugins/xml-pack/ide-xml-sax.c
index 22194f1..728cc8a 100644
--- a/plugins/xml-pack/ide-xml-sax.c
+++ b/plugins/xml-pack/ide-xml-sax.c
@@ -18,7 +18,7 @@
#include <glib/gi18n.h>
#include <string.h>
-#include <libxml/parser.h>
+
#include <libxml/parserInternals.h>
#include "ide-xml-sax.h"
@@ -184,6 +184,7 @@ static void
get_tag_location (IdeXmlSax *self,
gint *line,
gint *line_offset,
+ gint *end_line,
gint *end_line_offset,
const gchar **content,
gsize *size)
@@ -203,6 +204,8 @@ get_tag_location (IdeXmlSax *self,
g_assert (IDE_IS_XML_SAX (self));
g_assert (line != NULL);
g_assert (line_offset != NULL);
+ g_assert (end_line != NULL);
+ g_assert (end_line_offset != NULL);
g_assert (content != NULL);
g_assert (size != NULL);
@@ -211,13 +214,45 @@ get_tag_location (IdeXmlSax *self,
input = self->context->input;
base = (const gchar *)input->base;
current = (const gchar *)input->cur;
- end_line_number = start_line_number = xmlSAX2GetLineNumber (self->context);
+ *end_line = end_line_number = start_line_number = xmlSAX2GetLineNumber (self->context);
- /* Adjust the element size, can be a start, a end or an auto-closed one */
- if (g_utf8_get_char (current) != '>')
+ /* Adjust the element size, can be a start, a end or an auto-closed one */
+ ch = g_utf8_get_char (current);
+ if (ch != '>')
{
+ /* Not properly closed tag */
+ if (ch == '<' || ch == 0)
+ {
+ ch = g_utf8_get_char (--current);
+ if (ch == '<')
+ {
+ /* Empty node */
+ *line = *end_line = end_line_number;
+ *line_offset = *end_line_offset = xmlSAX2GetColumnNumber (self->context);
+ return;
+ }
+ else
+ {
+ while (current >= base)
+ {
+ if (ch == '\n')
+ --end_line_number;
+
+ if (!g_unichar_isspace(ch))
+ break;
+
+ current = g_utf8_prev_char (current);
+ ch = g_utf8_get_char (current);
+ }
+
+ end_current = current;
+ *end_line = start_line_number = end_line_number;
+ size_offset = 0;
+ goto next;
+ }
+ }
/* Auto-closed start element case */
- if (g_utf8_get_char (current) == '/' && g_utf8_get_char (current + 1) == '>')
+ else if (ch == '/' && g_utf8_get_char (current + 1) == '>')
{
++current;
size_offset = 2;
@@ -241,6 +276,7 @@ get_tag_location (IdeXmlSax *self,
return;
}
+next:
while (current > base)
{
ch = g_utf8_get_char (current);
@@ -302,7 +338,7 @@ ide_xml_sax_get_location (IdeXmlSax *self,
g_return_val_if_fail (IDE_IS_XML_SAX (self), FALSE);
g_return_val_if_fail (self->context != NULL, FALSE);
- get_tag_location (self, &tmp_line, &tmp_line_offset, &tmp_end_line_offset, &tmp_content, &tmp_size);
+ get_tag_location (self, &tmp_line, &tmp_line_offset, &tmp_end_line, &tmp_end_line_offset, &tmp_content,
&tmp_size);
if (start_line != NULL)
*start_line = tmp_line;
@@ -316,9 +352,6 @@ ide_xml_sax_get_location (IdeXmlSax *self,
if (size != NULL)
*size = tmp_size;
- tmp_end_line = xmlSAX2GetLineNumber (self->context);
- //tmp_end_line_offset = xmlSAX2GetColumnNumber (self->context);
-
if (end_line != NULL)
*end_line = tmp_end_line;
@@ -337,3 +370,11 @@ ide_xml_sax_get_depth (IdeXmlSax *self)
return self->context->nameNr;
}
+xmlParserCtxt *
+ide_xml_sax_get_context (IdeXmlSax *self)
+{
+ g_return_val_if_fail (IDE_IS_XML_SAX (self), NULL);
+
+ return self->context;
+}
+
diff --git a/plugins/xml-pack/ide-xml-sax.h b/plugins/xml-pack/ide-xml-sax.h
index ae64076..8b4b4fc 100644
--- a/plugins/xml-pack/ide-xml-sax.h
+++ b/plugins/xml-pack/ide-xml-sax.h
@@ -21,6 +21,8 @@
#include <glib-object.h>
+#include <libxml/parser.h>
+
G_BEGIN_DECLS
#define IDE_TYPE_XML_SAX (ide_xml_sax_get_type())
@@ -48,6 +50,7 @@ enum _IdeXmlSaxCallbackType {
};
void ide_xml_sax_clear (IdeXmlSax *self);
+xmlParserCtxt *ide_xml_sax_get_context (IdeXmlSax *self);
gint ide_xml_sax_get_depth (IdeXmlSax *self);
gboolean ide_xml_sax_get_location (IdeXmlSax *self,
gint *start_line,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]