[geany/geany] 932dc7: Don't use struct/class/... member types when the edited text isn't a member

Jiří Techet git-noreply at xxxxx
Thu Feb 11 14:35:56 UTC 2016


Branch:      refs/heads/master
Author:      Jiří Techet <techet at gmail.com>
Committer:   Jiří Techet <techet at gmail.com>
Date:        Mon, 18 Jan 2016 21:55:02 UTC
Commit:      932dc71fe2edc0c58b15aface319d38855c5e612
             https://github.com/geany/geany/commit/932dc71fe2edc0c58b15aface319d38855c5e612

Log Message:
-----------
Don't use struct/class/... member types when the edited text isn't a member

For instance, consider

class A {
    int a;
    int b;
}

class B {
    A c;
    void foo() {
        c.    //<---- (3)
    }
}

int main() {
    c.    //<---- (1)
    foo.c.    //<---- (2)
}

Consider cases (1) and (2) first - in the case (1) scope completion
shouldn't be performed because c isn't a global variable; however,
in case (2) it should be performed because c is a member.

To fix this, we can check whether the typed variable ('c' in this case)
is preceeded by another dot - if it is, use member tags for scope
completion; otherwise don't use them.

There's one exception from this rule - in the case (3) we are accessing
a member variable from a member function at the same scope so the
function should have access to the variable. For this we can use the
scope at the position of the cursor. It should be

B::foo

in this case, more generally ...::class_name::function_name. We need
to check if class_name exists at the given scope and if the member
variable we are trying to access is inside ...::class_name - if so,
scope completion can be performed using member tags (without explicit
invocation on a member).


Modified Paths:
--------------
    src/editor.c
    tagmanager/src/tm_workspace.c
    tagmanager/src/tm_workspace.h

Modified: src/editor.c
14 lines changed, 13 insertions(+), 1 deletions(-)
===================================================================
@@ -708,6 +708,8 @@ static void autocomplete_scope(GeanyEditor *editor)
 	GeanyFiletype *ft = editor->document->file_type;
 	GPtrArray *tags;
 	gboolean function = FALSE;
+	gboolean member;
+	const gchar *current_scope;
 
 	if (typed == '.')
 		pos -= 1;
@@ -751,7 +753,17 @@ static void autocomplete_scope(GeanyEditor *editor)
 	if (!name)
 		return;
 
-	tags = tm_workspace_find_scope_members(editor->document->tm_file, name, function);
+	/* check if invoked on member */
+	pos -= strlen(name);
+	while (pos > 0 && isspace(sci_get_char_at(sci, pos - 1)))
+		pos--;
+	member = match_last_chars(sci, pos, ".") || match_last_chars(sci, pos, "::") ||
+			 match_last_chars(sci, pos, "->") || match_last_chars(sci, pos, "->*");
+
+	if (symbols_get_current_scope(editor->document, &current_scope) == -1)
+		current_scope = "";
+	tags = tm_workspace_find_scope_members(editor->document->tm_file, name, function,
+				member, current_scope);
 	if (tags)
 	{
 		show_tags_list(editor, tags, 0);


Modified: tagmanager/src/tm_workspace.c
88 lines changed, 77 insertions(+), 11 deletions(-)
===================================================================
@@ -877,9 +877,60 @@ find_scope_members (const GPtrArray *tags_array, const char *name, langType lang
 }
 
 
+/* Checks whether a member tag is directly accessible from method with method_scope */
+static gboolean member_at_method_scope(const GPtrArray *tags, const gchar *method_scope, TMTag *member_tag,
+	langType lang)
+{
+	const gchar *sep = tm_tag_context_separator(lang);
+	gboolean ret = FALSE;
+	gchar **comps;
+	guint len;
+
+	/* method scope is in the form ...::class_name::method_name */
+	comps = g_strsplit (method_scope, sep, 0);
+	len = g_strv_length(comps);
+	if (len > 1)
+	{
+		gchar *method, *member_scope, *cls, *cls_scope;
+
+		/* get method/member scope */
+		method = comps[len - 1];
+		comps[len - 1] = NULL;
+		member_scope = g_strjoinv(sep, comps);
+		comps[len - 1] = method;
+
+		/* get class scope */
+		cls = comps[len - 2];
+		comps[len - 2] = NULL;
+		cls_scope = g_strjoinv(sep, comps);
+		comps[len - 2] = cls;
+
+		/* check whether member inside the class */
+		if (g_strcmp0(member_tag->scope, member_scope) == 0)
+		{
+			const GPtrArray *src = member_tag->file ? member_tag->file->tags_array : tags;
+			GPtrArray *cls_tags = g_ptr_array_new();
+
+			/* check whether the class exists */
+			fill_find_tags_array(cls_tags, src, cls, cls_scope,
+				tm_tag_class_t | tm_tag_struct_t | tm_tag_interface_t, FALSE, lang);
+			ret = cls_tags->len > 0;
+			g_ptr_array_free(cls_tags, TRUE);
+		}
+
+		g_free(cls_scope);
+		g_free(member_scope);
+	}
+
+	g_strfreev(comps);
+	return ret;
+}
+
+
 /* For an array of variable/type tags, find members inside the types */
 static GPtrArray *
-find_scope_members_all(const GPtrArray *tags, const GPtrArray *searched_array, langType lang)
+find_scope_members_all(const GPtrArray *tags, const GPtrArray *searched_array, langType lang,
+	gboolean member, const gchar *current_scope)
 {
 	GPtrArray *member_tags = NULL;
 	guint i;
@@ -896,13 +947,22 @@ find_scope_members_all(const GPtrArray *tags, const GPtrArray *searched_array, l
 			member_tags = find_scope_members(searched_array, tag->name, lang, TRUE);
 		else if (tag->var_type)  /* variable: scope search */
 		{
-			gchar *tag_type = g_strdup(tag->var_type);
+			/* The question now is whether we should use member tags (such as
+			 * tm_tag_field_t, tm_tag_member_t) or not. We want them if member==TRUE
+			 * (which means user has typed something like foo.bar.) or if we are
+			 * inside a method where foo is a class member, we want scope completion
+			 * for foo. */
+			if (!(tag->type & (tm_tag_field_t | tm_tag_member_t)) || member ||
+				member_at_method_scope(tags, current_scope, tag, lang))
+			{
+				gchar *tag_type = g_strdup(tag->var_type);
 
-			/* remove pointers in case the type contains them */
-			g_strdelimit(tag_type, "*^", ' ');
-			g_strstrip(tag_type);
-			member_tags = find_scope_members(searched_array, tag_type, lang, FALSE);
-			g_free(tag_type);
+				/* remove pointers in case the type contains them */
+				g_strdelimit(tag_type, "*^", ' ');
+				g_strstrip(tag_type);
+				member_tags = find_scope_members(searched_array, tag_type, lang, FALSE);
+				g_free(tag_type);
+			}
 		}
 	}
 
@@ -915,9 +975,12 @@ find_scope_members_all(const GPtrArray *tags, const GPtrArray *searched_array, l
  @param source_file TMSourceFile of the edited source file or NULL if not available
  @param name Name of the variable/type whose members are searched
  @param function TRUE if the name is a name of a function
+ @param member TRUE if invoked on class/struct member (e.g. after the last dot in foo.bar.)
+ @param current_scope The current scope in the editor
  @return A GPtrArray of TMTag pointers to struct/union/class members or NULL when not found */
 GPtrArray *
-tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name, gboolean function)
+tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name,
+	gboolean function, gboolean member, const gchar *current_scope)
 {
 	langType lang = source_file ? source_file->lang : -1;
 	GPtrArray *tags, *member_tags = NULL;
@@ -936,11 +999,14 @@ tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name, gb
 	 * end with global tags. This way we find the "closest" tag to the current
 	 * file in case there are more of them. */
 	if (source_file)
-		member_tags = find_scope_members_all(tags, source_file->tags_array, lang);
+		member_tags = find_scope_members_all(tags, source_file->tags_array,
+											 lang, member, current_scope);
 	if (!member_tags)
-		member_tags = find_scope_members_all(tags, theWorkspace->tags_array, lang);
+		member_tags = find_scope_members_all(tags, theWorkspace->tags_array, lang,
+											 member, current_scope);
 	if (!member_tags)
-		member_tags = find_scope_members_all(tags, theWorkspace->global_tags, lang);
+		member_tags = find_scope_members_all(tags, theWorkspace->global_tags, lang,
+											 member, current_scope);
 
 	g_ptr_array_free(tags, TRUE);
 


Modified: tagmanager/src/tm_workspace.h
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -59,7 +59,7 @@ GPtrArray *tm_workspace_find(const char *name, const char *scope, TMTagType type
 	TMTagAttrType *attrs, gboolean partial, langType lang);
 
 GPtrArray *tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name,
-	gboolean function);
+	gboolean function, gboolean member, const gchar *current_scope);
 
 
 void tm_workspace_add_source_file_noupdate(TMSourceFile *source_file);



--------------
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