For C/C++ only mark tag as local if it originates from a source file
[geany-mirror.git] / src / tagmanager / tm_ctags.c
blob16e2ebf04e616db12ef47d37036ab56170007c06
1 /*
2 * Copyright (c) 2016, Jiri Techet
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * Encapsulates ctags so it is isolated from the rest of Geany.
8 */
10 #include "tm_ctags.h"
11 #include "tm_tag.h"
13 #include "general.h" /* must always come before the rest of ctags headers */
14 #include "entry_p.h"
15 #include "error_p.h"
16 #include "field_p.h"
17 #include "options_p.h"
18 #include "parse_p.h"
19 #include "trashbox_p.h"
20 #include "writer_p.h"
21 #include "xtag_p.h"
22 #include "param_p.h"
24 #include <string.h>
27 static gint write_entry(tagWriter *writer, MIO * mio, const tagEntryInfo *const tag, void *user_data);
28 static void rescan_failed(tagWriter *writer, gulong valid_tag_num, void *user_data);
30 tagWriter geanyWriter = {
31 .writeEntry = write_entry,
32 .writePtagEntry = NULL, /* no pseudo-tags */
33 .preWriteEntry = NULL,
34 .postWriteEntry = NULL,
35 .rescanFailedEntry = rescan_failed,
36 .treatFieldAsFixed = NULL,
37 .defaultFileName = "geany_tags_file_which_should_never_appear_anywhere",
38 .private = NULL,
39 .type = WRITER_CUSTOM
43 static bool nonfatal_error_printer(const errorSelection selection,
44 const gchar *const format,
45 va_list ap, void *data CTAGS_ATTR_UNUSED)
47 g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, format, ap);
49 return false;
53 static void enable_roles(const TMParserType lang, guint kind)
55 unsigned int c = countLanguageRoles(lang, kind);
56 kindDefinition *def = getLanguageKind(lang, kind);
57 gchar kind_letter = def->letter;
59 for (unsigned int i = 0; i < c; i++)
61 roleDefinition* rdef = getLanguageRole(lang, kind, (int)i);
62 gboolean should_enable = tm_parser_enable_role(lang, kind_letter);
63 enableRole(rdef, should_enable);
68 static void enable_kinds_and_roles()
70 TMParserType lang;
72 for (lang = 0; lang < (gint)countParsers(); lang++)
74 guint kind_num = countLanguageKinds(lang);
75 guint kind;
77 for (kind = 0; kind < kind_num; kind++)
79 kindDefinition *def = getLanguageKind(lang, kind);
80 gboolean should_enable = tm_parser_enable_kind(lang, def->letter);
82 enableKind(def, should_enable);
83 if (should_enable)
84 enable_roles(lang, kind);
91 Initializes a TMTag structure with information from a ctagsTag struct
92 used by the ctags parsers. Note that the TMTag structure must be malloc()ed
93 before calling this function.
94 @param tag The TMTag structure to initialize
95 @param file Pointer to a TMSourceFile struct (it is assigned to the file member)
96 @param tag_entry Tag information gathered by the ctags parser
97 @return TRUE on success, FALSE on failure
99 static gboolean init_tag(TMTag *tag, TMSourceFile *file, const tagEntryInfo *tag_entry)
101 TMTagType type;
102 guchar kind_letter;
103 TMParserType lang;
105 if (!tag_entry)
106 return FALSE;
108 lang = tag_entry->langType;
109 kind_letter = getLanguageKind(tag_entry->langType, tag_entry->kindIndex)->letter;
110 type = tm_parser_get_tag_type(kind_letter, lang);
111 if (file->lang != lang) /* this is a tag from a subparser */
113 /* check for possible re-definition of subparser type */
114 type = tm_parser_get_subparser_type(file->lang, lang, type);
117 if (!tag_entry->name || type == tm_tag_undef_t)
118 return FALSE;
120 tag->name = g_strdup(tag_entry->name);
121 tag->type = type;
122 tag->local = tag_entry->isFileScope && file->trust_file_scope;
123 tag->flags = tm_tag_flag_none_t;
124 if (isTagExtraBitMarked(tag_entry, XTAG_ANONYMOUS))
125 tag->flags |= tm_tag_flag_anon_t;
126 tag->kind_letter = kind_letter;
127 tag->line = tag_entry->lineNumber;
128 if (NULL != tag_entry->extensionFields.signature)
129 tag->arglist = g_strdup(tag_entry->extensionFields.signature);
130 if ((NULL != tag_entry->extensionFields.scopeName) &&
131 (0 != tag_entry->extensionFields.scopeName[0]))
132 tag->scope = g_strdup(tag_entry->extensionFields.scopeName);
133 if (tag_entry->extensionFields.inheritance != NULL)
134 tag->inheritance = g_strdup(tag_entry->extensionFields.inheritance);
135 if (tag_entry->extensionFields.typeRef[1] != NULL)
136 tag->var_type = g_strdup(tag_entry->extensionFields.typeRef[1]);
137 if (tag_entry->extensionFields.access != NULL)
138 tag->access = tm_source_file_get_tag_access(tag_entry->extensionFields.access);
139 if (tag_entry->extensionFields.implementation != NULL)
140 tag->impl = tm_source_file_get_tag_impl(tag_entry->extensionFields.implementation);
141 if ((tm_tag_macro_t == tag->type) && (NULL != tag->arglist))
142 tag->type = tm_tag_macro_with_arg_t;
143 tag->file = file;
144 /* redefine lang also for subparsers because the rest of Geany assumes that
145 * tags from a single file are from a single language */
146 tag->lang = file->lang;
147 if (tag->scope)
149 gchar *new_scope = tm_parser_update_scope(tag->lang, tag->scope);
150 if (new_scope != tag->scope)
152 g_free(tag->scope);
153 tag->scope = new_scope;
156 return TRUE;
160 static gint write_entry(tagWriter *writer, MIO * mio, const tagEntryInfo *const tag, void *user_data)
162 TMSourceFile *source_file = user_data;
163 TMTag *tm_tag = tm_tag_new();
165 getTagScopeInformation((tagEntryInfo *)tag, NULL, NULL);
167 if (!init_tag(tm_tag, source_file, tag))
169 tm_tag_unref(tm_tag);
170 return 0;
173 g_ptr_array_add(source_file->tags_array, tm_tag);
175 /* output length - we don't write anything to the MIO */
176 return 0;
180 static void rescan_failed(tagWriter *writer, gulong valid_tag_num, void *user_data)
182 TMSourceFile *source_file = user_data;
183 GPtrArray *tags_array = source_file->tags_array;
185 if (tags_array->len > valid_tag_num)
187 guint i;
188 for (i = valid_tag_num; i < tags_array->len; i++)
189 tm_tag_unref(tags_array->pdata[i]);
190 g_ptr_array_set_size(tags_array, valid_tag_num);
195 /* keep in sync with ctags main() - use only things interesting for us */
196 void tm_ctags_init(void)
198 initDefaultTrashBox();
200 setErrorPrinter(nonfatal_error_printer, NULL);
201 setTagWriter(WRITER_CUSTOM, &geanyWriter);
203 checkRegex();
204 initFieldObjects();
205 initXtagObjects();
207 initializeParsing();
208 initOptions();
209 initRegexOptscript();
211 /* make sure all parsers are initialized */
212 initializeParser(LANG_AUTO);
214 /* change default values which are false */
215 enableXtag(XTAG_TAGS_GENERATED_BY_GUEST_PARSERS, true);
216 enableXtag(XTAG_REFERENCE_TAGS, true);
218 /* some kinds we are interested in are disabled by default */
219 enable_kinds_and_roles();
223 void tm_ctags_add_ignore_symbol(const char *value)
225 langType lang = getNamedLanguage ("CPreProcessor", 0);
226 gchar *val = g_strdup(value);
228 /* make sure we don't enter empty string - passing NULL or "" clears
229 * the ignore list in ctags */
230 val = g_strstrip(val);
231 if (*val)
232 applyParameter (lang, "ignore", val);
233 g_free(val);
237 void tm_ctags_clear_ignore_symbols(void)
239 langType lang = getNamedLanguage ("CPreProcessor", 0);
240 applyParameter (lang, "ignore", NULL);
244 /* call after all tags have been collected so we don't have to handle reparses
245 * with the counter (which gets complicated when also subparsers are involved) */
246 static void rename_anon_tags(TMSourceFile *source_file)
248 gboolean is_c = source_file->lang == TM_PARSER_C || source_file->lang == TM_PARSER_CPP;
249 gint *anon_counter_table = NULL;
250 GPtrArray *removed_typedefs = NULL;
251 guint i;
253 for (i = 0; i < source_file->tags_array->len; i++)
255 TMTag *tag = TM_TAG(source_file->tags_array->pdata[i]);
256 if (tm_tag_is_anon(tag))
258 gchar *orig_name, *new_name = NULL;
259 guint j;
260 guint new_name_len, orig_name_len;
261 gboolean inside_nesting = FALSE;
262 guint scope_len = tag->scope ? strlen(tag->scope) : 0;
263 gchar kind = tag->kind_letter;
265 orig_name = tag->name;
266 orig_name_len = strlen(orig_name);
268 if (is_c)
270 /* First check if there's a typedef behind the scope nesting
271 * such as typedef struct {} Foo; - in this case we can replace
272 * the anon tag with Foo */
273 for (j = i + 1; j < source_file->tags_array->len; j++)
275 TMTag *nested_tag = TM_TAG(source_file->tags_array->pdata[j]);
276 guint nested_scope_len = nested_tag->scope ? strlen(nested_tag->scope) : 0;
278 /* Tags can be interleaved with scopeless macros - skip those */
279 if (nested_tag->type & (tm_tag_macro_t | tm_tag_macro_with_arg_t))
280 continue;
282 /* Nested tags have longer scope than the parent - once the scope
283 * is equal or lower than the parent scope, we are outside the tag's
284 * scope. */
285 if (nested_scope_len <= scope_len)
286 break;
289 /* We are out of the nesting - the next tag could be a typedef */
290 if (j < source_file->tags_array->len)
292 TMTag *typedef_tag = TM_TAG(source_file->tags_array->pdata[j]);
293 guint typedef_scope_len = typedef_tag->scope ? strlen(typedef_tag->scope) : 0;
295 /* Should be at the same scope level as the anon tag */
296 if (typedef_tag->type == tm_tag_typedef_t &&
297 typedef_scope_len == scope_len &&
298 g_strcmp0(typedef_tag->var_type, tag->name) == 0)
300 /* set the name of the original anon tag and pretend
301 * it wasn't a anon tag */
302 tag->name = g_strdup(typedef_tag->name);
303 tag->flags &= ~tm_tag_flag_anon_t;
304 new_name = tag->name;
305 /* the typedef tag will be removed */
306 if (!removed_typedefs)
307 removed_typedefs = g_ptr_array_new();
308 g_ptr_array_add(removed_typedefs, GUINT_TO_POINTER(j));
313 /* there's no typedef name for the anon tag so let's generate one */
314 if (!new_name)
316 gchar buf[50];
317 guint anon_counter;
318 const gchar *kind_name = tm_ctags_get_kind_name(kind, tag->lang);
320 if (!anon_counter_table)
321 anon_counter_table = g_new0(gint, 256);
323 anon_counter = ++anon_counter_table[kind];
325 sprintf(buf, "anon_%s_%u", kind_name, anon_counter);
326 tag->name = g_strdup(buf);
327 new_name = tag->name;
330 new_name_len = strlen(new_name);
332 /* Check if this tag is parent of some other tag - if so, we have to
333 * update the scope. It can only be parent of the following tags
334 * so start with the next tag. */
335 for (j = i + 1; j < source_file->tags_array->len; j++)
337 TMTag *nested_tag = TM_TAG(source_file->tags_array->pdata[j]);
338 guint nested_scope_len = nested_tag->scope ? strlen(nested_tag->scope) : 0;
339 gchar *pos;
341 /* Tags can be interleaved with scopeless macros - skip those */
342 if (is_c && nested_tag->type & (tm_tag_macro_t | tm_tag_macro_with_arg_t))
343 continue;
345 /* In Fortran, we can create variables of anonymous structures:
346 * structure var1, var2
347 * integer a
348 * end structure
349 * and the parser first generates tags for var1 and var2 which
350 * are on the same scope as the structure itself. So first
351 * we need to skip past the tags on the same scope and only
352 * afterwards we get the nested tags.
353 * */
354 if (source_file->lang == TM_PARSER_FORTRAN &&
355 !inside_nesting && nested_scope_len == scope_len)
356 continue;
358 inside_nesting = TRUE;
360 /* Terminate if outside of tag scope, see above */
361 if (nested_scope_len <= scope_len)
362 break;
364 pos = strstr(nested_tag->scope, orig_name);
365 /* We found the parent name in the nested tag scope - replace it
366 * with the new name. Note: anonymous tag names generated by
367 * ctags are unique enough that we don't have to check for
368 * scope separators here. */
369 if (pos)
371 gchar *str = g_malloc(nested_scope_len + 50);
372 guint prefix_len = pos - nested_tag->scope;
374 strncpy(str, nested_tag->scope, prefix_len);
375 strcpy(str + prefix_len, new_name);
376 strcpy(str + prefix_len + new_name_len, pos + orig_name_len);
377 g_free(nested_tag->scope);
378 nested_tag->scope = str;
382 /* We are out of the nesting - the next tags could be variables
383 * of an anonymous struct such as "struct {} a[2], *b, c;" */
384 while (j < source_file->tags_array->len)
386 TMTag *var_tag = TM_TAG(source_file->tags_array->pdata[j]);
387 guint var_scope_len = var_tag->scope ? strlen(var_tag->scope) : 0;
388 gchar *pos;
390 /* Should be at the same scope level as the anon tag */
391 if (var_scope_len == scope_len &&
392 var_tag->var_type && (pos = strstr(var_tag->var_type, orig_name)))
394 GString *str = g_string_new(var_tag->var_type);
395 gssize p = pos - var_tag->var_type;
396 g_string_erase(str, p, strlen(orig_name));
397 g_string_insert(str, p, new_name);
398 g_free(var_tag->var_type);
399 var_tag->var_type = str->str;
400 g_string_free(str, FALSE);
402 else
403 break;
405 j++;
408 g_free(orig_name);
412 if (removed_typedefs)
414 for (i = 0; i < removed_typedefs->len; i++)
416 guint j = GPOINTER_TO_UINT(removed_typedefs->pdata[i]);
417 TMTag *tag = TM_TAG(source_file->tags_array->pdata[j]);
418 tm_tag_unref(tag);
419 source_file->tags_array->pdata[j] = NULL;
422 /* remove NULL entries from the array */
423 tm_tags_prune(source_file->tags_array);
425 g_ptr_array_free(removed_typedefs, TRUE);
428 if (anon_counter_table)
429 g_free(anon_counter_table);
433 void tm_ctags_parse(guchar *buffer, gsize buffer_size,
434 const gchar *file_name, TMParserType language, TMSourceFile *source_file)
436 g_return_if_fail(buffer != NULL || file_name != NULL);
438 parseRawBuffer(file_name, buffer, buffer_size, language, source_file);
440 rename_anon_tags(source_file);
444 const gchar *tm_ctags_get_lang_name(TMParserType lang)
446 return getLanguageName(lang);
450 TMParserType tm_ctags_get_named_lang(const gchar *name)
452 return getNamedLanguage(name, 0);
456 const gchar *tm_ctags_get_lang_kinds(TMParserType lang)
458 guint kind_num = countLanguageKinds(lang);
459 static gchar kinds[257];
460 guint i;
462 for (i = 0; i < kind_num; i++)
463 kinds[i] = getLanguageKind(lang, i)->letter;
464 kinds[i] = '\0';
466 return kinds;
470 const gchar *tm_ctags_get_kind_name(gchar kind, TMParserType lang)
472 kindDefinition *def = getLanguageKindForLetter(lang, kind);
473 return def ? def->name : "unknown";
477 gchar tm_ctags_get_kind_from_name(const gchar *name, TMParserType lang)
479 kindDefinition *def = getLanguageKindForName(lang, name);
480 return def ? def->letter : '-';
484 guint tm_ctags_get_lang_count(void)
486 return countParsers();