Commit bd27c6ef authored by Anoop Chandu's avatar Anoop Chandu Committed by Christian Hergert
Browse files

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
parent 73c8e7e6
/* 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);
}
/* 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
......@@ -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);
}
......@@ -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 */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment