1
/* ide-clang-translation-unit.c
3
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
5
* This program is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19
#define G_LOG_DOMAIN "clang-translation-unit"
21
#include <clang-c/Index.h>
22
#include <glib/gi18n.h>
24
#include "egg-counter.h"
26
#include "ide-context.h"
27
#include "ide-clang-completion-item.h"
28
#include "ide-clang-private.h"
29
#include "ide-clang-translation-unit.h"
30
#include "ide-debug.h"
31
#include "ide-diagnostic.h"
32
#include "ide-diagnostics.h"
34
#include "ide-internal.h"
35
#include "ide-project.h"
36
#include "ide-ref-ptr.h"
37
#include "ide-source-location.h"
38
#include "ide-symbol.h"
39
#include "ide-thread-pool.h"
40
#include "ide-unsaved-file.h"
41
#include "ide-unsaved-files.h"
44
struct _IdeClangTranslationUnit
46
IdeObject parent_instance;
51
IdeHighlightIndex *index;
52
GHashTable *diagnostics;
57
GPtrArray *unsaved_files;
70
G_DEFINE_TYPE (IdeClangTranslationUnit, ide_clang_translation_unit, IDE_TYPE_OBJECT)
71
EGG_DEFINE_COUNTER (instances, "Clang", "Translation Units", "Number of clang translation units")
82
static GParamSpec *gParamSpecs [LAST_PROP];
85
code_complete_state_free (gpointer data)
87
CodeCompleteState *state = data;
91
g_clear_pointer (&state->unsaved_files, g_ptr_array_unref);
98
* ide_clang_translation_unit_get_index:
99
* @self: A #IdeClangTranslationUnit.
101
* Gets the highlight index for the translation unit.
103
* Returns: (transfer none) (nullable): An #IdeHighlightIndex or %NULL.
106
ide_clang_translation_unit_get_index (IdeClangTranslationUnit *self)
108
g_return_val_if_fail (IDE_IS_CLANG_TRANSLATION_UNIT (self), NULL);
114
ide_clang_translation_unit_set_index (IdeClangTranslationUnit *self,
115
IdeHighlightIndex *index)
117
g_assert (IDE_IS_CLANG_TRANSLATION_UNIT (self));
120
self->index = ide_highlight_index_ref (index);
124
ide_clang_translation_unit_get_file (IdeClangTranslationUnit *self)
126
g_return_val_if_fail (IDE_IS_CLANG_TRANSLATION_UNIT (self), NULL);
132
ide_clang_translation_unit_set_file (IdeClangTranslationUnit *self,
135
g_return_if_fail (IDE_IS_CLANG_TRANSLATION_UNIT (self));
136
g_return_if_fail (G_IS_FILE (file));
138
if (g_set_object (&self->file, file))
139
g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_FILE]);
142
IdeClangTranslationUnit *
143
_ide_clang_translation_unit_new (IdeContext *context,
144
CXTranslationUnit tu,
146
IdeHighlightIndex *index,
149
IdeClangTranslationUnit *ret;
151
g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
152
g_return_val_if_fail (tu, NULL);
153
g_return_val_if_fail (!file || G_IS_FILE (file), NULL);
155
ret = g_object_new (IDE_TYPE_CLANG_TRANSLATION_UNIT,
166
static IdeDiagnosticSeverity
167
translate_severity (enum CXDiagnosticSeverity severity)
171
case CXDiagnostic_Ignored:
172
return IDE_DIAGNOSTIC_IGNORED;
174
case CXDiagnostic_Note:
175
return IDE_DIAGNOSTIC_NOTE;
177
case CXDiagnostic_Warning:
178
return IDE_DIAGNOSTIC_WARNING;
180
case CXDiagnostic_Error:
181
return IDE_DIAGNOSTIC_ERROR;
183
case CXDiagnostic_Fatal:
184
return IDE_DIAGNOSTIC_FATAL;
192
get_path (const gchar *workpath,
195
if (g_str_has_prefix (path, workpath))
197
path = path + strlen (workpath);
198
while (*path == G_DIR_SEPARATOR)
201
return g_strdup (path);
204
return g_strdup (path);
207
static IdeSourceLocation *
208
create_location (IdeClangTranslationUnit *self,
210
const gchar *workpath,
211
CXSourceLocation cxloc)
213
IdeSourceLocation *ret = NULL;
214
IdeFile *file = NULL;
215
CXFile cxfile = NULL;
216
g_autofree gchar *path = NULL;
223
g_return_val_if_fail (self, NULL);
224
g_return_val_if_fail (workpath, NULL);
226
clang_getFileLocation (cxloc, &cxfile, &line, &column, &offset);
228
if (line > 0) line--;
229
if (column > 0) column--;
231
str = clang_getFileName (cxfile);
232
cstr = clang_getCString (str);
234
path = get_path (workpath, cstr);
235
clang_disposeString (str);
239
file = ide_project_get_file_for_path (project, path);
246
context = ide_object_get_context (IDE_OBJECT (self));
247
gfile = g_file_new_for_path (path);
249
file = g_object_new (IDE_TYPE_FILE,
256
ret = ide_source_location_new (file, line, column, offset);
261
static IdeSourceRange *
262
create_range (IdeClangTranslationUnit *self,
264
const gchar *workpath,
265
CXSourceRange cxrange)
267
IdeSourceRange *range = NULL;
268
CXSourceLocation cxbegin;
269
CXSourceLocation cxend;
270
g_autoptr(IdeSourceLocation) begin = NULL;
271
g_autoptr(IdeSourceLocation) end = NULL;
273
g_return_val_if_fail (IDE_IS_CLANG_TRANSLATION_UNIT (self), NULL);
275
cxbegin = clang_getRangeStart (cxrange);
276
cxend = clang_getRangeEnd (cxrange);
278
begin = create_location (self, project, workpath, cxbegin);
279
end = create_location (self, project, workpath, cxend);
281
if ((begin != NULL) && (end != NULL))
282
range = _ide_source_range_new (begin, end);
288
cxfile_equal (CXFile cxfile,
295
cxstr = clang_getFileName (cxfile);
296
path = g_file_get_path (file);
298
ret = (0 == g_strcmp0 (clang_getCString (cxstr), path));
300
clang_disposeString (cxstr);
306
static IdeDiagnostic *
307
create_diagnostic (IdeClangTranslationUnit *self,
309
const gchar *workpath,
311
CXDiagnostic *cxdiag)
313
enum CXDiagnosticSeverity cxseverity;
314
IdeDiagnosticSeverity severity;
316
IdeSourceLocation *loc;
317
g_autofree gchar *spelling = NULL;
319
CXSourceLocation cxloc;
320
CXFile cxfile = NULL;
324
g_return_val_if_fail (IDE_IS_CLANG_TRANSLATION_UNIT (self), NULL);
325
g_return_val_if_fail (cxdiag, NULL);
327
cxloc = clang_getDiagnosticLocation (cxdiag);
328
clang_getExpansionLocation (cxloc, &cxfile, NULL, NULL, NULL);
330
if (cxfile && !cxfile_equal (cxfile, target))
333
cxseverity = clang_getDiagnosticSeverity (cxdiag);
334
severity = translate_severity (cxseverity);
336
cxstr = clang_getDiagnosticSpelling (cxdiag);
337
spelling = g_strdup (clang_getCString (cxstr));
338
clang_disposeString (cxstr);
341
* I thought we could use an approach like the following to get deprecation
342
* status. However, it has so far proven ineffective.
344
* cursor = clang_getCursor (self->tu, cxloc);
345
* avail = clang_getCursorAvailability (cursor);
347
if ((severity == IDE_DIAGNOSTIC_WARNING) &&
348
(spelling != NULL) &&
349
(strstr (spelling, "deprecated") != NULL))
350
severity = IDE_DIAGNOSTIC_DEPRECATED;
352
loc = create_location (self, project, workpath, cxloc);
354
diag = _ide_diagnostic_new (severity, spelling, loc);
356
num_ranges = clang_getDiagnosticNumRanges (cxdiag);
358
for (i = 0; i < num_ranges; i++)
360
CXSourceRange cxrange;
361
IdeSourceRange *range;
363
cxrange = clang_getDiagnosticRange (cxdiag, i);
364
range = create_range (self, project, workpath, cxrange);
366
_ide_diagnostic_take_range (diag, range);
373
* ide_clang_translation_unit_get_diagnostics_for_file:
375
* Retrieves the diagnostics for the translation unit for a specific file.
377
* Returns: (transfer none) (nullable): An #IdeDiagnostics or %NULL.
380
ide_clang_translation_unit_get_diagnostics_for_file (IdeClangTranslationUnit *self,
383
g_return_val_if_fail (IDE_IS_CLANG_TRANSLATION_UNIT (self), NULL);
385
if (!g_hash_table_contains (self->diagnostics, file))
390
g_autofree gchar *workpath = NULL;
396
diags = g_ptr_array_new_with_free_func ((GDestroyNotify)ide_diagnostic_unref);
399
* Acquire the reader lock for the project since we will need to do
400
* a bunch of project tree lookups when creating diagnostics. By doing
401
* this outside of the loops, we avoid creating lots of contention on
402
* the reader lock, but potentially hold on to the entire lock for a bit
405
context = ide_object_get_context (IDE_OBJECT (self));
406
project = ide_context_get_project (context);
407
vcs = ide_context_get_vcs (context);
408
workdir = ide_vcs_get_working_directory (vcs);
409
workpath = g_file_get_path (workdir);
411
ide_project_reader_lock (project);
413
count = clang_getNumDiagnostics (self->tu);
414
for (i = 0; i < count; i++)
419
cxdiag = clang_getDiagnostic (self->tu, i);
420
diag = create_diagnostic (self, project, workpath, file, cxdiag);
427
num_fixits = clang_getDiagnosticNumFixIts (cxdiag);
429
for (j = 0; j < num_fixits; j++)
431
IdeFixit *fixit = NULL;
432
IdeSourceRange *range;
433
CXSourceRange cxrange;
436
cxstr = clang_getDiagnosticFixIt (cxdiag, j, &cxrange);
437
range = create_range (self, project, workpath, cxrange);
438
fixit = _ide_fixit_new (range, clang_getCString (cxstr));
439
clang_disposeString (cxstr);
442
_ide_diagnostic_take_fixit (diag, fixit);
445
g_ptr_array_add (diags, diag);
448
clang_disposeDiagnostic (cxdiag);
451
ide_project_reader_unlock (project);
453
g_hash_table_insert (self->diagnostics, g_object_ref (file), _ide_diagnostics_new (diags));
456
return g_hash_table_lookup (self->diagnostics, file);
460
* ide_clang_translation_unit_get_diagnostics:
462
* Retrieves the diagnostics for the translation unit.
464
* Returns: (transfer none) (nullable): An #IdeDiagnostics or %NULL.
467
ide_clang_translation_unit_get_diagnostics (IdeClangTranslationUnit *self)
469
return ide_clang_translation_unit_get_diagnostics_for_file (self, self->file);
473
ide_clang_translation_unit_get_serial (IdeClangTranslationUnit *self)
475
g_return_val_if_fail (IDE_IS_CLANG_TRANSLATION_UNIT (self), -1);
481
ide_clang_translation_unit_finalize (GObject *object)
483
IdeClangTranslationUnit *self = (IdeClangTranslationUnit *)object;
487
clang_disposeTranslationUnit (self->tu);
488
g_clear_object (&self->file);
489
g_clear_pointer (&self->index, ide_highlight_index_unref);
490
g_clear_pointer (&self->diagnostics, g_hash_table_unref);
492
G_OBJECT_CLASS (ide_clang_translation_unit_parent_class)->finalize (object);
494
EGG_COUNTER_DEC (instances);
500
ide_clang_translation_unit_get_property (GObject *object,
505
IdeClangTranslationUnit *self = IDE_CLANG_TRANSLATION_UNIT (object);
510
g_value_set_object (value, ide_clang_translation_unit_get_file (self));
514
g_value_set_boxed (value, ide_clang_translation_unit_get_index (self));
518
g_value_set_int64 (value, ide_clang_translation_unit_get_serial (self));
522
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
527
ide_clang_translation_unit_set_property (GObject *object,
532
IdeClangTranslationUnit *self = IDE_CLANG_TRANSLATION_UNIT (object);
537
ide_clang_translation_unit_set_file (self, g_value_get_object (value));
541
ide_clang_translation_unit_set_index (self, g_value_get_boxed (value));
545
self->serial = g_value_get_int64 (value);
549
self->tu = g_value_get_pointer (value);
553
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
558
ide_clang_translation_unit_class_init (IdeClangTranslationUnitClass *klass)
560
GObjectClass *object_class = G_OBJECT_CLASS (klass);
562
object_class->finalize = ide_clang_translation_unit_finalize;
563
object_class->get_property = ide_clang_translation_unit_get_property;
564
object_class->set_property = ide_clang_translation_unit_set_property;
566
gParamSpecs [PROP_FILE] =
567
g_param_spec_object ("file",
569
_("The file used to build the translation unit."),
571
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
573
gParamSpecs [PROP_INDEX] =
574
g_param_spec_boxed ("index",
576
_("The highlight index for the translation unit."),
577
IDE_TYPE_HIGHLIGHT_INDEX,
578
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
580
gParamSpecs [PROP_NATIVE] =
581
g_param_spec_pointer ("native",
583
_("The native translation unit pointer."),
584
(G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
586
gParamSpecs [PROP_SERIAL] =
587
g_param_spec_int64 ("serial",
589
_("A sequence number for the translation unit."),
593
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
595
g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
599
ide_clang_translation_unit_init (IdeClangTranslationUnit *self)
601
EGG_COUNTER_INC (instances);
603
self->diagnostics = g_hash_table_new_full ((GHashFunc)g_file_hash,
604
(GEqualFunc)g_file_equal,
606
(GDestroyNotify)ide_diagnostics_unref);
610
ide_clang_translation_unit_code_complete_worker (GTask *task,
611
gpointer source_object,
613
GCancellable *cancellable)
615
IdeClangTranslationUnit *self = source_object;
616
CodeCompleteState *state = task_data;
617
CXCodeCompleteResults *results;
618
g_autoptr(IdeRefPtr) refptr = NULL;
619
struct CXUnsavedFile *ufs;
620
g_autoptr(GPtrArray) ar = NULL;
624
g_assert (IDE_IS_CLANG_TRANSLATION_UNIT (self));
626
g_assert (state->unsaved_files);
629
* FIXME: Not thread safe! We should probably add a "Pending" flag or something that is
630
* similar to g_input_stream_set_pending().
635
/* implausable to reach here, anyway */
636
g_task_return_new_error (task,
638
G_IO_ERROR_INVALID_FILENAME,
639
_("clang_codeCompleteAt() only works on local files"));
643
ufs = g_new0 (struct CXUnsavedFile, state->unsaved_files->len);
645
for (i = 0; i < state->unsaved_files->len; i++)
651
uf = g_ptr_array_index (state->unsaved_files, i);
652
file = ide_unsaved_file_get_file (uf);
653
path = g_file_get_path (file);
656
* NOTE: Some files might not be local, and therefore return a NULL path.
657
* Also, we will free the path from the (const char *) pointer after
658
* executing the work.
662
GBytes *content = ide_unsaved_file_get_content (uf);
664
ufs [j].Filename = path;
665
ufs [j].Contents = g_bytes_get_data (content, NULL);
666
ufs [j].Length = g_bytes_get_size (content);
672
results = clang_codeCompleteAt (self->tu,
675
state->line_offset + 1,
677
clang_defaultCodeCompleteOptions ());
680
* encapsulate in refptr so we don't need to malloc lots of little strings.
681
* we will inflate result strings as necessary.
683
refptr = ide_ref_ptr_new (results, (GDestroyNotify)clang_disposeCodeCompleteResults);
684
ar = g_ptr_array_new ();
686
for (i = 0; i < results->NumResults; i++)
688
GtkSourceCompletionProposal *proposal;
690
proposal = g_object_new (IDE_TYPE_CLANG_COMPLETION_ITEM,
691
"results", ide_ref_ptr_ref (refptr),
694
g_ptr_array_add (ar, proposal);
697
g_task_return_pointer (task, g_ptr_array_ref (ar), (GDestroyNotify)g_ptr_array_unref);
699
/* cleanup malloc'd state */
700
for (i = 0; i < j; i++)
701
g_free ((gchar *)ufs [i].Filename);
707
ide_clang_translation_unit_code_complete_async (IdeClangTranslationUnit *self,
709
const GtkTextIter *location,
710
GCancellable *cancellable,
711
GAsyncReadyCallback callback,
714
g_autoptr(GTask) task = NULL;
715
CodeCompleteState *state;
717
IdeUnsavedFiles *unsaved_files;
721
g_return_if_fail (IDE_IS_CLANG_TRANSLATION_UNIT (self));
722
g_return_if_fail (G_IS_FILE (file));
723
g_return_if_fail (location);
724
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
726
context = ide_object_get_context (IDE_OBJECT (self));
727
unsaved_files = ide_context_get_unsaved_files (context);
729
task = g_task_new (self, cancellable, callback, user_data);
731
state = g_new0 (CodeCompleteState, 1);
732
state->path = g_file_get_path (file);
733
state->line = gtk_text_iter_get_line (location);
734
state->line_offset = gtk_text_iter_get_line_offset (location);
735
state->unsaved_files = ide_unsaved_files_to_array (unsaved_files);
738
* TODO: Technically it is not safe for us to go run this in a thread. We need to ensure
739
* that only one thread is dealing with this at a time.
742
g_task_set_task_data (task, state, code_complete_state_free);
744
ide_thread_pool_push_task (IDE_THREAD_POOL_COMPILER,
746
ide_clang_translation_unit_code_complete_worker);
752
* ide_clang_translation_unit_code_complete_finish:
753
* @self: A #IdeClangTranslationUnit.
754
* @result: A #GAsyncResult
755
* @error: (out) (nullable): A location for a #GError, or %NULL.
757
* Completes a call to ide_clang_translation_unit_code_complete_async().
759
* Returns: (transfer container) (element-type GtkSourceCompletionProposal*): An array of
760
* #GtkSourceCompletionProposal. Upon failure, %NULL is returned.
763
ide_clang_translation_unit_code_complete_finish (IdeClangTranslationUnit *self,
764
GAsyncResult *result,
767
GTask *task = (GTask *)result;
772
g_return_val_if_fail (IDE_IS_CLANG_TRANSLATION_UNIT (self), NULL);
773
g_return_val_if_fail (G_IS_TASK (task), NULL);
775
ret = g_task_propagate_pointer (task, error);
780
static enum CXChildVisitResult
781
find_child_type (CXCursor cursor,
783
CXClientData user_data)
785
enum CXCursorKind *child_kind = user_data;
786
enum CXCursorKind kind = clang_getCursorKind (cursor);
790
case CXCursor_StructDecl:
791
case CXCursor_UnionDecl:
792
case CXCursor_EnumDecl:
794
return CXChildVisit_Break;
796
case CXCursor_TypeRef:
797
cursor = clang_getCursorReferenced (cursor);
798
*child_kind = clang_getCursorKind (cursor);
799
return CXChildVisit_Break;
805
return CXChildVisit_Continue;
809
get_symbol_kind (CXCursor cursor,
810
IdeSymbolFlags *flags)
812
enum CXAvailabilityKind availability;
813
enum CXCursorKind cxkind;
814
IdeSymbolFlags local_flags = 0;
815
IdeSymbolKind kind = 0;
817
availability = clang_getCursorAvailability (cursor);
818
if (availability == CXAvailability_Deprecated)
819
local_flags |= IDE_SYMBOL_FLAGS_IS_DEPRECATED;
821
cxkind = clang_getCursorKind (cursor);
823
if (cxkind == CXCursor_TypedefDecl)
825
enum CXCursorKind child_kind = 0;
827
clang_visitChildren (cursor, find_child_type, &child_kind);
833
case CXCursor_StructDecl:
834
kind = IDE_SYMBOL_STRUCT;
837
case CXCursor_UnionDecl:
838
kind = IDE_SYMBOL_UNION;
841
case CXCursor_ClassDecl:
842
kind = IDE_SYMBOL_CLASS;
845
case CXCursor_FunctionDecl:
846
kind = IDE_SYMBOL_FUNCTION;
849
case CXCursor_EnumDecl:
850
kind = IDE_SYMBOL_ENUM;
853
case CXCursor_EnumConstantDecl:
854
kind = IDE_SYMBOL_ENUM_VALUE;
857
case CXCursor_FieldDecl:
858
kind = IDE_SYMBOL_FIELD;
865
*flags = local_flags;
871
ide_clang_translation_unit_lookup_symbol (IdeClangTranslationUnit *self,
872
IdeSourceLocation *location,
875
g_autofree gchar *filename = NULL;
876
g_autofree gchar *workpath = NULL;
877
g_auto(CXString) cxstr = { 0 };
878
g_autoptr(IdeSourceLocation) declaration = NULL;
879
g_autoptr(IdeSourceLocation) definition = NULL;
880
g_autoptr(IdeSourceLocation) canonical = NULL;
881
IdeSymbolKind symkind = 0;
882
IdeSymbolFlags symflags = 0;
887
CXSourceLocation cxlocation;
891
IdeSymbol *ret = NULL;
899
g_return_val_if_fail (IDE_IS_CLANG_TRANSLATION_UNIT (self), NULL);
900
g_return_val_if_fail (location != NULL, NULL);
902
context = ide_object_get_context (IDE_OBJECT (self));
903
project = ide_context_get_project (context);
904
vcs = ide_context_get_vcs (context);
905
workdir = ide_vcs_get_working_directory (vcs);
906
workpath = g_file_get_path (workdir);
908
line = ide_source_location_get_line (location);
909
line_offset = ide_source_location_get_line_offset (location);
911
if (!(file = ide_source_location_get_file (location)) ||
912
!(gfile = ide_file_get_file (file)) ||
913
!(filename = g_file_get_path (gfile)) ||
914
!(cxfile = clang_getFile (self->tu, filename)))
917
cxlocation = clang_getLocation (self->tu, cxfile, line + 1, line_offset + 1);
918
cursor = clang_getCursor (self->tu, cxlocation);
919
if (clang_Cursor_isNull (cursor))
922
tmpcursor = clang_getCursorReferenced (cursor);
923
if (!clang_Cursor_isNull (tmpcursor))
925
CXSourceLocation tmploc;
926
CXSourceRange cxrange;
928
cxrange = clang_getCursorExtent (tmpcursor);
929
tmploc = clang_getRangeStart (cxrange);
930
definition = create_location (self, project, workpath, tmploc);
933
symkind = get_symbol_kind (cursor, &symflags);
935
cxstr = clang_getCursorDisplayName (cursor);
936
ret = _ide_symbol_new (clang_getCString (cxstr), symkind, symflags,
937
declaration, definition, canonical);
940
* TODO: We should also get information about the defintion of the symbol.
948
create_symbol (CXCursor cursor,
949
GetSymbolsState *state)
951
g_auto(CXString) cxname = { 0 };
952
g_autoptr(IdeSourceLocation) srcloc = NULL;
953
CXSourceLocation cxloc;
954
IdeSymbolKind symkind;
955
IdeSymbolFlags symflags;
961
cxname = clang_getCursorSpelling (cursor);
962
name = clang_getCString (cxname);
963
cxloc = clang_getCursorLocation (cursor);
964
clang_getFileLocation (cxloc, NULL, &line, &line_offset, NULL);
965
srcloc = ide_source_location_new (state->file, line-1, line_offset-1, 0);
967
symkind = get_symbol_kind (cursor, &symflags);
969
symbol = _ide_symbol_new (name, symkind, symflags, NULL, NULL, srcloc);
974
static enum CXChildVisitResult
975
ide_clang_translation_unit_get_symbols__visitor_cb (CXCursor cursor,
977
CXClientData user_data)
979
GetSymbolsState *state = user_data;
980
g_autoptr(IdeSymbol) symbol = NULL;
981
g_auto(CXString) filename = { 0 };
982
CXSourceLocation cxloc;
984
enum CXCursorKind kind;
988
cxloc = clang_getCursorLocation (cursor);
989
clang_getFileLocation (cxloc, &file, NULL, NULL, NULL);
990
filename = clang_getFileName (file);
992
if (0 != g_strcmp0 (clang_getCString (filename), state->path))
993
return CXChildVisit_Continue;
995
kind = clang_getCursorKind (cursor);
999
case CXCursor_FunctionDecl:
1000
case CXCursor_TypedefDecl:
1001
symbol = create_symbol (cursor, state);
1009
g_ptr_array_add (state->ar, ide_symbol_ref (symbol));
1011
return CXChildVisit_Continue;
1015
sort_symbols_by_name (gconstpointer a,
1018
IdeSymbol **asym = (IdeSymbol **)a;
1019
IdeSymbol **bsym = (IdeSymbol **)b;
1021
return g_strcmp0 (ide_symbol_get_name (*asym),
1022
ide_symbol_get_name (*bsym));
1026
* ide_clang_translation_unit_get_symbols:
1028
* Returns: (transfer container) (element-type IdeSymbol*): An array of #IdeSymbol.
1031
ide_clang_translation_unit_get_symbols (IdeClangTranslationUnit *self,
1034
GetSymbolsState state = { 0 };
1037
g_return_val_if_fail (IDE_IS_CLANG_TRANSLATION_UNIT (self), NULL);
1038
g_return_val_if_fail (IDE_IS_FILE (file), NULL);
1040
state.ar = g_ptr_array_new_with_free_func ((GDestroyNotify)ide_symbol_unref);
1042
state.path = g_file_get_path (ide_file_get_file (file));
1044
cursor = clang_getTranslationUnitCursor (self->tu);
1045
clang_visitChildren (cursor,
1046
ide_clang_translation_unit_get_symbols__visitor_cb,
1049
g_ptr_array_sort (state.ar, sort_symbols_by_name);
1051
g_free (state.path);