mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
Merge pull request #1710 from benrfairless/fix/ruby-namespaced-constructor-callee
fix(extraction): reduce A::B.new callee to the constant
This commit is contained in:
2 files changed
+57
-1
No files matched your search
@@ -2249,11 +2249,15 @@ static char *extract_callee_name(CBMArena *a, TSNode node, const char *source, C
|
||||
// method is `new`. The constructor body lives in `initialize`, so a callee
|
||||
// of "new" never resolves. Redirect to the receiver type name so the call
|
||||
// links to the class/constructor like every other language's `new T()`.
|
||||
// Scope-resolved receivers (`Admin::User.new`) get the same treatment —
|
||||
// the callee carries the full constant path ("Admin::User"), whose bare
|
||||
// leaf ("User") is what resolution joins on.
|
||||
if (lang == CBM_LANG_RUBY) {
|
||||
TSNode m = ts_node_child_by_field_name(node, TS_FIELD("method"));
|
||||
TSNode recv = ts_node_child_by_field_name(node, TS_FIELD("receiver"));
|
||||
if (!ts_node_is_null(m) && !ts_node_is_null(recv) &&
|
||||
strcmp(ts_node_type(recv), "constant") == 0) {
|
||||
(strcmp(ts_node_type(recv), "constant") == 0 ||
|
||||
strcmp(ts_node_type(recv), "scope_resolution") == 0)) {
|
||||
char *mt = cbm_node_text(a, m, source);
|
||||
if (mt && strcmp(mt, "new") == 0) {
|
||||
char *rt = cbm_node_text(a, recv, source);
|
||||
|
||||
@@ -857,6 +857,57 @@ TEST(ruby_module) {
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* A Ruby `Const.new` call is rewritten to name the CONSTANT, not the method:
|
||||
* the constructor body lives in `initialize`, so the call should link the class
|
||||
* like every other language's `new T()`. The rewrite fired only for bare
|
||||
* `constant` receivers, so a scope-resolved receiver kept the whole call text
|
||||
* as its callee ("Admin::User.new"), which resolves to nothing and cannot join
|
||||
* the Ruby LSP's constructor rows, whose callee is the class QN.
|
||||
*
|
||||
* Both spellings must land on the bare constant path; a retained ".new" suffix
|
||||
* is the bug's signature. */
|
||||
TEST(ruby_constructor_callee_is_constant_path) {
|
||||
CBMFileResult *r = extract("module Admin\n class User\n end\nend\n"
|
||||
"class Widget\nend\n"
|
||||
"class Maker\n"
|
||||
" def build\n"
|
||||
" Admin::User.new\n"
|
||||
" Widget.new\n"
|
||||
" end\n"
|
||||
"end\n",
|
||||
CBM_LANG_RUBY, "t", "maker.rb");
|
||||
ASSERT_NOT_NULL(r);
|
||||
ASSERT_FALSE(r->has_error);
|
||||
|
||||
int scoped = 0, bare = 0, kept_new = 0;
|
||||
for (int i = 0; i < r->calls.count; i++) {
|
||||
const char *callee = r->calls.items[i].callee_name;
|
||||
if (strcmp(callee, "Admin::User") == 0)
|
||||
scoped = 1;
|
||||
if (strcmp(callee, "Widget") == 0)
|
||||
bare = 1;
|
||||
/* Either failure mode: the method name survived on its own, or the
|
||||
* whole `Recv.new` expression did. */
|
||||
size_t n = strlen(callee);
|
||||
if (strcmp(callee, "new") == 0 || (n >= 4 && strcmp(callee + n - 4, ".new") == 0))
|
||||
kept_new = 1;
|
||||
}
|
||||
if (!scoped || !bare || kept_new) {
|
||||
printf(" ruby callees (%d):\n", r->calls.count);
|
||||
for (int i = 0; i < r->calls.count; i++)
|
||||
printf(" '%s'\n", r->calls.items[i].callee_name);
|
||||
}
|
||||
/* Scope-resolved receiver reduces to the constant path; its bare leaf is
|
||||
* what resolution joins on. */
|
||||
ASSERT(scoped);
|
||||
/* Bare receiver: pre-existing behaviour, guarded against regression. */
|
||||
ASSERT(bare);
|
||||
ASSERT_FALSE(kept_new);
|
||||
|
||||
cbm_free_result(r);
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* --- C# --- */
|
||||
TEST(csharp_class) {
|
||||
CBMFileResult *r = extract("namespace App { public class Service { public void Run() {} public "
|
||||
@@ -13493,6 +13544,7 @@ SUITE(extraction) {
|
||||
RUN_TEST(php_function);
|
||||
RUN_TEST(ruby_class);
|
||||
RUN_TEST(ruby_module);
|
||||
RUN_TEST(ruby_constructor_callee_is_constant_path);
|
||||
RUN_TEST(csharp_class);
|
||||
RUN_TEST(csharp_interface);
|
||||
RUN_TEST(csharp_extension_block_members);
|
||||
|
||||
Reference in new issue
Block a user