diff --git a/internal/cbm/doclink_go.c b/internal/cbm/doclink_go.c
index 97dab618d..aeb0c5858 100644
--- a/internal/cbm/doclink_go.c
+++ b/internal/cbm/doclink_go.c
@@ -43,10 +43,10 @@
* drops these lines and so carries no line number
* at all.
* G path go.mod: the module path
- * w says who keeps the node. A Go method node has a FLAT qualified name
- * (
.), so a function, the methods of every receiver, a type and
- * a value of one name all claim the node ., and within a file the
- * declaration on the LAST line keeps it (cbm_gbuf_upsert_node). w is 1 for
+ * w says who keeps the node .. A function, a type and a value of
+ * one name all claim it, and within a file the declaration on the LAST line
+ * keeps it (cbm_gbuf_upsert_node). A method claims nothing: its node is
+ * receiver-qualified (.., #1913), and its w is `-`. w is 1 for
* that declaration, 0 for the others of that name, x when two of them start
* on that last line, and - for a value the extractor gives no node at all
* (it gives one to the first name of a constant spec and of a parenthesis-
@@ -1511,9 +1511,11 @@ static void go_scan_method(go_scan_t *s, TSNode m) {
recv = "?";
recv_len = SKIP_ONE;
}
- go_push_claim(s,
- cbm_arena_sprintf(s->tmp, "M\t%.*s\t%.*s", (int)recv_len, recv, (int)len, name),
- name, len, m);
+ /* #1913: a Go method node is receiver-qualified (..),
+ * so a method claims no flat name: w is `-`, and the method is found
+ * through its receiver (the member table), never through .. */
+ (void)go_push_rec(
+ s, cbm_arena_sprintf(s->tmp, "M\t%.*s\t%.*s\t-", (int)recv_len, recv, (int)len, name));
}
/* The implied name of an embedded field: the type's own name, without
diff --git a/src/pipeline/doc_links_go.c b/src/pipeline/doc_links_go.c
index 047a7654e..b43289c95 100644
--- a/src/pipeline/doc_links_go.c
+++ b/src/pipeline/doc_links_go.c
@@ -32,10 +32,11 @@
* fields of its own struct declaration and the methods of its own interface
* declaration: nothing promoted through embedding.
*
- * Binding. The graph keeps one node per qualified name, Go method nodes have
- * a FLAT name (.), and is the directory, not the package
- * clause: functions, methods of every receiver, types and values of one name,
- * in every file of the directory, share one node, and the node is ONE of those
+ * Binding. The graph keeps one node per qualified name, and is the
+ * directory, not the package clause. Go method nodes are receiver-qualified
+ * (.., #1913) and are found through their receiver only.
+ * Functions, types and values of one name, in every file of the directory,
+ * share one node ., and the node is ONE of those
* declarations (cbm_gbuf_upsert_node keeps the smallest file path, then the
* last line). So a reference binds only when the node IS the entity it names:
* the node's file is a file of the named package, the declaration that keeps
@@ -59,7 +60,7 @@
* not), missing (a repository package that does not declare the name; an
* import path inside a module without a package there), graph_gap (declared,
* but the node is another declaration's or absent: block variables, later
- * names of a declaration, embedded fields, methods that lost the flat name;
+ * names of a declaration, embedded fields;
* also an undeclared name in a package with a parse error), test_only_target
* (product code naming a declaration that only test files have), ambiguous
* (several modules or packages fit; a name declared as two kinds; a name two
@@ -1063,7 +1064,7 @@ static void go_record_decl(go_index_t *ix, go_file_t *file, char **f, int nf) {
FIELD_FIELDS = 4,
IM_FIELDS = 3
};
- enum { F_OWNER = 2, T_ALIAS = 3, T_OWNER = 4, V_OWNER = 2, M_OWNER = 3, FIELD_NODE = 3 };
+ enum { F_OWNER = 2, T_ALIAS = 3, T_OWNER = 4, V_OWNER = 2, FIELD_NODE = 3 };
char kind = f[0][0];
if (nf < IM_FIELDS || !go_name_ok(f[SKIP_ONE])) {
return;
@@ -1078,10 +1079,12 @@ static void go_record_decl(go_index_t *ix, go_file_t *file, char **f, int nf) {
go_add_sym(ix, file, GO_KIND_VALUE, f[SKIP_ONE], NULL);
go_add_claim(ix, file, GO_KIND_VALUE, f[SKIP_ONE], NULL, f[V_OWNER]);
} else if (kind == 'M' && nf == M_FIELDS && go_name_ok(f[PAIR_LEN])) {
+ /* #1913: a method is found through its receiver only; it claims no
+ * flat . (its record says w `-`), so a type, function or
+ * value of the same name keeps that node. */
if (strcmp(f[SKIP_ONE], "?") != 0) {
go_add_member(ix, file, GO_MEM_METHOD, f[SKIP_ONE], f[PAIR_LEN], true);
}
- go_add_claim(ix, file, GO_KIND_METHOD, f[PAIR_LEN], f[SKIP_ONE], f[M_OWNER]);
} else if (kind == 'f' && nf == FIELD_FIELDS && go_name_ok(f[PAIR_LEN])) {
go_add_member(ix, file, GO_MEM_FIELD, f[SKIP_ONE], f[PAIR_LEN], f[FIELD_NODE][0] == '1');
} else if (kind == 'm' && nf == IM_FIELDS && go_name_ok(f[PAIR_LEN])) {
@@ -1342,9 +1345,9 @@ static const cbm_gbuf_node_t *go_member_node(const go_ctx_t *c, const go_pkg_t *
return (fm && (fm->node_kinds & kind)) ? n : NULL;
}
-/* The node of the method `recv.name`: its receiver-qualified node, else the
- * flat node . when the method is the one that kept it (the last
- * declaration of that name in the node's file). */
+/* The node of the method `recv.name`: its receiver-qualified node. The flat
+ * fallback below (the method that kept .) is unreachable since
+ * #1913: no method record claims a flat name any more. */
static const cbm_gbuf_node_t *go_method_node(const go_ctx_t *c, const go_pkg_t *pkg, go_str_t recv,
go_str_t name) {
const cbm_gbuf_node_t *qualified = go_member_node(c, pkg, GO_MEM_METHOD, recv, name);