[geany/geany] dbd0eb: Consistently rename anonymous tags and drop the last ctags diff

Jiří Techet git-noreply at xxxxx
Sat Feb 12 21:38:22 UTC 2022


Branch:      refs/heads/master
Author:      Jiří Techet <techet at gmail.com>
Committer:   Jiří Techet <techet at gmail.com>
Date:        Mon, 10 Jan 2022 22:10:44 UTC
Commit:      dbd0ebc914d5ac56baef3fe1c28acda9d7ff3e09
             https://github.com/geany/geany/commit/dbd0ebc914d5ac56baef3fe1c28acda9d7ff3e09

Log Message:
-----------
Consistently rename anonymous tags and drop the last ctags diff

Check all the collected tags once a file is parsed (i.e. when
we have all tags, including those from subparsers) and renamea
them in the form

anon_enum_1
anon_struct_1
anon_enum_2
anon_struct_2

where the second component is a ctags kind and the number is
per-kind.

In addition, scopes of the nested tags have to be updated if the parent
tag is an anonymous tag.

Finally, for anonymous tags of the form typedef struct Foo{int a;};
we can use the name of the typedef instead of generating the
anonymous name. In this case we can drop the typedef tag once
the anonymous tag is updated with its name.

More details can be found in comments.


Modified Paths:
--------------
    ctags/ctags_changes.patch
    ctags/main/parse.c
    scripts/update-ctags.py
    src/tagmanager/tm_ctags.c
    src/tagmanager/tm_source_file.c
    src/tagmanager/tm_tag.h

Modified: ctags/ctags_changes.patch
24 lines changed, 0 insertions(+), 24 deletions(-)
===================================================================
@@ -1,24 +0,0 @@
-A patch to ctags containing our changes to ctags
-(changing anon tag names from anon<hash> to anon<number>).
-diff --git a/ctags/main/parse.c b/ctags/main/parse.c
-index 8fbb7148..c12f8662 100644
---- ctags/main/parse.c
-+++ ctags/main/parse.c
-@@ -4111,12 +4111,18 @@ extern void anonGenerate (vString *buffer, const char *prefix, int kind)
- 	parser -> anonymousIdentiferId ++;
- 
- 	char szNum[32];
-+#if 0
- 	char buf [9];
- 
- 	vStringCopyS(buffer, prefix);
- 
- 	anonHashString (getInputFileName(), buf);
- 	sprintf(szNum,"%s%02x%02x",buf,parser -> anonymousIdentiferId, kind);
-+#else
-+	/* we want to see numbers for anon functions in the tree view instead of the hash */
-+	vStringCopyS(buffer, prefix);
-+	sprintf(szNum,"%u", parser -> anonymousIdentiferId);
-+#endif
- 	vStringCatS(buffer,szNum);
- }


Modified: ctags/main/parse.c
6 lines changed, 0 insertions(+), 6 deletions(-)
===================================================================
@@ -4787,18 +4787,12 @@ extern void anonGenerate (vString *buffer, const char *prefix, int kind)
 	parser -> anonymousIdentiferId ++;
 
 	char szNum[32];
-#if 0
 	char buf [9];
 
 	vStringCopyS(buffer, prefix);
 
 	anonHashString (getInputFileName(), buf);
 	sprintf(szNum,"%s%02x%02x",buf,parser -> anonymousIdentiferId, kind);
-#else
-	/* we want to see numbers for anon functions in the tree view instead of the hash */
-	vStringCopyS(buffer, prefix);
-	sprintf(szNum,"%u", parser -> anonymousIdentiferId);
-#endif
 	vStringCatS(buffer,szNum);
 }
 


Modified: scripts/update-ctags.py
3 lines changed, 0 insertions(+), 3 deletions(-)
===================================================================
@@ -51,6 +51,3 @@
 main_diff = set(main_src_files) - set(main_dst_files)
 if main_diff:
     print('Files added to main: ' + str(main_diff))
-
-os.chdir(dstdir)
-os.system('patch -p1 <ctags_changes.patch')


Modified: src/tagmanager/tm_ctags.c
141 lines changed, 141 insertions(+), 0 deletions(-)
===================================================================
@@ -123,6 +123,7 @@ static gboolean init_tag(TMTag *tag, TMSourceFile *file, const tagEntryInfo *tag
 	tag->flags = tm_tag_flag_none_t;
 	if (isTagExtraBitMarked(tag_entry, XTAG_ANONYMOUS))
 		tag->flags |= tm_tag_flag_anon_t;
+	tag->kind_letter = kind_letter;
 	tag->line = tag_entry->lineNumber;
 	if (NULL != tag_entry->extensionFields.signature)
 		tag->arglist = g_strdup(tag_entry->extensionFields.signature);
@@ -240,12 +241,152 @@ void tm_ctags_clear_ignore_symbols(void)
 }
 
 
+/* call after all tags have been collected so we don't have to handle reparses
+ * with the counter (which gets complicated when also subparsers are involved) */
+static void rename_anon_tags(TMSourceFile *source_file)
+{
+	gint *anon_counter_table = NULL;
+	GPtrArray *removed_typedefs = NULL;
+	guint i;
+
+	for (i = 0; i < source_file->tags_array->len; i++)
+	{
+		TMTag *tag = TM_TAG(source_file->tags_array->pdata[i]);
+		if (tm_tag_is_anon(tag))
+		{
+			gchar *orig_name, *new_name = NULL;
+			guint j;
+			guint new_name_len, orig_name_len;
+			guint scope_len = tag->scope ? strlen(tag->scope) : 0;
+			gchar kind = tag->kind_letter;
+
+			orig_name = tag->name;
+			orig_name_len = strlen(orig_name);
+
+			if (source_file->lang == TM_PARSER_C || source_file->lang == TM_PARSER_CPP)
+			{
+				/* First check if there's a typedef behind the scope nesting
+				 * such as typedef struct {} Foo; - in this case we can replace
+				 * the anon tag with Foo */
+				for (j = i + 1; j < source_file->tags_array->len; j++)
+				{
+					TMTag *nested_tag = TM_TAG(source_file->tags_array->pdata[j]);
+					guint nested_scope_len = nested_tag->scope ? strlen(nested_tag->scope) : 0;
+
+					/* Nested tags have longer scope than the parent - once the scope
+					 * is equal or lower than the parent scope, we are outside the tag's
+					 * scope. */
+					if (nested_scope_len <= scope_len)
+						break;
+				}
+
+				/* We are out of the nesting - the next tag could be a typedef */
+				if (j < source_file->tags_array->len)
+				{
+					TMTag *typedef_tag = TM_TAG(source_file->tags_array->pdata[j]);
+					guint typedef_scope_len = typedef_tag->scope ? strlen(typedef_tag->scope) : 0;
+
+					/* Should be at the same scope level as the anon tag */
+					if (typedef_tag->type == tm_tag_typedef_t &&
+						typedef_scope_len == scope_len &&
+						g_strcmp0(typedef_tag->var_type, tag->name) == 0)
+					{
+						/* set the name of the original anon tag and pretend
+						 * it wasn't a anon tag */
+						tag->name = g_strdup(typedef_tag->name);
+						tag->flags &= ~tm_tag_flag_anon_t;
+						new_name = tag->name;
+						/* the typedef tag will be removed */
+						if (!removed_typedefs)
+							removed_typedefs = g_ptr_array_new();
+						g_ptr_array_add(removed_typedefs, GUINT_TO_POINTER(j));
+					}
+				}
+			}
+
+			/* there's no typedef name for the anon tag so let's generate one  */
+			if (!new_name)
+			{
+				gchar buf[50];
+				guint anon_counter;
+				const gchar *kind_name = tm_ctags_get_kind_name(kind, tag->lang);
+
+				if (!anon_counter_table)
+					anon_counter_table = g_new0(gint, 256);
+
+				anon_counter = ++anon_counter_table[kind];
+
+				sprintf(buf, "anon_%s_%u", kind_name, anon_counter);
+				tag->name = g_strdup(buf);
+				new_name = tag->name;
+			}
+
+			new_name_len = strlen(new_name);
+
+			/* Check if this tag is parent of some other tag - if so, we have to
+			 * update the scope. It can only be parent of the following tags
+			 * so start with the next tag. */
+			for (j = i + 1; j < source_file->tags_array->len; j++)
+			{
+				TMTag *nested_tag = TM_TAG(source_file->tags_array->pdata[j]);
+				guint nested_scope_len = nested_tag->scope ? strlen(nested_tag->scope) : 0;
+				gchar *pos;
+
+				/* Terminate if outside of tag scope, see above */
+				if (nested_scope_len <= scope_len)
+					break;
+
+				pos = strstr(nested_tag->scope, orig_name);
+				/* We found the parent name in the nested tag scope - replace it
+				 * with the new name. Note: anonymous tag names generated by
+				 * ctags are unique enough that we don't have to check for
+				 * scope separators here. */
+				if (pos)
+				{
+					gchar *str = g_malloc(nested_scope_len + 50);
+					guint prefix_len = pos - nested_tag->scope;
+
+					strncpy(str, nested_tag->scope, prefix_len);
+					strcpy(str + prefix_len, new_name);
+					strcpy(str + prefix_len + new_name_len, pos + orig_name_len);
+					g_free(nested_tag->scope);
+					nested_tag->scope = str;
+				}
+			}
+
+			g_free(orig_name);
+		}
+	}
+
+	if (removed_typedefs)
+	{
+		for (i = 0; i < removed_typedefs->len; i++)
+		{
+			guint j = GPOINTER_TO_UINT(removed_typedefs->pdata[i]);
+			TMTag *tag = TM_TAG(source_file->tags_array->pdata[j]);
+			tm_tag_unref(tag);
+			source_file->tags_array->pdata[j] = NULL;
+		}
+
+		/* remove NULL entries from the array */
+		tm_tags_prune(source_file->tags_array);
+
+		g_ptr_array_free(removed_typedefs, TRUE);
+	}
+
+	if (anon_counter_table)
+		g_free(anon_counter_table);
+}
+
+
 void tm_ctags_parse(guchar *buffer, gsize buffer_size,
 	const gchar *file_name, TMParserType language, TMSourceFile *source_file)
 {
 	g_return_if_fail(buffer != NULL || file_name != NULL);
 
 	parseRawBuffer(file_name, buffer, buffer_size, language, source_file);
+
+	rename_anon_tags(source_file);
 }
 
 


Modified: src/tagmanager/tm_source_file.c
5 lines changed, 3 insertions(+), 2 deletions(-)
===================================================================
@@ -383,9 +383,10 @@ static gboolean init_tag_from_file_ctags(TMTag *tag, TMSourceFile *file, FILE *f
 				const gchar *kind = value ? value : key;
 
 				if (kind[0] && kind[1])
-					tag->type = tm_parser_get_tag_type(tm_ctags_get_kind_from_name(kind, lang), lang);
+					tag->kind_letter = tm_ctags_get_kind_from_name(kind, lang);
 				else
-					tag->type = tm_parser_get_tag_type(*kind, lang);
+					tag->kind_letter = *kind;
+				tag->type = tm_parser_get_tag_type(tag->kind_letter, lang);
 			}
 			else if (0 == strcmp(key, "inherits")) /* comma-separated list of classes this class inherits from */
 			{


Modified: src/tagmanager/tm_tag.h
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -109,6 +109,7 @@ typedef struct TMTag
 	char access; /**< Access type (public/protected/private/etc.) */
 	char impl; /**< Implementation (e.g. virtual) */
 	TMParserType lang; /* Programming language of the file */
+	gchar kind_letter; /* Kind letter from ctags */
 } TMTag;
 
 /* The GType for a TMTag */



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Commits mailing list