[gnome-builder] clang: stub out diagnose handler and test case



commit ec47bea6b6cc75456372469be64b0ab8db0419f4
Author: Christian Hergert <chergert redhat com>
Date:   Fri Apr 20 03:26:14 2018 -0700

    clang: stub out diagnose handler and test case

 src/plugins/clang/gnome-builder-clang.c |  79 +++++++++++++++
 src/plugins/clang/ide-clang.c           | 171 ++++++++++++++++++++++++++++++++
 src/plugins/clang/ide-clang.h           |   9 ++
 src/plugins/clang/test-daemon.c         |  42 ++++++++
 4 files changed, 301 insertions(+)
---
diff --git a/src/plugins/clang/gnome-builder-clang.c b/src/plugins/clang/gnome-builder-clang.c
index 7b776caa5..4d91a771d 100644
--- a/src/plugins/clang/gnome-builder-clang.c
+++ b/src/plugins/clang/gnome-builder-clang.c
@@ -242,6 +242,80 @@ handle_index_file (JsonrpcServer *server,
                               client_op_ref (op));
 }
 
+/* Diagnose Handler {{{1 */
+
+static void
+handle_diagnose_cb (IdeClang     *clang,
+                    GAsyncResult *result,
+                    gpointer      user_data)
+{
+  g_autoptr(ClientOp) op = user_data;
+  g_autoptr(GPtrArray) diagnostics = NULL;
+  g_autoptr(GError) error = NULL;
+  GVariantBuilder builder;
+
+  g_assert (IDE_IS_CLANG (clang));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (op != NULL);
+
+  if (!(diagnostics = ide_clang_diagnose_finish (clang, result, &error)))
+    {
+      client_op_error (op, error);
+      return;
+    }
+
+  IDE_PTR_ARRAY_SET_FREE_FUNC (diagnostics, ide_diagnostic_unref);
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
+
+  for (guint i = 0; i < diagnostics->len; i++)
+    {
+      G_GNUC_UNUSED IdeDiagnostic *diag = g_ptr_array_index (diagnostics, i);
+
+      g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
+      g_variant_builder_close (&builder);
+    }
+
+  client_op_reply (op, g_variant_builder_end (&builder));
+}
+
+static void
+handle_diagnose (JsonrpcServer *server,
+                 JsonrpcClient *client,
+                 const gchar   *method,
+                 GVariant      *id,
+                 GVariant      *params,
+                 IdeClang      *clang)
+{
+  g_autoptr(GPtrArray) argv = NULL;
+  g_autoptr(ClientOp) op = NULL;
+  g_auto(GStrv) flags = NULL;
+  const gchar *path = NULL;
+
+  g_assert (JSONRPC_IS_SERVER (server));
+  g_assert (JSONRPC_IS_CLIENT (client));
+  g_assert (g_str_equal (method, "clang/diagnose"));
+  g_assert (id != NULL);
+  g_assert (IDE_IS_CLANG (clang));
+
+  op = client_op_new (client, id);
+
+  if (!JSONRPC_MESSAGE_PARSE (params, "path", JSONRPC_MESSAGE_GET_STRING (&path)))
+    {
+      client_op_bad_params (op);
+      return;
+    }
+
+  JSONRPC_MESSAGE_PARSE (params, "flags", JSONRPC_MESSAGE_GET_STRV (&flags));
+
+  ide_clang_diagnose_async (clang,
+                            path,
+                            (const gchar * const *)flags,
+                            op->cancellable,
+                            (GAsyncReadyCallback)handle_diagnose_cb,
+                            client_op_ref (op));
+}
+
 /* Main and Server Setup {{{1 */
 
 static void
@@ -303,6 +377,11 @@ main (gint argc,
                               (JsonrpcServerHandler)handle_index_file,
                               g_object_ref (clang),
                               g_object_unref);
+  jsonrpc_server_add_handler (server,
+                              "clang/diagnose",
+                              (JsonrpcServerHandler)handle_diagnose,
+                              g_object_ref (clang),
+                              g_object_unref);
 
 
   jsonrpc_server_accept_io_stream (server, stream);
diff --git a/src/plugins/clang/ide-clang.c b/src/plugins/clang/ide-clang.c
index 651db352a..cf7014907 100644
--- a/src/plugins/clang/ide-clang.c
+++ b/src/plugins/clang/ide-clang.c
@@ -472,6 +472,177 @@ ide_clang_index_file_finish (IdeClang      *self,
   return ret;
 }
 
+/* Diagnose {{{1 */
+
+typedef struct
+{
+  GPtrArray  *diagnostics;
+  gchar      *path;
+  gchar     **argv;
+  guint       argc;
+} Diagnose;
+
+static void
+diagnose_free (gpointer data)
+{
+  Diagnose *state = data;
+
+  g_clear_pointer (&state->path, g_free);
+  g_clear_pointer (&state->argv, g_strfreev);
+  g_clear_pointer (&state->diagnostics, g_ptr_array_unref);
+
+  g_slice_free (Diagnose, state);
+}
+
+static IdeDiagnostic *
+create_diagnostic (CXDiagnostic diag)
+{
+  g_assert (diag != NULL);
+
+
+  return NULL;
+}
+
+static void
+ide_clang_diagnose_worker (IdeTask      *task,
+                           gpointer      source_object,
+                           gpointer      task_data,
+                           GCancellable *cancellable)
+{
+  Diagnose *state = task_data;
+  g_auto(CXTranslationUnit) unit = NULL;
+  g_auto(CXIndex) index = NULL;
+  enum CXErrorCode code;
+  unsigned options;
+  guint n_diags;
+
+  g_assert (IDE_IS_CLANG (source_object));
+  g_assert (IDE_IS_TASK (task));
+  g_assert (state != NULL);
+  g_assert (state->path != NULL);
+  g_assert (state->diagnostics != NULL);
+
+  options = (clang_defaultEditingTranslationUnitOptions () |
+#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 43)
+             CXTranslationUnit_SingleFileParse |
+#endif
+#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 35)
+             CXTranslationUnit_KeepGoing |
+#endif
+             CXTranslationUnit_DetailedPreprocessingRecord |
+             CXTranslationUnit_SkipFunctionBodies);
+
+  index = clang_createIndex (0, 0);
+  code = clang_parseTranslationUnit2 (index,
+                                      state->path,
+                                      (const char * const *)state->argv,
+                                      state->argc,
+                                      NULL,
+                                      0,
+                                      options,
+                                      &unit);
+
+  if (code != CXError_Success)
+    {
+      ide_task_return_new_error (task,
+                                 G_IO_ERROR,
+                                 G_IO_ERROR_FAILED,
+                                 "Failed to index file \"%s\", exited with code %d",
+                                 state->path, code);
+      return;
+    }
+
+  n_diags = clang_getNumDiagnostics (unit);
+
+  for (guint i = 0; i < n_diags; i++)
+    {
+      g_autoptr(CXDiagnostic) cxdiag = NULL;
+      g_autoptr(IdeDiagnostic) diag = NULL;
+
+      cxdiag = clang_getDiagnostic (unit, i);
+      diag = create_diagnostic (cxdiag);
+
+      if (diag != NULL)
+        g_ptr_array_add (state->diagnostics, g_steal_pointer (&diag));
+    }
+
+  ide_task_return_pointer (task,
+                           g_steal_pointer (&state->diagnostics),
+                           (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * ide_clang_diagnose_async:
+ * @self: a #IdeClang
+ * @path: the path to the C/C++/Obj-C file on local disk
+ * @argv: the command line arguments for clang
+ * @cancellable: (nullable): a #GCancellable or %NULL
+ * @callback: a callback to execute up on completion
+ * @user_data: closure data for @callback
+ *
+ * Asynchronously requests that the file be diagnosed.
+ *
+ * This generates diagnostics related to the file after parsing it.
+ *
+ * Since: 3.30
+ */
+void
+ide_clang_diagnose_async (IdeClang            *self,
+                          const gchar         *path,
+                          const gchar * const *argv,
+                          GCancellable        *cancellable,
+                          GAsyncReadyCallback  callback,
+                          gpointer             user_data)
+{
+  g_autoptr(IdeTask) task = NULL;
+  Diagnose *state;
+
+  g_return_if_fail (IDE_IS_CLANG (self));
+  g_return_if_fail (path != NULL);
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  state = g_slice_new0 (Diagnose);
+  state->path = g_strdup (path);
+  state->argv = ide_clang_cook_flags (argv);
+  state->argc = state->argv ? g_strv_length (state->argv) : 0;
+  state->diagnostics = g_ptr_array_new ();
+
+  IDE_PTR_ARRAY_SET_FREE_FUNC (state->diagnostics, ide_diagnostic_unref);
+
+  task = ide_task_new (self, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, ide_clang_diagnose_async);
+  ide_task_set_kind (task, IDE_TASK_KIND_COMPILER);
+  ide_task_set_task_data (task, state, diagnose_free);
+  ide_task_run_in_thread (task, ide_clang_diagnose_worker);
+}
+
+/**
+ * ide_clang_diagnose_finish:
+ *
+ * Finishes a request to diagnose a file.
+ *
+ * Returns: (transfer full) (element-type Ide.Diagnostic):
+ *   a #GPtrArray of #IdeDiagnostic
+ *
+ * Since: 3.30
+ */
+GPtrArray *
+ide_clang_diagnose_finish (IdeClang      *self,
+                           GAsyncResult  *result,
+                           GError       **error)
+{
+  GPtrArray *ret;
+
+  g_return_val_if_fail (IDE_IS_CLANG (self), NULL);
+  g_return_val_if_fail (IDE_IS_TASK (result), NULL);
+
+  ret = ide_task_propagate_pointer (IDE_TASK (result), error);
+
+  IDE_PTR_ARRAY_CLEAR_FREE_FUNC (ret);
+
+  return ret;
+}
+
 /* Get symbol at source location {{{1 */
 
 /* vim:set foldmethod=marker: */
diff --git a/src/plugins/clang/ide-clang.h b/src/plugins/clang/ide-clang.h
index 8a38c4f04..739be0114 100644
--- a/src/plugins/clang/ide-clang.h
+++ b/src/plugins/clang/ide-clang.h
@@ -36,5 +36,14 @@ void       ide_clang_index_file_async  (IdeClang             *self,
 GPtrArray *ide_clang_index_file_finish (IdeClang             *self,
                                         GAsyncResult         *result,
                                         GError              **error);
+void       ide_clang_diagnose_async    (IdeClang             *self,
+                                        const gchar          *path,
+                                        const gchar * const  *argv,
+                                        GCancellable         *cancellable,
+                                        GAsyncReadyCallback   callback,
+                                        gpointer              user_data);
+GPtrArray *ide_clang_diagnose_finish   (IdeClang             *self,
+                                        GAsyncResult         *result,
+                                        GError              **error);
 
 G_END_DECLS
diff --git a/src/plugins/clang/test-daemon.c b/src/plugins/clang/test-daemon.c
index 70b92b7ba..d9b3b54a0 100644
--- a/src/plugins/clang/test-daemon.c
+++ b/src/plugins/clang/test-daemon.c
@@ -8,6 +8,8 @@ typedef void (*TestFunc) (JsonrpcClient *client,
                           GTask         *task);
 
 static void tick_tests      (JsonrpcClient *client);
+static void test_diagnose   (JsonrpcClient *client,
+                             GTask         *task);
 static void test_index_file (JsonrpcClient *client,
                              GTask         *task);
 
@@ -15,6 +17,7 @@ static gchar **flags;
 static const gchar *path;
 static GMainLoop *main_loop;
 static TestFunc test_funcs[] = {
+  test_diagnose,
   test_index_file,
 };
 
@@ -57,6 +60,45 @@ test_index_file (JsonrpcClient *client,
                              g_object_ref (task));
 }
 
+static void
+test_diagnose_cb (GObject      *object,
+                  GAsyncResult *result,
+                  gpointer      user_data)
+{
+  JsonrpcClient *client = (JsonrpcClient *)object;
+  g_autoptr(GTask) task = user_data;
+  g_autoptr(GVariant) reply = NULL;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (G_IS_TASK (task));
+
+  if (!jsonrpc_client_call_finish (client, result, &reply, &error))
+    g_error ("diagnose: %s", error->message);
+
+  g_printerr ("diagnose: %s\n", g_variant_print (reply, TRUE));
+
+  g_task_return_boolean (task, TRUE);
+}
+
+static void
+test_diagnose (JsonrpcClient *client,
+               GTask         *task)
+{
+  g_autoptr(GVariant) params = NULL;
+
+  params = JSONRPC_MESSAGE_NEW (
+    "path", JSONRPC_MESSAGE_PUT_STRING (path),
+    "flags", JSONRPC_MESSAGE_PUT_STRV ((const gchar * const *)flags)
+  );
+
+  jsonrpc_client_call_async (client,
+                             "clang/diagnose",
+                             params,
+                             NULL,
+                             test_diagnose_cb,
+                             g_object_ref (task));
+}
+
 static void
 finished_cb (GObject      *object,
              GAsyncResult *result,


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