[gnome-builder] clang: add minimal implementation of symbol tree for Clang
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] clang: add minimal implementation of symbol tree for Clang
- Date: Sat, 20 Jun 2015 09:48:04 +0000 (UTC)
commit 22173ed20994ca16c5aebb9d3cdc7122127ee196
Author: Christian Hergert <christian hergert me>
Date: Thu Jun 18 16:48:19 2015 -0700
clang: add minimal implementation of symbol tree for Clang
Lots still to be done here. For example, we need to support more clang
cursor types. We also need to create source locations for the nodes so
that we can jump to the location when activated in the tree.
We should make sure we do source location lookup via a vfunc/signal so
that it can be done lazily as well. No sense in creating all those
file path strings until they are needed.
libide/Makefile.am | 2 +
libide/clang/ide-clang-private.h | 18 ++-
libide/clang/ide-clang-symbol-node.c | 187 +++++++++++++++++++++++++++++
libide/clang/ide-clang-symbol-node.h | 32 +++++
libide/clang/ide-clang-symbol-tree.c | 167 +++++++++++++++++++++++++-
libide/clang/ide-clang-symbol-tree.h | 4 +
libide/clang/ide-clang-translation-unit.c | 17 +--
7 files changed, 409 insertions(+), 18 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index ef4166b..b658b24 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -221,6 +221,8 @@ libide_1_0_la_SOURCES = \
clang/ide-clang-service.h \
clang/ide-clang-symbol-resolver.c \
clang/ide-clang-symbol-resolver.h \
+ clang/ide-clang-symbol-node.c \
+ clang/ide-clang-symbol-node.h \
clang/ide-clang-symbol-tree.c \
clang/ide-clang-symbol-tree.h \
clang/ide-clang-translation-unit.c \
diff --git a/libide/clang/ide-clang-private.h b/libide/clang/ide-clang-private.h
index 0f73654..496b9f2 100644
--- a/libide/clang/ide-clang-private.h
+++ b/libide/clang/ide-clang-private.h
@@ -24,17 +24,23 @@
#include "ide-types.h"
#include "ide-clang-service.h"
+#include "ide-clang-symbol-node.h"
#include "ide-clang-translation-unit.h"
#include "ide-highlight-index.h"
G_BEGIN_DECLS
-IdeClangTranslationUnit *_ide_clang_translation_unit_new (IdeContext *context,
- CXTranslationUnit tu,
- GFile *file,
- IdeHighlightIndex *index,
- gint64 serial);
-void _ide_clang_dispose_string (CXString *str);
+IdeClangTranslationUnit *_ide_clang_translation_unit_new (IdeContext *context,
+ CXTranslationUnit tu,
+ GFile *file,
+ IdeHighlightIndex *index,
+ gint64 serial);
+void _ide_clang_dispose_string (CXString *str);
+IdeSymbolNode *_ide_clang_symbol_node_new (CXCursor cursor);
+CXCursor _ide_clang_symbol_node_get_cursor (IdeClangSymbolNode *self);
+GArray *_ide_clang_symbol_node_get_children (IdeClangSymbolNode *self);
+void _ide_clang_symbol_node_set_children (IdeClangSymbolNode *self,
+ GArray *children);
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (CXString, _ide_clang_dispose_string)
diff --git a/libide/clang/ide-clang-symbol-node.c b/libide/clang/ide-clang-symbol-node.c
new file mode 100644
index 0000000..cfb25e7
--- /dev/null
+++ b/libide/clang/ide-clang-symbol-node.c
@@ -0,0 +1,187 @@
+/* ide-clang-symbol-node.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ */
+
+#include <clang-c/Index.h>
+
+#include "ide-clang-symbol-node.h"
+#include "ide-symbol.h"
+
+struct _IdeClangSymbolNode
+{
+ IdeSymbolNode parent_instance;
+
+ CXCursor cursor;
+ GArray *children;
+};
+
+G_DEFINE_TYPE (IdeClangSymbolNode, ide_clang_symbol_node, IDE_TYPE_SYMBOL_NODE)
+
+static enum CXChildVisitResult
+find_child_type (CXCursor cursor,
+ CXCursor parent,
+ CXClientData user_data)
+{
+ enum CXCursorKind *child_kind = user_data;
+ enum CXCursorKind kind = clang_getCursorKind (cursor);
+
+ switch ((int)kind)
+ {
+ case CXCursor_StructDecl:
+ case CXCursor_UnionDecl:
+ case CXCursor_EnumDecl:
+ *child_kind = kind;
+ return CXChildVisit_Break;
+
+ case CXCursor_TypeRef:
+ cursor = clang_getCursorReferenced (cursor);
+ *child_kind = clang_getCursorKind (cursor);
+ return CXChildVisit_Break;
+
+ default:
+ break;
+ }
+
+ return CXChildVisit_Continue;
+}
+
+static IdeSymbolKind
+get_symbol_kind (CXCursor cursor,
+ IdeSymbolFlags *flags)
+{
+ enum CXAvailabilityKind availability;
+ enum CXCursorKind cxkind;
+ IdeSymbolFlags local_flags = 0;
+ IdeSymbolKind kind = 0;
+
+ availability = clang_getCursorAvailability (cursor);
+ if (availability == CXAvailability_Deprecated)
+ local_flags |= IDE_SYMBOL_FLAGS_IS_DEPRECATED;
+
+ cxkind = clang_getCursorKind (cursor);
+
+ if (cxkind == CXCursor_TypedefDecl)
+ {
+ enum CXCursorKind child_kind = 0;
+
+ clang_visitChildren (cursor, find_child_type, &child_kind);
+ cxkind = child_kind;
+ }
+
+ switch ((int)cxkind)
+ {
+ 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_FunctionDecl:
+ kind = IDE_SYMBOL_FUNCTION;
+ break;
+
+ case CXCursor_EnumDecl:
+ kind = IDE_SYMBOL_ENUM;
+ break;
+
+ case CXCursor_EnumConstantDecl:
+ kind = IDE_SYMBOL_ENUM_VALUE;
+ break;
+
+ case CXCursor_FieldDecl:
+ kind = IDE_SYMBOL_FIELD;
+ break;
+
+ default:
+ break;
+ }
+
+ *flags = local_flags;
+
+ return kind;
+}
+
+IdeClangSymbolNode *
+_ide_clang_symbol_node_new (CXCursor cursor)
+{
+ IdeClangSymbolNode *self;
+ IdeSymbolFlags flags = 0;
+ IdeSymbolKind kind;
+ CXString cxname;
+
+ /*
+ * TODO: Create IdeSourceLocation for cursor.
+ */
+
+ kind = get_symbol_kind (cursor, &flags);
+ cxname = clang_getCursorSpelling (cursor);
+
+ self = g_object_new (IDE_TYPE_CLANG_SYMBOL_NODE,
+ "kind", kind,
+ "flags", flags,
+ "name", clang_getCString (cxname),
+ NULL);
+
+ self->cursor = cursor;
+
+ clang_disposeString (cxname);
+
+ return self;
+}
+
+CXCursor
+_ide_clang_symbol_node_get_cursor (IdeClangSymbolNode *self)
+{
+ g_return_val_if_fail (IDE_IS_CLANG_SYMBOL_NODE (self), clang_getNullCursor ());;
+
+ return self->cursor;
+}
+
+static void
+ide_clang_symbol_node_class_init (IdeClangSymbolNodeClass *klass)
+{
+}
+
+static void
+ide_clang_symbol_node_init (IdeClangSymbolNode *self)
+{
+}
+
+GArray *
+_ide_clang_symbol_node_get_children (IdeClangSymbolNode *self)
+{
+ g_return_val_if_fail (IDE_IS_CLANG_SYMBOL_NODE (self), NULL);
+
+ return self->children;
+}
+
+void
+_ide_clang_symbol_node_set_children (IdeClangSymbolNode *self,
+ GArray *children)
+{
+ g_return_if_fail (IDE_IS_CLANG_SYMBOL_NODE (self));
+ g_return_if_fail (self->children == NULL);
+ g_return_if_fail (children != NULL);
+
+ self->children = g_array_ref (children);
+}
diff --git a/libide/clang/ide-clang-symbol-node.h b/libide/clang/ide-clang-symbol-node.h
new file mode 100644
index 0000000..ed7afca
--- /dev/null
+++ b/libide/clang/ide-clang-symbol-node.h
@@ -0,0 +1,32 @@
+/* ide-clang-symbol-node.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * 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_SYMBOL_NODE_H
+#define IDE_CLANG_SYMBOL_NODE_H
+
+#include "ide-symbol-node.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_CLANG_SYMBOL_NODE (ide_clang_symbol_node_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeClangSymbolNode, ide_clang_symbol_node, IDE, CLANG_SYMBOL_NODE, IdeSymbolNode)
+
+G_END_DECLS
+
+#endif /* IDE_CLANG_SYMBOL_NODE_H */
diff --git a/libide/clang/ide-clang-symbol-tree.c b/libide/clang/ide-clang-symbol-tree.c
index 20007dc..3276571 100644
--- a/libide/clang/ide-clang-symbol-tree.c
+++ b/libide/clang/ide-clang-symbol-tree.c
@@ -16,8 +16,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <clang-c/Index.h>
#include <glib/gi18n.h>
+#include "ide-clang-private.h"
+#include "ide-clang-symbol-node.h"
#include "ide-clang-symbol-tree.h"
#include "ide-ref-ptr.h"
@@ -26,8 +29,17 @@ struct _IdeClangSymbolTree
GObject parent_instance;
IdeRefPtr *native;
+ GFile *file;
+ gchar *path;
+ GArray *children;
};
+typedef struct
+{
+ const gchar *path;
+ GArray *children;
+} TraversalState;
+
static void symbol_tree_iface_init (IdeSymbolTreeInterface *iface);
G_DEFINE_TYPE_WITH_CODE (IdeClangSymbolTree, ide_clang_symbol_tree, G_TYPE_OBJECT,
@@ -35,22 +47,139 @@ G_DEFINE_TYPE_WITH_CODE (IdeClangSymbolTree, ide_clang_symbol_tree, G_TYPE_OBJEC
enum {
PROP_0,
+ PROP_FILE,
PROP_NATIVE,
LAST_PROP
};
static GParamSpec *gParamSpecs [LAST_PROP];
+/**
+ * ide_clang_symbol_tree_get_file:
+ * @self: A #IdeClangSymbolTree.
+ *
+ * Gets the #IdeClangSymbolTree:file property.
+ *
+ * Returns: (transfer none): A #GFile.
+ */
+GFile *
+ide_clang_symbol_tree_get_file (IdeClangSymbolTree *self)
+{
+ g_return_val_if_fail (IDE_IS_CLANG_SYMBOL_TREE (self), NULL);
+
+ return self->file;
+}
+
+static void
+ide_clang_symbol_tree_set_file (IdeClangSymbolTree *self,
+ GFile *file)
+{
+ g_return_if_fail (IDE_IS_CLANG_SYMBOL_TREE (self));
+ g_return_if_fail (G_IS_FILE (file));
+
+ self->file = g_object_ref (file);
+ self->path = g_file_get_path (file);
+}
+
+static gboolean
+cursor_is_recognized (TraversalState *state,
+ CXCursor cursor)
+{
+ CXString filename;
+ CXSourceLocation cxloc;
+ CXFile file;
+ enum CXCursorKind kind;
+ gboolean ret = FALSE;
+
+ kind = clang_getCursorKind (cursor);
+
+ switch ((int)kind)
+ {
+ /*
+ * TODO: Support way more CXCursorKind.
+ */
+
+ case CXCursor_FunctionDecl:
+ case CXCursor_TypedefDecl:
+ cxloc = clang_getCursorLocation (cursor);
+ clang_getFileLocation (cxloc, &file, NULL, NULL, NULL);
+ filename = clang_getFileName (file);
+ ret = ide_str_equal0 (clang_getCString (filename), state->path);
+ clang_disposeString (filename);
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static enum CXChildVisitResult
+count_recognizable_children (CXCursor cursor,
+ CXCursor parent,
+ CXClientData user_data)
+{
+ TraversalState *state = user_data;
+
+ if (cursor_is_recognized (state, cursor))
+ g_array_append_val (state->children, cursor);
+
+ return CXChildVisit_Continue;
+}
+
static guint
ide_clang_symbol_tree_get_n_children (IdeSymbolTree *symbol_tree,
IdeSymbolNode *parent)
{
IdeClangSymbolTree *self = (IdeClangSymbolTree *)symbol_tree;
+ CXTranslationUnit tu;
+ CXCursor cursor;
+ TraversalState state = { 0 };
+ GArray *children = NULL;
+ guint count;
g_return_val_if_fail (IDE_IS_CLANG_SYMBOL_TREE (self), 0);
- g_return_val_if_fail (!parent || IDE_IS_SYMBOL_NODE (parent), 0);
+ g_return_val_if_fail (!parent || IDE_IS_CLANG_SYMBOL_NODE (parent), 0);
+ g_return_val_if_fail (self->native != NULL, 0);
+
+ if (parent == NULL)
+ children = self->children;
+ else
+ children = _ide_clang_symbol_node_get_children (IDE_CLANG_SYMBOL_NODE (parent));
+
+ if (children != NULL)
+ return children->len;
+
+ if (parent == NULL)
+ {
+ tu = ide_ref_ptr_get (self->native);
+ cursor = clang_getTranslationUnitCursor (tu);
+ }
+ else
+ {
+ cursor = _ide_clang_symbol_node_get_cursor (IDE_CLANG_SYMBOL_NODE (parent));
+ }
+
+ children = g_array_new (FALSE, FALSE, sizeof (CXCursor));
+
+ state.path = self->path;
+ state.children = children;
+
+ clang_visitChildren (cursor,
+ count_recognizable_children,
+ &state);
+
+ if (parent == NULL)
+ self->children = g_array_ref (children);
+ else
+ _ide_clang_symbol_node_set_children (IDE_CLANG_SYMBOL_NODE (parent), children);
- return 0;
+ count = children->len;
+
+ g_array_unref (children);
+
+ return count;
}
static IdeSymbolNode *
@@ -59,10 +188,28 @@ ide_clang_symbol_tree_get_nth_child (IdeSymbolTree *symbol_tree,
guint nth)
{
IdeClangSymbolTree *self = (IdeClangSymbolTree *)symbol_tree;
+ GArray *children;
g_return_val_if_fail (IDE_IS_CLANG_SYMBOL_TREE (self), NULL);
g_return_val_if_fail (!parent || IDE_IS_SYMBOL_NODE (parent), NULL);
+ if (parent == NULL)
+ children = self->children;
+ else
+ children = _ide_clang_symbol_node_get_children (IDE_CLANG_SYMBOL_NODE (parent));
+
+ g_assert (children != NULL);
+
+ if (nth < children->len)
+ {
+ CXCursor cursor;
+
+ cursor = g_array_index (children, CXCursor, nth);
+ return _ide_clang_symbol_node_new (cursor);
+ }
+
+ g_warning ("nth child %u is out of bounds", nth);
+
return NULL;
}
@@ -72,6 +219,7 @@ ide_clang_symbol_tree_finalize (GObject *object)
IdeClangSymbolTree *self = (IdeClangSymbolTree *)object;
g_clear_pointer (&self->native, ide_ref_ptr_unref);
+ g_clear_pointer (&self->children, g_array_unref);
G_OBJECT_CLASS (ide_clang_symbol_tree_parent_class)->finalize (object);
}
@@ -86,6 +234,10 @@ ide_clang_symbol_tree_get_property (GObject *object,
switch (prop_id)
{
+ case PROP_FILE:
+ g_value_set_object (value, ide_clang_symbol_tree_get_file (self));
+ break;
+
case PROP_NATIVE:
g_value_set_boxed (value, self->native);
break;
@@ -105,6 +257,10 @@ ide_clang_symbol_tree_set_property (GObject *object,
switch (prop_id)
{
+ case PROP_FILE:
+ ide_clang_symbol_tree_set_file (self, g_value_get_object (value));
+ break;
+
case PROP_NATIVE:
self->native = g_value_dup_boxed (value);
break;
@@ -123,6 +279,13 @@ ide_clang_symbol_tree_class_init (IdeClangSymbolTreeClass *klass)
object_class->get_property = ide_clang_symbol_tree_get_property;
object_class->set_property = ide_clang_symbol_tree_set_property;
+ gParamSpecs [PROP_FILE] =
+ g_param_spec_object ("file",
+ _("File"),
+ _("File"),
+ G_TYPE_FILE,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
gParamSpecs [PROP_NATIVE] =
g_param_spec_boxed ("native",
_("Native"),
diff --git a/libide/clang/ide-clang-symbol-tree.h b/libide/clang/ide-clang-symbol-tree.h
index 24aff08..f4376ad 100644
--- a/libide/clang/ide-clang-symbol-tree.h
+++ b/libide/clang/ide-clang-symbol-tree.h
@@ -19,6 +19,8 @@
#ifndef IDE_CLANG_SYMBOL_TREE_H
#define IDE_CLANG_SYMBOL_TREE_H
+#include <gio/gio.h>
+
#include "ide-symbol-tree.h"
G_BEGIN_DECLS
@@ -27,6 +29,8 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (IdeClangSymbolTree, ide_clang_symbol_tree, IDE, CLANG_SYMBOL_TREE, GObject)
+GFile *ide_clang_symbol_tree_get_file (IdeClangSymbolTree *self);
+
G_END_DECLS
#endif /* IDE_CLANG_SYMBOL_TREE_H */
diff --git a/libide/clang/ide-clang-translation-unit.c b/libide/clang/ide-clang-translation-unit.c
index de759cb..e452f4a 100644
--- a/libide/clang/ide-clang-translation-unit.c
+++ b/libide/clang/ide-clang-translation-unit.c
@@ -26,6 +26,7 @@
#include "ide-context.h"
#include "ide-clang-completion-item.h"
#include "ide-clang-private.h"
+#include "ide-clang-symbol-tree.h"
#include "ide-clang-translation-unit.h"
#include "ide-debug.h"
#include "ide-diagnostic.h"
@@ -1078,22 +1079,18 @@ ide_clang_translation_unit_get_symbol_tree_async (IdeClangTranslationUnit *self,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
+ IdeSymbolTree *symbol_tree;
g_return_if_fail (IDE_IS_CLANG_TRANSLATION_UNIT (self));
g_return_if_fail (G_IS_FILE (file));
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_task_data (task, g_object_ref (file), g_object_unref);
-
- /*
- * TODO: implement IdeClangSymbolTree
- */
-
- g_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- "Not yet supported");
+ symbol_tree = g_object_new (IDE_TYPE_CLANG_SYMBOL_TREE,
+ "native", self->native,
+ "file", file,
+ NULL);
+ g_task_return_pointer (task, symbol_tree, g_object_unref);
}
IdeSymbolTree *
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]