[gnome-builder] clang: port clang indexer to new async API



commit e7766058d10d03745f1b8db2461520a4491fd936
Author: Christian Hergert <chergert redhat com>
Date:   Wed Jan 17 17:28:19 2018 -0800

    clang: port clang indexer to new async API
    
    This removes the "threaded" usage of IdeCodeIndexer and moves to
    our new async/finish API.
    
    It also creates a new CXIndex for each file, so we can more
    reliably release memory after each parse. It probably means we
    have to index some data more, but since this is a background
    operation, I'd prefer to keep the memory usage lower at any
    given time.

 src/plugins/clang/ide-clang-code-index-entries.c | 464 +++++++++++------------
 src/plugins/clang/ide-clang-code-index-entries.h |   5 +-
 src/plugins/clang/ide-clang-code-indexer.c       | 245 ++++++------
 src/plugins/clang/ide-clang-code-indexer.h       |   2 +-
 4 files changed, 343 insertions(+), 373 deletions(-)
---
diff --git a/src/plugins/clang/ide-clang-code-index-entries.c 
b/src/plugins/clang/ide-clang-code-index-entries.c
index cfbbfbcd5..6043c84b5 100644
--- a/src/plugins/clang/ide-clang-code-index-entries.c
+++ b/src/plugins/clang/ide-clang-code-index-entries.c
@@ -27,78 +27,168 @@
   */
 struct _IdeClangCodeIndexEntries
 {
-  GObject                 parent;
+  GObject parent;
 
-  CXTranslationUnit       tu;
+  /*
+   * This is the index that was used to parse the translation unit. We are
+   * responsible for disposing the index when finalizing.
+   */
+  CXIndex index;
 
-  GQueue                  cursors;
-  GQueue                  decl_cursors;
+  /*
+   * The unit that was parsed by the indexer. We traverse this to locate
+   * items within the file that are indexable. We also own the reference
+   * and must clang_disposeIndex() when finalizing.
+   */
+  CXTranslationUnit unit;
 
-  gchar                  *main_file;
-};
+  /*
+   * Queue of cursors as we iterate through the translation unit. These are
+   * GSlice allocated structures holding the raw CXCursor from the
+   * translation unit. Since we own the unit/index, these are safe for the
+   * lifetime of the object.
+   */
+  GQueue cursors;
+  GQueue decl_cursors;
 
-enum {
-  PROP_0,
-  PROP_MAIN_FILE,
-  PROP_UNIT,
-  N_PROPS
+  /* Path to the file that has been parsed. */
+  gchar *path;
 };
 
-static GParamSpec *properties [N_PROPS];
+static void
+cx_cursor_free (CXCursor *cursor)
+{
+  g_slice_free (CXCursor, cursor);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (CXCursor, cx_cursor_free)
 
-static void index_entries_iface_init (IdeCodeIndexEntriesInterface *iface);
+static IdeSymbolKind
+translate_kind (enum CXCursorKind cursor_kind)
+{
+  switch ((int)cursor_kind)
+    {
+    case CXCursor_StructDecl:
+      return IDE_SYMBOL_STRUCT;
 
-G_DEFINE_TYPE_EXTENDED (IdeClangCodeIndexEntries, ide_clang_code_index_entries, G_TYPE_OBJECT, 0,
-                        G_IMPLEMENT_INTERFACE (IDE_TYPE_CODE_INDEX_ENTRIES, index_entries_iface_init))
+    case CXCursor_UnionDecl:
+      return IDE_SYMBOL_UNION;
 
+    case CXCursor_ClassDecl:
+      return IDE_SYMBOL_CLASS;
 
-static void
-cx_cursor_free (CXCursor *cursor)
+    case CXCursor_EnumDecl:
+      return IDE_SYMBOL_ENUM;
+
+    case CXCursor_FieldDecl:
+      return IDE_SYMBOL_FIELD;
+
+    case CXCursor_EnumConstantDecl:
+      return IDE_SYMBOL_ENUM_VALUE;
+
+    case CXCursor_FunctionDecl:
+      return IDE_SYMBOL_FUNCTION;
+
+    case CXCursor_CXXMethod:
+      return IDE_SYMBOL_METHOD;
+
+    case CXCursor_VarDecl:
+    case CXCursor_ParmDecl:
+      return IDE_SYMBOL_VARIABLE;
+
+    case CXCursor_TypedefDecl:
+    case CXCursor_NamespaceAlias:
+    case CXCursor_TypeAliasDecl:
+      return IDE_SYMBOL_ALIAS;
+
+    case CXCursor_Namespace:
+      return IDE_SYMBOL_NAMESPACE;
+
+    case CXCursor_FunctionTemplate:
+    case CXCursor_ClassTemplate:
+      return IDE_SYMBOL_TEMPLATE;
+
+    case CXCursor_MacroDefinition:
+      return IDE_SYMBOL_MACRO;
+
+    default:
+      return IDE_SYMBOL_NONE;
+    }
+}
+
+static const gchar *
+get_symbol_prefix (IdeSymbolKind kind)
 {
-  g_slice_free (CXCursor, cursor);
+  switch ((int)kind)
+    {
+    case IDE_SYMBOL_FUNCTION:
+      return "f\x1F";
+
+    case IDE_SYMBOL_STRUCT:
+      return "s\x1F";
+
+    case IDE_SYMBOL_VARIABLE:
+      return "v\x1F";
+
+    case IDE_SYMBOL_UNION:
+      return "u\x1F";
+
+    case IDE_SYMBOL_ENUM:
+      return "e\x1F";
+
+    case IDE_SYMBOL_CLASS:
+      return "c\x1F";
+
+    case IDE_SYMBOL_ENUM_VALUE:
+      return "a\x1F";
+
+    case IDE_SYMBOL_MACRO:
+      return "m\x1F";
+
+    default:
+      return "x\x1F";
+    }
 }
 
-/*
- * Visit all children of a node and push those into cursors queue.
- * push declaration cursor into decl_cursors queue only if its from the main file.
- */
 static enum CXChildVisitResult
 visitor (CXCursor     cursor,
          CXCursor     parent,
          CXClientData client_data)
 {
   IdeClangCodeIndexEntries *self = client_data;
-  enum CXCursorKind cursor_kind;
+  g_autoptr(CXCursor) child_cursor = NULL;
+  g_auto(CXString) cxpath = {0};
   CXSourceLocation location;
+  const char *path;
   CXFile file;
-  g_auto(CXString) cx_file_name = {0};
-  const char *file_name;
-  CXCursor *child_cursor;
 
+  g_assert (IDE_IS_CLANG_CODE_INDEX_ENTRIES (self));
   g_assert (!clang_Cursor_isNull (cursor));
 
-  child_cursor = g_slice_new (CXCursor);
-  *child_cursor = cursor;
+  /*
+   * Visit all children of a node and push those into cursors queue. Push
+   * declaration cursor into decl_cursors queue only if its from the main
+   * file.
+   */
+
+  child_cursor = g_slice_dup (CXCursor, &cursor);
   g_queue_push_tail (&self->cursors, child_cursor);
 
   location = clang_getCursorLocation (cursor);
-
   clang_getSpellingLocation (location, &file, NULL, NULL, NULL);
 
-  cx_file_name = clang_getFileName (file);
-  file_name = clang_getCString (cx_file_name);
+  cxpath = clang_getFileName (file);
+  path = clang_getCString (cxpath);
 
-  cursor_kind = clang_getCursorKind (cursor);
-
-  if (!g_strcmp0 (file_name, self->main_file))
+  if (dzl_str_equal0 (path, self->path))
     {
+      enum CXCursorKind cursor_kind = clang_getCursorKind (cursor);
+
       if ((cursor_kind >= CXCursor_StructDecl && cursor_kind <= CXCursor_Namespace) ||
           (cursor_kind >= CXCursor_Constructor && cursor_kind <= CXCursor_NamespaceAlias) ||
           cursor_kind == CXCursor_TypeAliasDecl ||
           cursor_kind == CXCursor_MacroDefinition)
-        {
-          g_queue_push_tail (&self->decl_cursors, child_cursor);
-        }
+        g_queue_push_tail (&self->decl_cursors, child_cursor);
     }
 
   /* TODO: Record MACRO EXPANSION FOR G_DEFINE_TYPE, G_DECLARE_TYPE */
@@ -107,78 +197,80 @@ visitor (CXCursor     cursor,
 }
 
 /*
- * decl_cursors store declarations to be returned by this class. If decl_cursors
- * is not empty then this function returns a declaration popped from queue,
- * else this will do Breadth first traversal on AST till it finds a declaration.
- * On next request when decl_cursors is empty it will continue traversal
- * from where it has stopped in previously.
+ * decl_cursors store declarations to be returned by this class. If
+ * decl_cursors is not empty then this function returns a declaration popped
+ * from queue, else this will do Breadth first traversal on AST till it
+ * finds a declaration.  On next request when decl_cursors is empty it will
+ * continue traversal from where it has stopped in previously.
  */
 static IdeCodeIndexEntry *
 ide_clang_code_index_entries_real_get_next_entry (IdeClangCodeIndexEntries *self,
                                                   gboolean                 *finish)
 {
+  g_autoptr(CXCursor) cursor = NULL;
+  g_autofree gchar *name = NULL;
+  g_auto(CXString) cxname = {0};
+  g_auto(CXString) usr = {0};
   CXSourceLocation location;
+  IdeSymbolFlags flags = IDE_SYMBOL_FLAGS_NONE;
+  IdeSymbolKind kind = IDE_SYMBOL_NONE;
+  enum CXLinkageKind linkage;
+  enum CXCursorKind cursor_kind;
+  const gchar *cname = NULL;
+  const gchar *prefix = NULL;
+  const gchar *key = NULL;
   guint line = 0;
   guint column = 0;
   guint offset = 0;
-  enum CXLinkageKind linkage;
-  g_auto(CXString) cx_name = {0};
-  const gchar *cname = NULL;
-  gchar *prefix = NULL;
-  g_autofree gchar *name = NULL;
-  g_autofree gchar *key = NULL;
-  IdeSymbolKind kind = IDE_SYMBOL_NONE;
-  IdeSymbolFlags flags = IDE_SYMBOL_FLAGS_NONE;
-  CXCursor *cursor = NULL;
-  enum CXCursorKind cursor_kind;
 
   g_assert (IDE_IS_CLANG_CODE_INDEX_ENTRIES (self));
   g_assert (finish != NULL);
 
   *finish = FALSE;
+
   /* First declaration missing */
   /* Traverse AST till atleast one declaration is found */
+
   while (g_queue_is_empty (&self->decl_cursors))
     {
+      g_autoptr(CXCursor) decl_cursor = NULL;
+
       if (g_queue_is_empty (&self->cursors))
         {
-          clang_disposeTranslationUnit (self->tu);
-          self->tu = NULL;
           *finish = TRUE;
           return NULL;
         }
 
-      cursor = g_queue_pop_head (&self->cursors);
-
-      /* Resume visiting children.*/
-      clang_visitChildren (*cursor, visitor, self);
-      g_slice_free (CXCursor, cursor);
+      decl_cursor = g_queue_pop_head (&self->cursors);
+      clang_visitChildren (*decl_cursor, visitor, self);
     }
 
-  cursor = g_queue_pop_head (&self->decl_cursors);
+  g_assert (!g_queue_is_empty (&self->decl_cursors));
 
+  cursor = g_queue_pop_head (&self->decl_cursors);
   location = clang_getCursorLocation (*cursor);
   clang_getSpellingLocation (location, NULL, &line, &column, &offset);
 
-  cx_name = clang_getCursorSpelling (*cursor);
-  cname = clang_getCString (cx_name);
-
-  if ((cname == NULL) || (cname[0] == '\0'))
+  /* Skip this item if its NULL, we'll get called again to fetch
+   * the next item. One possible chance for improvement here is
+   * to jump to the next item instead of returning here.
+   */
+  cxname = clang_getCursorSpelling (*cursor);
+  cname = clang_getCString (cxname);
+  if (dzl_str_empty0 (cname))
     return NULL;
 
-  cursor_kind = clang_getCursorKind (*cursor);
-
   /*
-   * If current cursor is a type alias then resolve actual type of this recursively
-   * by resolving parent type.
+   * If current cursor is a type alias then resolve actual type of this
+   * recursively by resolving parent type.
    */
+  cursor_kind = clang_getCursorKind (*cursor);
   if ((cursor_kind == CXCursor_TypedefDecl) ||
-     (cursor_kind == CXCursor_NamespaceAlias) || (cursor_kind == CXCursor_TypeAliasDecl))
+     (cursor_kind == CXCursor_NamespaceAlias) ||
+     (cursor_kind == CXCursor_TypeAliasDecl))
     {
-      CXType type;
       CXCursor temp = *cursor;
-
-      type = clang_getTypedefDeclUnderlyingType (temp);
+      CXType type = clang_getTypedefDeclUnderlyingType (temp);
 
       while (CXType_Invalid != type.kind)
         {
@@ -189,98 +281,22 @@ ide_clang_code_index_entries_real_get_next_entry (IdeClangCodeIndexEntries *self
       cursor_kind = clang_getCursorKind (temp);
     }
 
-  /* Translate CXCursorKind to IdeSymbolKind */
-  switch ((int)cursor_kind)
-    {
-    case CXCursor_StructDecl:
-      kind = IDE_SYMBOL_STRUCT;
-      break;
-    case CXCursor_UnionDecl:
-      kind = IDE_SYMBOL_UNION;
-      break;
-    case CXCursor_ClassDecl:
-      kind = IDE_SYMBOL_CLASS;
-      break;
-    case CXCursor_EnumDecl:
-      kind = IDE_SYMBOL_ENUM;
-      break;
-    case CXCursor_FieldDecl:
-      kind = IDE_SYMBOL_FIELD;
-      break;
-    case CXCursor_EnumConstantDecl:
-      kind = IDE_SYMBOL_ENUM_VALUE;
-      break;
-    case CXCursor_FunctionDecl:
-      kind = IDE_SYMBOL_FUNCTION;
-      break;
-    case CXCursor_CXXMethod:
-      kind = IDE_SYMBOL_METHOD;
-      break;
-    case CXCursor_VarDecl:
-    case CXCursor_ParmDecl:
-      kind = IDE_SYMBOL_VARIABLE;
-      break;
-    case CXCursor_TypedefDecl:
-    case CXCursor_NamespaceAlias:
-    case CXCursor_TypeAliasDecl:
-      kind = IDE_SYMBOL_ALIAS;
-      break;
-    case CXCursor_Namespace:
-      kind = IDE_SYMBOL_NAMESPACE;
-      break;
-    case CXCursor_FunctionTemplate:
-    case CXCursor_ClassTemplate:
-      kind = IDE_SYMBOL_TEMPLATE;
-      break;
-    case CXCursor_MacroDefinition:
-      kind = IDE_SYMBOL_MACRO;
-      break;
-    default:
-      kind = IDE_SYMBOL_NONE;
-      break;
-    }
-
-  /* Add prefix to name so that filters can be applied */
-  if (kind == IDE_SYMBOL_FUNCTION)
-    prefix = "f\x1F";
-  else if (kind == IDE_SYMBOL_STRUCT)
-    prefix = "s\x1F";
-  else if (kind == IDE_SYMBOL_VARIABLE)
-    prefix = "v\x1F";
-  else if (kind == IDE_SYMBOL_UNION)
-    prefix = "u\x1F";
-  else if (kind == IDE_SYMBOL_ENUM)
-    prefix = "e\x1F";
-  else if (kind == IDE_SYMBOL_CLASS)
-    prefix = "c\x1F";
-  else if (kind == IDE_SYMBOL_ENUM_VALUE)
-    prefix = "a\x1F";
-  else if (kind == IDE_SYMBOL_MACRO)
-    prefix = "m\x1F";
-  else
-    prefix = "x\x1F";
-
+  kind = translate_kind (cursor_kind);
+  prefix = get_symbol_prefix (kind);
   name = g_strconcat (prefix, cname, NULL);
 
   if (clang_isCursorDefinition (*cursor))
     flags |= IDE_SYMBOL_FLAGS_IS_DEFINITION;
 
   linkage = clang_getCursorLinkage (*cursor);
-
   if (linkage == CXLinkage_Internal)
-    {
-      flags |= IDE_SYMBOL_FLAGS_IS_STATIC;
-    }
+    flags |= IDE_SYMBOL_FLAGS_IS_STATIC;
   else if (linkage == CXLinkage_NoLinkage)
-    {
-      flags |= IDE_SYMBOL_FLAGS_IS_MEMBER;
-    }
+    flags |= IDE_SYMBOL_FLAGS_IS_MEMBER;
   else
     {
-      g_auto(CXString) usr = {0};
-
       usr = clang_getCursorUSR (*cursor);
-      key = g_strdup (clang_getCString (usr));
+      key = clang_getCString (usr);
     }
 
   return g_object_new (IDE_TYPE_CODE_INDEX_ENTRY,
@@ -293,7 +309,6 @@ ide_clang_code_index_entries_real_get_next_entry (IdeClangCodeIndexEntries *self
                        NULL);
 }
 
-/* Retrives next IdeCodeIndexEntry. */
 static IdeCodeIndexEntry *
 ide_clang_code_index_entries_get_next_entry (IdeCodeIndexEntries *entries)
 {
@@ -301,15 +316,27 @@ ide_clang_code_index_entries_get_next_entry (IdeCodeIndexEntries *entries)
   g_autoptr(IdeCodeIndexEntry) entry = NULL;
   gboolean finish = FALSE;
 
+  g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (IDE_IS_CLANG_CODE_INDEX_ENTRIES (self));
 
-  entry = ide_clang_code_index_entries_real_get_next_entry (self, &finish);
-  while (entry == NULL && !finish)
+  do
     entry = ide_clang_code_index_entries_real_get_next_entry (self, &finish);
+  while (entry == NULL && finish == FALSE);
+
+  g_assert (entry == NULL || IDE_IS_CODE_INDEX_ENTRY (entry));
 
   return g_steal_pointer (&entry);
 }
 
+static void
+index_entries_iface_init (IdeCodeIndexEntriesInterface *iface)
+{
+  iface->get_next_entry = ide_clang_code_index_entries_get_next_entry;
+}
+
+G_DEFINE_TYPE_WITH_CODE (IdeClangCodeIndexEntries, ide_clang_code_index_entries, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_CODE_INDEX_ENTRIES, index_entries_iface_init))
+
 static void
 ide_clang_code_index_entries_finalize (GObject *object)
 {
@@ -321,98 +348,18 @@ ide_clang_code_index_entries_finalize (GObject *object)
   g_queue_foreach (&self->cursors, (GFunc)cx_cursor_free, NULL);
   g_queue_clear (&self->cursors);
 
-  if (self->tu != NULL)
-    {
-      clang_disposeTranslationUnit (self->tu);
-      self->tu = NULL;
-    }
+  g_clear_pointer (&self->unit, clang_disposeTranslationUnit);
+  g_clear_pointer (&self->index, clang_disposeIndex);
 
   G_OBJECT_CLASS(ide_clang_code_index_entries_parent_class)->finalize (object);
 }
 
-static void
-ide_clang_code_index_entries_constructed (GObject *object)
-{
-  IdeClangCodeIndexEntries *self = (IdeClangCodeIndexEntries *)object;
-  CXCursor root_cursor;
-
-  G_OBJECT_CLASS (ide_clang_code_index_entries_parent_class)->constructed (object);
-
-  root_cursor = clang_getTranslationUnitCursor (self->tu);
-  g_queue_push_head (&self->cursors, g_slice_dup (CXCursor, &root_cursor));
-}
-
-static void
-ide_clang_code_index_entries_set_property (GObject       *object,
-                                           guint          prop_id,
-                                           const GValue  *value,
-                                           GParamSpec    *pspec)
-{
-  IdeClangCodeIndexEntries *self = (IdeClangCodeIndexEntries *)object;
-
-  switch (prop_id)
-    {
-    case PROP_MAIN_FILE:
-      self->main_file = g_strdup ((gchar *)g_value_get_pointer (value));
-      break;
-    case PROP_UNIT:
-      self->tu = g_value_get_pointer (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
-}
-
-static void
-ide_clang_code_index_entries_get_property (GObject    *object,
-                                           guint       prop_id,
-                                           GValue     *value,
-                                           GParamSpec *pspec)
-{
-  IdeClangCodeIndexEntries *self = (IdeClangCodeIndexEntries *)object;
-
-  switch (prop_id)
-    {
-    case PROP_MAIN_FILE:
-      g_value_set_pointer (value, self->main_file);
-      break;
-    case PROP_UNIT:
-      g_value_set_pointer (value, &self->tu);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
-}
-
 static void
 ide_clang_code_index_entries_class_init (IdeClangCodeIndexEntriesClass *klass)
 {
   GObjectClass *object_class = (GObjectClass *)klass;
 
   object_class->finalize = ide_clang_code_index_entries_finalize;
-  object_class->constructed = ide_clang_code_index_entries_constructed;
-  object_class->set_property = ide_clang_code_index_entries_set_property;
-  object_class->get_property = ide_clang_code_index_entries_get_property;
-
-  properties [PROP_MAIN_FILE] =
-    g_param_spec_pointer ("main-file",
-                          "Main File",
-                          "Name of file from which TU is parsed.",
-                          G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-  properties [PROP_UNIT] =
-    g_param_spec_pointer ("unit",
-                          "Unit",
-                          "Translation Unit from which index entries are to be generated",
-                          G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-  g_object_class_install_properties (object_class, N_PROPS, properties);
-}
-
-static void
-index_entries_iface_init (IdeCodeIndexEntriesInterface *iface)
-{
-  iface->get_next_entry = ide_clang_code_index_entries_get_next_entry;
 }
 
 static void
@@ -420,15 +367,40 @@ ide_clang_code_index_entries_init (IdeClangCodeIndexEntries *self)
 {
 }
 
+/**
+ * ide_clang_code_index_entries_new:
+ * @index: (transfer full): a #CXIndex to take ownership of
+ * @unit: (transfer full): a #CXTranslationUnit to take ownership of
+ * @path: the path of the file that was indexed
+ *
+ * Creates a new #IdeClangCodeIndexEntries that can be used to iterate
+ * the translation unit for interesting data.
+ *
+ * Returns: (transfer full): a new #IdeClangCodeIndexEntries
+ *
+ * Thread safety: this object may be created from any thread, but the
+ *   ide_clang_code_index_entries_get_next_entry() may only be called
+ *   from the main thread, as required by the base interface.
+ */
 IdeClangCodeIndexEntries *
-ide_clang_code_index_entries_new (CXTranslationUnit  unit,
-                                  const gchar       *main_file)
+ide_clang_code_index_entries_new (CXIndex            index,
+                                  CXTranslationUnit  unit,
+                                  const gchar       *path)
 {
-  g_return_val_if_fail ((unit != NULL), NULL);
-  g_return_val_if_fail ((main_file != NULL), NULL);
+  IdeClangCodeIndexEntries *self;
+  CXCursor root;
 
-  return g_object_new (IDE_TYPE_CLANG_CODE_INDEX_ENTRIES,
-                       "unit", unit,
-                       "main-file", main_file,
-                       NULL);
+  g_return_val_if_fail (index != NULL, NULL);
+  g_return_val_if_fail (unit != NULL, NULL);
+  g_return_val_if_fail (path != NULL, NULL);
+
+  self = g_object_new (IDE_TYPE_CLANG_CODE_INDEX_ENTRIES, NULL);
+  self->index = index;
+  self->unit = unit;
+  self->path = g_strdup (path);
+
+  root = clang_getTranslationUnitCursor (unit);
+  g_queue_push_head (&self->cursors, g_slice_dup (CXCursor, &root));
+
+  return self;
 }
diff --git a/src/plugins/clang/ide-clang-code-index-entries.h 
b/src/plugins/clang/ide-clang-code-index-entries.h
index 042cb49f5..48efd59e5 100644
--- a/src/plugins/clang/ide-clang-code-index-entries.h
+++ b/src/plugins/clang/ide-clang-code-index-entries.h
@@ -23,11 +23,12 @@
 
 G_BEGIN_DECLS
 
-#define IDE_TYPE_CLANG_CODE_INDEX_ENTRIES (ide_clang_code_index_entries_get_type ())
+#define IDE_TYPE_CLANG_CODE_INDEX_ENTRIES (ide_clang_code_index_entries_get_type())
 
 G_DECLARE_FINAL_TYPE (IdeClangCodeIndexEntries, ide_clang_code_index_entries, IDE, CLANG_CODE_INDEX_ENTRIES, 
GObject)
 
-IdeClangCodeIndexEntries *ide_clang_code_index_entries_new (CXTranslationUnit  tu,
+IdeClangCodeIndexEntries *ide_clang_code_index_entries_new (CXIndex            index,
+                                                            CXTranslationUnit  unit,
                                                             const gchar       *source_filename);
 
 G_END_DECLS
diff --git a/src/plugins/clang/ide-clang-code-indexer.c b/src/plugins/clang/ide-clang-code-indexer.c
index 5a304b606..1fe3f3273 100644
--- a/src/plugins/clang/ide-clang-code-indexer.c
+++ b/src/plugins/clang/ide-clang-code-indexer.c
@@ -20,117 +20,125 @@
 
 #include <clang-c/Index.h>
 
+#include "ide-clang-code-index-entries.h"
+#include "ide-clang-code-indexer.h"
+#include "ide-clang-private.h"
 #include "ide-clang-service.h"
 #include "ide-clang-translation-unit.h"
-#include "ide-clang-code-indexer.h"
-#include "ide-clang-code-index-entries.h"
 
-/*
- * This class will index a file and returns IdeCodeIndexEntries using which index entries
- * can be retrieved one by one.It will be backed by TU of the file.
- */
-
-struct _IdeClangCodeIndexer
+typedef struct
 {
-  GObject                    parent;
-
-  CXIndex                    index;
-
-  gchar                    **build_flags;
-};
+  GFile  *file;
+  gchar **build_flags;
+} BuildRequest;
 
-static void code_indexer_iface_init (IdeCodeIndexerInterface *iface);
-
-G_DEFINE_TYPE_EXTENDED (IdeClangCodeIndexer, ide_clang_code_indexer, IDE_TYPE_OBJECT, 0,
-                        G_IMPLEMENT_INTERFACE (IDE_TYPE_CODE_INDEXER, code_indexer_iface_init))
-
-static gchar **
-ide_clang_code_indexer_get_default_build_flags (IdeClangCodeIndexer *self)
+static void
+build_request_free (gpointer data)
 {
-  IdeConfigurationManager *manager;
-  IdeConfiguration *config;
-  IdeContext *context;
-  const gchar *cflags;
-  const gchar *cxxflags;
-  gchar **argv = NULL;
+  BuildRequest *br = data;
 
-  g_assert (IDE_IS_CLANG_CODE_INDEXER (self));
-
-  context = ide_object_get_context (IDE_OBJECT (self));
-  manager = ide_context_get_configuration_manager (context);
-  config = ide_configuration_manager_get_current (manager);
-  cflags = ide_configuration_getenv (config, "CFLAGS");
-  cxxflags = ide_configuration_getenv (config, "CXXFLAGS");
+  g_clear_object (&br->file);
+  g_clear_pointer (&br->build_flags, g_strfreev);
+  g_slice_free (BuildRequest, br);
+}
 
-  if (cflags && *cflags)
-    g_shell_parse_argv (cflags, NULL, &argv, NULL);
+static void
+ide_clang_code_indexer_index_file_worker (GTask        *task,
+                                          gpointer      source_object,
+                                          gpointer      task_data,
+                                          GCancellable *cancellable)
+{
+  BuildRequest *br = task_data;
+  g_autoptr(IdeClangCodeIndexEntries) entries = NULL;
+  g_auto(CXTranslationUnit) unit = NULL;
+  g_auto(CXIndex) index = NULL;
+  g_autofree gchar *path = NULL;
+  enum CXErrorCode code;
 
-  if ((!argv || !*argv) && cxxflags && *cxxflags)
-    g_shell_parse_argv (cxxflags, NULL, &argv, NULL);
+  g_assert (G_IS_TASK (task));
+  g_assert (IDE_IS_CLANG_CODE_INDEXER (source_object));
+  g_assert (br != NULL);
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  path = g_file_get_path (br->file);
+  index = clang_createIndex (0, 0);
+  code = clang_parseTranslationUnit2 (index,
+                                      path,
+                                      (const char * const *)br->build_flags,
+                                      g_strv_length (br->build_flags),
+                                      NULL,
+                                      0,
+                                      (CXTranslationUnit_SingleFileParse |
+                                       CXTranslationUnit_KeepGoing |
+                                       CXTranslationUnit_DetailedPreprocessingRecord |
+                                       CXTranslationUnit_SkipFunctionBodies),
+                                      &unit);
+
+  if (code != CXError_Success)
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_FAILED,
+                               "Failed to index \"%s\"",
+                               path);
+      return;
+    }
 
-  if (argv == NULL)
-    argv = g_new0 (gchar*, 1);
+  entries = ide_clang_code_index_entries_new (g_steal_pointer (&index),
+                                              g_steal_pointer (&unit),
+                                              path);
 
-  return argv;
+  g_task_return_pointer (task, g_steal_pointer (&entries), g_object_unref);
 }
 
-/* This will return a IdeCodeIndexEntries backed by translation unit of file. */
-static IdeCodeIndexEntries *
-ide_clang_code_indexer_index_file (IdeCodeIndexer       *indexer,
-                                   GFile                *file,
-                                   const gchar * const  *args,
-                                   GCancellable         *cancellable,
-                                   GError              **error)
+static void
+ide_clang_code_indexer_index_file_async (IdeCodeIndexer      *indexer,
+                                         GFile               *file,
+                                         const gchar * const *args,
+                                         GCancellable        *cancellable,
+                                         GAsyncReadyCallback  callback,
+                                         gpointer             user_data)
 {
   IdeClangCodeIndexer *self = (IdeClangCodeIndexer *)indexer;
-  g_autofree gchar *filename = NULL;
-  CXTranslationUnit tu;
-  guint n_args = 0;
-
-  g_return_val_if_fail (IDE_IS_CLANG_CODE_INDEXER (self), NULL);
-  g_return_val_if_fail (G_IS_FILE (file), NULL);
-  g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
+  g_autoptr(GTask) task = NULL;
+  BuildRequest *br;
 
-  filename = g_file_get_path (file);
+  g_assert (IDE_IS_CLANG_CODE_INDEXER (self));
+  g_assert (G_IS_FILE (file));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  g_debug ("Indexing %s", filename);
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, ide_clang_code_indexer_index_file_async);
+  g_task_set_priority (task, G_PRIORITY_LOW);
 
-  if (args == NULL)
+  if (!g_file_is_native (file))
     {
-      if (self->build_flags == NULL)
-        self->build_flags = ide_clang_code_indexer_get_default_build_flags (self);
-      args = (const gchar * const *)self->build_flags;
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_NOT_SUPPORTED,
+                               "Only native files are supported");
+      return;
     }
 
-  while (args [n_args] != NULL)
-    n_args++;
-
-  if (CXError_Success == clang_parseTranslationUnit2 (self->index,
-                                                      filename,
-                                                      args,
-                                                      n_args,
-                                                      NULL,
-                                                      0,
-                                                      CXTranslationUnit_DetailedPreprocessingRecord,
-                                                      &tu))
-    {
-      g_autoptr(IdeClangCodeIndexEntries) entries = NULL;
-
-      /* entries has to dispose TU when done with it */
-      entries = ide_clang_code_index_entries_new (tu, filename);
+  br = g_slice_new0 (BuildRequest);
+  br->build_flags = g_strdupv ((gchar **)args);
+  br->file = g_object_ref (file);
+  g_task_set_task_data (task, br, build_request_free);
 
-      if (entries != NULL)
-        return g_steal_pointer (&entries);
-
-      clang_disposeTranslationUnit (tu);
-    }
+  ide_thread_pool_push_task (IDE_THREAD_POOL_INDEXER,
+                             task,
+                             ide_clang_code_indexer_index_file_worker);
+}
 
-  g_set_error (error,
-               G_IO_ERROR,
-               G_IO_ERROR_FAILED,
-               "Unable to create translation unit");
+static IdeCodeIndexEntries *
+ide_clang_code_indexer_index_file_finish (IdeCodeIndexer  *indexer,
+                                          GAsyncResult    *result,
+                                          GError         **error)
+{
+  g_assert (IDE_IS_CLANG_CODE_INDEXER (indexer));
+  g_assert (G_IS_TASK (result));
 
-  return NULL;
+  return g_task_propagate_pointer (G_TASK (result), error);
 }
 
 static void
@@ -146,29 +154,24 @@ ide_clang_code_indexer_generate_key_cb (GObject       *object,
   IdeSourceLocation *location;
 
   g_assert (IDE_IS_CLANG_SERVICE (service));
+  g_assert (G_IS_ASYNC_RESULT (result));
   g_assert (G_IS_TASK (task));
 
-  unit = ide_clang_service_get_translation_unit_finish (service, result, &error);
-
-  if (unit == NULL)
+  if (!(unit = ide_clang_service_get_translation_unit_finish (service, result, &error)))
     {
       g_task_return_error (task, g_steal_pointer (&error));
       return;
     }
 
   location = g_task_get_task_data (task);
+  g_assert (location != NULL);
 
-  g_clear_error (&error);
-
-  key = ide_clang_translation_unit_generate_key (unit, location);
-
-  if (key == NULL)
+  if (!(key = ide_clang_translation_unit_generate_key (unit, location)))
     g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Key not found");
   else
     g_task_return_pointer (task, g_steal_pointer (&key), g_free);
 }
 
-/* This will get USR of declaration referneced at location by using IdeClangTranslationUnit.*/
 static void
 ide_clang_code_indexer_generate_key_async (IdeCodeIndexer       *indexer,
                                            IdeSourceLocation    *location,
@@ -177,14 +180,19 @@ ide_clang_code_indexer_generate_key_async (IdeCodeIndexer       *indexer,
                                            gpointer              user_data)
 {
   IdeClangCodeIndexer *self = (IdeClangCodeIndexer *)indexer;
-  IdeContext *context;
-  IdeClangService *service;
   g_autoptr(GTask) task = NULL;
+  IdeClangService *service;
+  IdeContext *context;
 
   g_return_if_fail (IDE_IS_CLANG_CODE_INDEXER (self));
   g_return_if_fail (location != NULL);
   g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
+  /*
+   * The key to generate is what clang calls a "USR". That is a stable key that
+   * can be referenced across compilation units.
+   */
+
   task = g_task_new (self, cancellable, callback, user_data);
   g_task_set_source_tag (task, ide_clang_code_indexer_generate_key_async);
   g_task_set_priority (task, G_PRIORITY_LOW);
@@ -194,10 +202,10 @@ ide_clang_code_indexer_generate_key_async (IdeCodeIndexer       *indexer,
                         (GDestroyNotify)ide_source_location_unref);
 
   context = ide_object_get_context (IDE_OBJECT (self));
-  service = ide_context_get_service_typed (context, IDE_TYPE_CLANG_SERVICE);
+  g_assert (IDE_IS_CONTEXT (context));
 
-  if (g_task_return_error_if_cancelled (task))
-    return;
+  service = ide_context_get_service_typed (context, IDE_TYPE_CLANG_SERVICE);
+  g_assert (IDE_IS_CLANG_SERVICE (service));
 
   ide_clang_service_get_translation_unit_async (service,
                                                 ide_source_location_get_file (location),
@@ -212,43 +220,32 @@ ide_clang_code_indexer_generate_key_finish (IdeCodeIndexer  *self,
                                             GAsyncResult    *result,
                                             GError         **error)
 {
-  GTask *task = (GTask *)result;
+  g_assert (IDE_IS_CODE_INDEXER (self));
+  g_assert (G_IS_TASK (result));
 
-  g_return_val_if_fail (G_IS_TASK (result), NULL);
-
-  return g_task_propagate_pointer (task, error);
+  return g_task_propagate_pointer (G_TASK (result), error);
 }
 
 static void
-ide_clang_code_indexer_dispose (GObject *object)
+code_indexer_iface_init (IdeCodeIndexerInterface *iface)
 {
-  IdeClangCodeIndexer *self = (IdeClangCodeIndexer *)object;
-
-  g_clear_pointer (&self->index, clang_disposeIndex);
-  g_clear_pointer (&self->build_flags, g_strfreev);
-
-  G_OBJECT_CLASS (ide_clang_code_indexer_parent_class)->dispose (object);
+  iface->index_file_async = ide_clang_code_indexer_index_file_async;
+  iface->index_file_finish = ide_clang_code_indexer_index_file_finish;
+  iface->generate_key_async = ide_clang_code_indexer_generate_key_async;
+  iface->generate_key_finish = ide_clang_code_indexer_generate_key_finish;
 }
 
-static void
-ide_clang_code_indexer_class_init (IdeClangCodeIndexerClass *klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+struct _IdeClangCodeIndexer { IdeObject parent; };
 
-  object_class->dispose = ide_clang_code_indexer_dispose;
-}
+G_DEFINE_TYPE_WITH_CODE (IdeClangCodeIndexer, ide_clang_code_indexer, IDE_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_CODE_INDEXER, code_indexer_iface_init))
 
 static void
-code_indexer_iface_init (IdeCodeIndexerInterface *iface)
+ide_clang_code_indexer_class_init (IdeClangCodeIndexerClass *klass)
 {
-  iface->index_file = ide_clang_code_indexer_index_file;
-  iface->generate_key_async = ide_clang_code_indexer_generate_key_async;
-  iface->generate_key_finish = ide_clang_code_indexer_generate_key_finish;
 }
 
-
 static void
 ide_clang_code_indexer_init (IdeClangCodeIndexer *self)
 {
-  self->index = clang_createIndex (0, 0);
 }
diff --git a/src/plugins/clang/ide-clang-code-indexer.h b/src/plugins/clang/ide-clang-code-indexer.h
index cb2905b34..94cc3d086 100644
--- a/src/plugins/clang/ide-clang-code-indexer.h
+++ b/src/plugins/clang/ide-clang-code-indexer.h
@@ -22,7 +22,7 @@
 
 G_BEGIN_DECLS
 
-#define IDE_TYPE_CLANG_CODE_INDEXER (ide_clang_code_indexer_get_type ())
+#define IDE_TYPE_CLANG_CODE_INDEXER (ide_clang_code_indexer_get_type())
 
 G_DECLARE_FINAL_TYPE (IdeClangCodeIndexer, ide_clang_code_indexer, IDE, CLANG_CODE_INDEXER, IdeObject)
 


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