[gnome-builder] clang: Implement IdeCodeIndexer



commit bd27c6ef9f4c527f2db714fd987999e1a5e746ea
Author: Anoop Chandu <anoopchandu96 gmail com>
Date:   Sat Aug 26 20:06:33 2017 +0530

    clang: Implement IdeCodeIndexer
    
    IdeClangCodeIndexer implements IdeCodeIndexer. On request to
    index file this will return a GListModel, a list of
    IdeCodeIndexEntries, backed by Translation unit. On request to
    get key it will return USR of symbol refereced at given location.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=786700

 plugins/clang/ide-clang-code-indexer.c     |  255 ++++++++++++++++++++++++++++
 plugins/clang/ide-clang-code-indexer.h     |   32 ++++
 plugins/clang/ide-clang-translation-unit.c |   61 +++++++-
 plugins/clang/ide-clang-translation-unit.h |    3 +-
 4 files changed, 347 insertions(+), 4 deletions(-)
---
diff --git a/plugins/clang/ide-clang-code-indexer.c b/plugins/clang/ide-clang-code-indexer.c
new file mode 100644
index 0000000..7962cb4
--- /dev/null
+++ b/plugins/clang/ide-clang-code-indexer.c
@@ -0,0 +1,255 @@
+/* ide-clang-code-indexer.c
+ *
+ * Copyright (C) 2017 Anoop Chandu <anoopchandu96 gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-clang-code-indexer"
+
+#include <clang-c/Index.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
+{
+  GObject                    parent;
+
+  CXIndex                    index;
+
+  gchar                    **build_flags;
+};
+
+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)
+{
+  IdeConfigurationManager *manager;
+  IdeConfiguration *config;
+  IdeContext *context;
+  const gchar *cflags;
+  const gchar *cxxflags;
+  gchar **argv = NULL;
+
+  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");
+
+  if (cflags && *cflags)
+    g_shell_parse_argv (cflags, NULL, &argv, NULL);
+
+  if ((!argv || !*argv) && cxxflags && *cxxflags)
+    g_shell_parse_argv (cxxflags, NULL, &argv, NULL);
+
+  if (argv == NULL)
+    argv = g_new0 (gchar*, 1);
+
+  return argv;
+}
+
+/* This will return a IdeCodeIndexEntries backed by translation unit of file. */
+static IdeCodeIndexEntries *
+ide_clang_code_indexer_index_file (IdeCodeIndexer      *indexer,
+                                   GFile               *file,
+                                   gchar              **args,
+                                   GCancellable        *cancellable,
+                                   GError             **error)
+{
+  IdeClangCodeIndexer *self = (IdeClangCodeIndexer *)indexer;
+  g_autoptr(GTask) task = NULL;
+  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);
+
+  task = g_task_new (self, cancellable, NULL, NULL);
+
+  filename = g_file_get_path (file);
+
+  g_debug ("Indexing %s", filename);
+
+  if (args == NULL)
+    {
+      if (self->build_flags == NULL)
+        self->build_flags = ide_clang_code_indexer_get_default_build_flags (self);
+
+      args  = self->build_flags;
+    }
+
+  while (args [n_args] != NULL)
+    n_args++;
+
+  if (CXError_Success == clang_parseTranslationUnit2 (self->index,
+                                                      filename,
+                                                      (const char * const *)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);
+
+      g_task_return_pointer (task, g_steal_pointer (&entries), g_object_unref);
+    }
+  else
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_FAILED,
+                               "Unable to create translation unit");
+    }
+
+  return g_task_propagate_pointer (task, error);
+}
+
+static void
+ide_clang_code_indexer_generate_key_cb (GObject       *object,
+                                        GAsyncResult  *result,
+                                        gpointer       user_data)
+{
+  IdeClangService *service = (IdeClangService *)object;
+  g_autoptr(IdeClangTranslationUnit) unit = NULL;
+  g_autoptr(GTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+  g_autofree gchar *key;
+  IdeSourceLocation *location;
+
+  g_assert (IDE_IS_CLANG_SERVICE (service));
+  g_assert (G_IS_TASK (task));
+
+  unit = ide_clang_service_get_translation_unit_finish (service, result, &error);
+
+  if (unit == NULL)
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  location = g_task_get_task_data (task);
+
+  g_clear_error (&error);
+
+  key = ide_clang_translation_unit_generate_key (unit, location);
+
+  if (key == NULL)
+    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,
+                                           GCancellable         *cancellable,
+                                           GAsyncReadyCallback   callback,
+                                           gpointer              user_data)
+{
+  IdeClangCodeIndexer *self = (IdeClangCodeIndexer *)indexer;
+  IdeContext *context;
+  IdeClangService *service;
+  g_autoptr(GTask) task = NULL;
+
+  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));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+
+  g_task_set_task_data (task,
+                        ide_source_location_ref (location),
+                        (GDestroyNotify)ide_source_location_unref);
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  service = ide_context_get_service_typed (context, IDE_TYPE_CLANG_SERVICE);
+
+  if (g_task_return_error_if_cancelled (task))
+    return;
+
+  ide_clang_service_get_translation_unit_async (service,
+                                                ide_source_location_get_file (location),
+                                                0,
+                                                cancellable,
+                                                ide_clang_code_indexer_generate_key_cb,
+                                                g_steal_pointer (&task));
+}
+
+static gchar *
+ide_clang_code_indexer_generate_key_finish (IdeCodeIndexer  *self,
+                                            GAsyncResult    *result,
+                                            GError         **error)
+{
+  GTask *task = (GTask *)result;
+
+  g_return_val_if_fail (G_IS_TASK (result), NULL);
+
+  return g_task_propagate_pointer (task, error);
+}
+
+static void
+ide_clang_code_indexer_finalize (GObject *object)
+{
+  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)->finalize (object);
+}
+
+static void
+ide_clang_code_indexer_class_init (IdeClangCodeIndexerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = ide_clang_code_indexer_finalize;
+}
+
+static void
+code_indexer_iface_init (IdeCodeIndexerInterface *iface)
+{
+  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/plugins/clang/ide-clang-code-indexer.h b/plugins/clang/ide-clang-code-indexer.h
new file mode 100644
index 0000000..003f859
--- /dev/null
+++ b/plugins/clang/ide-clang-code-indexer.h
@@ -0,0 +1,32 @@
+/* ide-clang-code-indexer.h
+ *
+ * Copyright (C) 2017 Anoop Chandu <anoopchandu96 gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_CLANG_CODE_INDEXER_H
+#define IDE_CLANG_CODE_INDEXER_H
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#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)
+
+G_END_DECLS
+
+#endif /* IDE_CLANG_CODE_INDEXER_H */
\ No newline at end of file
diff --git a/plugins/clang/ide-clang-translation-unit.c b/plugins/clang/ide-clang-translation-unit.c
index 222010d..6addc7e 100644
--- a/plugins/clang/ide-clang-translation-unit.c
+++ b/plugins/clang/ide-clang-translation-unit.c
@@ -942,7 +942,11 @@ ide_clang_translation_unit_lookup_symbol (IdeClangTranslationUnit  *self,
   if (clang_Cursor_isNull (cursor))
     IDE_RETURN (NULL);
 
-  tmpcursor = clang_getCursorReferenced (cursor);
+  tmpcursor = clang_getCursorDefinition (cursor);
+
+  if (clang_Cursor_isNull (tmpcursor))
+    tmpcursor = clang_getCursorReferenced (cursor);
+
   if (!clang_Cursor_isNull (tmpcursor))
     {
       CXSourceLocation tmploc;
@@ -950,7 +954,11 @@ ide_clang_translation_unit_lookup_symbol (IdeClangTranslationUnit  *self,
 
       cxrange = clang_getCursorExtent (tmpcursor);
       tmploc = clang_getRangeStart (cxrange);
-      definition = create_location (self, project, workpath, tmploc);
+
+      if (clang_isCursorDefinition (tmpcursor))
+        definition = create_location (self, project, workpath, tmploc);
+      else
+        declaration = create_location (self, project, workpath, tmploc);
     }
 
   symkind = get_symbol_kind (cursor, &symflags);
@@ -975,7 +983,7 @@ ide_clang_translation_unit_lookup_symbol (IdeClangTranslationUnit  *self,
                                NULL);
 
           g_clear_pointer (&definition, ide_symbol_unref);
-          definition = ide_source_location_new (file, 0, 0, 0);
+          declaration = ide_source_location_new (file, 0, 0, 0);
 
           g_clear_object (&file);
           g_clear_object (&gfile);
@@ -1294,3 +1302,50 @@ ide_clang_translation_unit_find_nearest_scope (IdeClangTranslationUnit  *self,
 
   IDE_RETURN (ret);
 }
+
+gchar *
+ide_clang_translation_unit_generate_key (IdeClangTranslationUnit  *self,
+                                         IdeSourceLocation        *location)
+{
+  CXTranslationUnit unit;
+  CXFile file;
+  CXSourceLocation cx_location;
+  CXCursor reference;
+  CXCursor declaration;
+  CXString cx_usr;
+  const gchar *usr;
+  g_autofree gchar *ret = NULL;
+  guint line = 0;
+  guint column = 0;
+  enum CXLinkageKind linkage;
+
+  g_return_val_if_fail (IDE_IS_CLANG_TRANSLATION_UNIT (self), NULL);
+
+  unit = ide_ref_ptr_get (self->native);
+
+  file = get_file_for_location (self, location);
+  line = ide_source_location_get_line (location);
+  column = ide_source_location_get_line_offset (location);
+
+  cx_location = clang_getLocation (unit, file, line + 1, column + 1);
+
+  reference = clang_getCursor (unit, cx_location);
+  declaration = clang_getCursorReferenced (reference);
+  cx_usr = clang_getCursorUSR (declaration);
+
+  linkage = clang_getCursorLinkage (declaration);
+
+  if (linkage == CXLinkage_Internal || linkage == CXLinkage_NoLinkage)
+    return NULL;
+
+  usr = clang_getCString (cx_usr);
+
+  if (usr == NULL)
+    return NULL;
+
+  ret = g_strdup (usr);
+
+  clang_disposeString (cx_usr);
+
+  return g_steal_pointer (&ret);
+}
diff --git a/plugins/clang/ide-clang-translation-unit.h b/plugins/clang/ide-clang-translation-unit.h
index 47663b2..96569ad 100644
--- a/plugins/clang/ide-clang-translation-unit.h
+++ b/plugins/clang/ide-clang-translation-unit.h
@@ -58,7 +58,8 @@ GPtrArray         *ide_clang_translation_unit_get_symbols              (IdeClang
 IdeSymbol         *ide_clang_translation_unit_find_nearest_scope       (IdeClangTranslationUnit  *self,
                                                                         IdeSourceLocation        *location,
                                                                         GError                  **error);
-
+gchar            *ide_clang_translation_unit_generate_key              (IdeClangTranslationUnit  *self,
+                                                                        IdeSourceLocation        *location);
 G_END_DECLS
 
 #endif /* IDE_CLANG_TRANSLATION_UNIT_H */


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