[gnome-builder/wip/slaf/xml-pack: 43/56] xml-pack: handling of partial nodes



commit 6bd4591ae74c7ed297a9f29dbadfc07e69e493fd
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]