[gnome-builder] compile-commands: locate information on Vala files
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] compile-commands: locate information on Vala files
- Date: Tue, 17 Oct 2017 08:35:30 +0000 (UTC)
commit ab6844f2299e2e7ec2ff522bd98197f72169cdce
Author: Christian Hergert <chergert redhat com>
Date: Tue Oct 17 01:33:44 2017 -0700
compile-commands: locate information on Vala files
We need some special fallback code when dealing with Vala and
how some build systems create compile_commands.json. In
particular, Meson only generates a single .vala command and we
won't be able to look it up by directly by file.
src/libide/buildsystem/ide-compile-commands.c | 150 +++++++++++++++++++++++--
src/tests/data/test-ide-compile-commands.json | 5 +
src/tests/test-ide-compile-commands.c | 12 ++
3 files changed, 155 insertions(+), 12 deletions(-)
---
diff --git a/src/libide/buildsystem/ide-compile-commands.c b/src/libide/buildsystem/ide-compile-commands.c
index c3a96f2..e55e6f8 100644
--- a/src/libide/buildsystem/ide-compile-commands.c
+++ b/src/libide/buildsystem/ide-compile-commands.c
@@ -22,6 +22,7 @@
#include <string.h>
#include "ide-debug.h"
+#include "ide-macros.h"
#include "buildsystem/ide-compile-commands.h"
@@ -49,9 +50,30 @@
struct _IdeCompileCommands
{
- GObject parent_instance;
+ GObject parent_instance;
+
+ /*
+ * The info_by_file field contains a hsahtable whose keys are GFile
+ * matching the file that is to be compiled. It contains as a value
+ * the CompileInfo struct describing how to compile that file.
+ */
GHashTable *info_by_file;
- guint has_loaded : 1;
+
+ /*
+ * The vala_info field contains an array of every vala like file we've
+ * discovered while parsing the database. This is used so because some
+ * compile_commands.json only have a single valac command which wont
+ * match the file we want to lookup (Notably Meson-based).
+ */
+ GPtrArray *vala_info;
+
+ /*
+ * The has_loaded field determines if we've had a load (async or sync
+ * variant) operation called. We can only do this safely once because
+ * we assign state in the task worker. Callers must discard the object
+ * if the load operation fails.
+ */
+ guint has_loaded : 1;
};
typedef struct
@@ -83,6 +105,7 @@ ide_compile_commands_finalize (GObject *object)
IdeCompileCommands *self = (IdeCompileCommands *)object;
g_clear_pointer (&self->info_by_file, g_hash_table_unref);
+ g_clear_pointer (&self->vala_info, g_ptr_array_unref);
G_OBJECT_CLASS (ide_compile_commands_parent_class)->finalize (object);
}
@@ -128,6 +151,7 @@ ide_compile_commands_load_worker (GTask *task,
g_autoptr(GError) error = NULL;
g_autoptr(GHashTable) info_by_file = NULL;
g_autoptr(GHashTable) directories_by_path = NULL;
+ g_autoptr(GPtrArray) vala_info = NULL;
g_autofree gchar *contents = NULL;
JsonNode *root;
JsonArray *ar;
@@ -171,6 +195,8 @@ ide_compile_commands_load_worker (GTask *task,
NULL,
g_object_unref);
+ vala_info = g_ptr_array_new_with_free_func (compile_info_free);
+
n_items = json_array_get_length (ar);
for (guint i = 0; i < n_items; i++)
@@ -224,11 +250,26 @@ ide_compile_commands_load_worker (GTask *task,
info->file = g_file_resolve_relative_path (dir, file);
info->directory = g_object_ref (dir);
info->command = g_strdup (command);
-
g_hash_table_insert (info_by_file, info->file, info);
+
+ /*
+ * We might need to keep a special copy of this for resolving .vala
+ * builds which won't be able ot be matched based on the filename. We
+ * keep all of them around right now in case we want to later on find
+ * the closest match based on directory.
+ */
+ if (g_str_has_suffix (file, ".vala"))
+ {
+ info = g_slice_new (CompileInfo);
+ info->file = g_file_resolve_relative_path (dir, file);
+ info->directory = g_object_ref (dir);
+ info->command = g_strdup (command);
+ g_ptr_array_add (vala_info, info);
+ }
}
self->info_by_file = g_steal_pointer (&info_by_file);
+ self->vala_info = g_steal_pointer (&vala_info);
g_task_return_boolean (task, TRUE);
@@ -417,6 +458,9 @@ ide_compile_commands_filter_c (IdeCompileCommands *self,
g_assert (info != NULL);
g_assert (argv != NULL);
+ if (*argv == NULL)
+ return;
+
ar = g_ptr_array_new ();
for (guint i = 0; (*argv)[i] != NULL; i++)
@@ -466,12 +510,67 @@ ide_compile_commands_filter_c (IdeCompileCommands *self,
static void
ide_compile_commands_filter_vala (IdeCompileCommands *self,
+ const CompileInfo *info,
gchar ***argv)
{
+ GPtrArray *ar;
+
g_assert (IDE_IS_COMPILE_COMMANDS (self));
+ g_assert (info != NULL);
g_assert (argv != NULL);
- /* TODO: Filter Vala Commands */
+ if (*argv == NULL)
+ return;
+
+ ar = g_ptr_array_new ();
+
+ for (guint i = 0; (*argv)[i] != NULL; i++)
+ {
+ const gchar *param = (*argv)[i];
+ const gchar *next = (*argv)[i+1];
+
+ if (g_str_has_prefix (param, "--pkg=") ||
+ g_str_has_prefix (param, "--target-glib=") ||
+ !!strstr (param, ".vapi"))
+ {
+ g_ptr_array_add (ar, g_strdup (param));
+ }
+ else if (g_str_has_prefix (param, "--vapidir=") ||
+ g_str_has_prefix (param, "--girdir=") ||
+ g_str_has_prefix (param, "--metadatadir="))
+ {
+ g_autofree gchar *resolved = NULL;
+ gchar *eq = strchr (param, '=');
+
+ next = eq + 1;
+ *eq = '\0';
+
+ resolved = ide_compile_commands_resolve (self, info, next);
+ g_ptr_array_add (ar, g_strdup_printf ("%s=%s", param, resolved));
+ }
+ else if (next != NULL &&
+ (g_str_has_prefix (param, "--pkg") ||
+ g_str_has_prefix (param, "--target-glib")))
+ {
+ g_ptr_array_add (ar, g_strdup (param));
+ g_ptr_array_add (ar, g_strdup (next));
+ i++;
+ }
+ else if (next != NULL &&
+ (g_str_has_prefix (param, "--vapidir") ||
+ g_str_has_prefix (param, "--girdir") ||
+ g_str_has_prefix (param, "--metadatadir")))
+ {
+ g_ptr_array_add (ar, g_strdup (param));
+ g_ptr_array_add (ar, ide_compile_commands_resolve (self, info, next));
+ i++;
+ }
+ }
+
+ g_free (*argv);
+
+ g_ptr_array_add (ar, NULL);
+ *argv = (gchar **)g_ptr_array_free (ar, FALSE);
}
/**
@@ -497,29 +596,29 @@ ide_compile_commands_lookup (IdeCompileCommands *self,
GFile **directory,
GError **error)
{
- g_auto(GStrv) argv = NULL;
g_autofree gchar *base = NULL;
- CompileInfo *info;
- gint argc = 0;
+ const CompileInfo *info;
+ const gchar *dot;
g_return_val_if_fail (IDE_IS_COMPILE_COMMANDS (self), NULL);
g_return_val_if_fail (G_IS_FILE (file), NULL);
+ base = g_file_get_basename (file);
+ dot = strrchr (base, '.');
+
if (self->info_by_file != NULL &&
NULL != (info = g_hash_table_lookup (self->info_by_file, file)))
{
- const gchar *dot;
+ g_auto(GStrv) argv = NULL;
+ gint argc = 0;
if (!g_shell_parse_argv (info->command, &argc, &argv, error))
return NULL;
- base = g_file_get_basename (file);
- dot = strrchr (base, '.');
-
if (suffix_is_c_like (dot))
ide_compile_commands_filter_c (self, info, &argv);
else if (suffix_is_vala (dot))
- ide_compile_commands_filter_vala (self, &argv);
+ ide_compile_commands_filter_vala (self, info, &argv);
if (directory != NULL)
*directory = g_object_ref (info->directory);
@@ -527,6 +626,33 @@ ide_compile_commands_lookup (IdeCompileCommands *self,
return g_steal_pointer (&argv);
}
+ /*
+ * Some compile-commands databases will give us info about .vala, but there
+ * may only be a single valac command to run. While we parsed the JSON
+ * document we stored information about each of the Vala files in a special
+ * list for exactly this purpose.
+ */
+ if (ide_str_equal0 (dot, ".vala") && self->vala_info != NULL)
+ {
+ for (guint i = 0; i < self->vala_info->len; i++)
+ {
+ g_auto(GStrv) argv = NULL;
+ gint argc = 0;
+
+ info = g_ptr_array_index (self->vala_info, i);
+
+ if (!g_shell_parse_argv (info->command, &argc, &argv, NULL))
+ continue;
+
+ ide_compile_commands_filter_vala (self, info, &argv);
+
+ if (directory != NULL)
+ *directory = g_object_ref (info->directory);
+
+ return g_steal_pointer (&argv);
+ }
+ }
+
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_NOT_FOUND,
diff --git a/src/tests/data/test-ide-compile-commands.json b/src/tests/data/test-ide-compile-commands.json
index 81acde3..5652427 100644
--- a/src/tests/data/test-ide-compile-commands.json
+++ b/src/tests/data/test-ide-compile-commands.json
@@ -8,5 +8,10 @@
"directory": "/build/gnome-builder/build",
"command": "cc -Isubprojects/libgd/libgd/gd@sha -Isubprojects/libgd/libgd -I../subprojects/libgd/libgd
-Isubprojects/libgd -I../subprojects/libgd -I/opt/gnome/include/gtk-3.0 -I/opt/gnome/include/pango-1.0
-I/opt/gnome/include/glib-2.0 -I/opt/gnome/lib/glib-2.0/include -I/usr/include/cairo -I/usr/include/pixman-1
-I/usr/include/freetype2 -I/usr/include/libpng16 -I/opt/gnome/include/harfbuzz
-I/opt/gnome/include/gdk-pixbuf-2.0 -I/opt/gnome/include/gio-unix-2.0/ -I/opt/gnome/include/atk-1.0
-I/opt/gnome/include/at-spi2-atk/2.0 -I/opt/gnome/include/at-spi-2.0 -I/usr/include/dbus-1.0
-I/usr/lib64/dbus-1.0/include -I/home/christian/Projects/gnome-builder/build -fdiagnostics-color=always -pipe
-D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -std=gnu11 -O0 -g -DHAVE_CONFIG_H -D_GNU_SOURCE
-DIDE_COMPILATION -ggdb -O0 -fno-omit-frame-pointer -fPIC -pthread -DLIBGD_TAGGED_ENTRY=1
'-DG_LOG_DOMAIN=\"libgd\"' -DG_DISABLE_DEPRECATED -MMD -MQ 'subprojects/libgd/libgd/gd@sha/gd-tagg
ed-entry.c.o' -MF 'subprojects/libgd/libgd/gd@sha/gd-tagged-entry.c.o.d' -o
'subprojects/libgd/libgd/gd@sha/gd-tagged-entry.c.o' -c ../subprojects/libgd/libgd/gd-tagged-entry.c",
"file": "../subprojects/libgd/libgd/gd-tagged-entry.c"
+ },
+ {
+ "directory": "/build/gnome-builder/build",
+ "command": "valac -C --debug --pkg json-glib-1.0 --pkg gtksourceview-3.0 --pkg gtk+-3.0 --pkg gio-2.0",
+ "file": "../no/such/file.vala"
}
]
diff --git a/src/tests/test-ide-compile-commands.c b/src/tests/test-ide-compile-commands.c
index a6d15f8..86f926e 100644
--- a/src/tests/test-ide-compile-commands.c
+++ b/src/tests/test-ide-compile-commands.c
@@ -26,10 +26,12 @@ test_compile_commands_basic (void)
g_autoptr(GFile) data_file = NULL;
g_autoptr(GFile) expected_file = NULL;
g_autoptr(GFile) dir = NULL;
+ g_autoptr(GFile) vala = NULL;
g_autoptr(GError) error = NULL;
g_autofree gchar *data_path = NULL;
g_autofree gchar *dir_path = NULL;
g_auto(GStrv) cmdstrv = NULL;
+ g_auto(GStrv) valastrv = NULL;
gboolean r;
commands = ide_compile_commands_new ();
@@ -54,6 +56,16 @@ test_compile_commands_basic (void)
g_assert_cmpstr (cmdstrv[0], ==, "-I/build/gnome-builder/build/subprojects/libgd/libgd/gd@sha");
dir_path = g_file_get_path (dir);
g_assert_cmpstr (dir_path, ==, "/build/gnome-builder/build");
+
+ /* Vala files don't need to match on exact filename, just something dot vala */
+ vala = g_file_new_for_path ("whatever.vala");
+ valastrv = ide_compile_commands_lookup (commands, vala, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (valastrv != NULL);
+ g_assert_cmpstr (valastrv[0], ==, "--pkg");
+ g_assert_cmpstr (valastrv[1], ==, "json-glib-1.0");
+ g_assert_cmpstr (valastrv[2], ==, "--pkg");
+ g_assert_cmpstr (valastrv[3], ==, "gtksourceview-3.0");
}
gint
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]