Skip to content

Commit ffb5ebe

Browse files
authored
Merge pull request #1721 from henry-hz/upstream-pr/elixir-call-arguments
fix(elixir): populate first_string_arg for Elixir calls
2 parents 8e1de04 + dc703da commit ffb5ebe

2 files changed

Lines changed: 54 additions & 0 deletions

File tree

‎internal/cbm/extract_calls.c‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,17 @@ static char *extract_objc_callee(CBMArena *a, TSNode node, const char *source, c
529529
return ts_node_is_null(selector) ? NULL : cbm_node_text(a, selector, source);
530530
}
531531

532+
/* tree-sitter-elixir gives a call's arguments node no field name, so it is
533+
* found positionally. Mirrors elixir_call_args() in extract_defs.c, which the
534+
* definition side has always used for the same reason. */
535+
static TSNode elixir_call_arguments_fallback(TSNode node) {
536+
TSNode args = ts_node_child_by_field_name(node, TS_FIELD("arguments"));
537+
if (ts_node_is_null(args) && ts_node_child_count(node) > 1) {
538+
args = ts_node_child(node, 1);
539+
}
540+
return args;
541+
}
542+
532543
// Erlang: extract callee from call node's first child.
533544
static char *extract_erlang_callee(CBMArena *a, TSNode node, const char *source, const char *nk) {
534545
if (strcmp(nk, "call") != 0 || ts_node_child_count(node) == 0) {
@@ -3697,6 +3708,21 @@ CBMInvocationDescriptor handle_calls(CBMExtractCtx *ctx, TSNode node, const CBML
36973708
}
36983709

36993710
TSNode args = ts_node_child_by_field_name(node, TS_FIELD("arguments"));
3711+
/* tree-sitter-elixir attaches NO field name to a call's arguments
3712+
* node — its whole field set is key, left, operand, operator,
3713+
* quoted_start, quoted_end, right, target, value — so the lookup
3714+
* above is always null for Elixir and first_string_arg was never
3715+
* populated for ANY Elixir call. That silently disabled every
3716+
* downstream signal keyed off a call's string argument: Phoenix
3717+
* route paths, HTTP/async service URLs, and config keys.
3718+
* cbm_elixir_call_args is the shared second-child fallback the
3719+
* definition side already uses. Restricted to `call` nodes —
3720+
* Elixir's other call kinds (`dot`, the `|>` binary_operator) have
3721+
* no arguments node in that position. */
3722+
if (ts_node_is_null(args) && ctx->language == CBM_LANG_ELIXIR &&
3723+
strcmp(ts_node_type(node), "call") == 0) {
3724+
args = elixir_call_arguments_fallback(node);
3725+
}
37003726
// ObjectScript stores args under oref_method/method_args, not the
37013727
// generic "arguments" field; macro arguments add one wrapper.
37023728
if (ts_node_is_null(args) && is_objectscript_language(ctx->language)) {

‎tests/test_extraction.c‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,33 @@ TEST(elixir_function) {
11481148
PASS();
11491149
}
11501150

1151+
/* tree-sitter-elixir gives a call's arguments node no field name, so the
1152+
* generic `arguments` field lookup returns null and first_string_arg was never
1153+
* populated for any Elixir call — Phoenix route paths, service URLs and config
1154+
* keys all key off it. */
1155+
TEST(elixir_call_string_argument) {
1156+
CBMFileResult *r = extract("defmodule Sample do\n"
1157+
" def run do\n"
1158+
" get(\"/wallets\", WalletController)\n"
1159+
" end\n"
1160+
"end\n",
1161+
CBM_LANG_ELIXIR, "t", "sample.ex");
1162+
ASSERT_NOT_NULL(r);
1163+
ASSERT_FALSE(r->has_error);
1164+
int seen = 0;
1165+
for (int i = 0; i < r->calls.count; i++) {
1166+
if (strcmp(r->calls.items[i].callee_name, "get") != 0) {
1167+
continue;
1168+
}
1169+
seen = 1;
1170+
ASSERT_NOT_NULL(r->calls.items[i].first_string_arg);
1171+
ASSERT_STR_EQ("/wallets", r->calls.items[i].first_string_arg);
1172+
}
1173+
ASSERT_EQ(1, seen);
1174+
cbm_free_result(r);
1175+
PASS();
1176+
}
1177+
11511178
/* --- Haskell --- */
11521179
TEST(haskell_function) {
11531180
CBMFileResult *r = extract("add :: Int -> Int -> Int\nadd x y = x + y\n\nmultiply :: Int -> "
@@ -7048,6 +7075,7 @@ SUITE(extraction) {
70487075

70497076
/* Functional */
70507077
RUN_TEST(elixir_function);
7078+
RUN_TEST(elixir_call_string_argument);
70517079
RUN_TEST(haskell_function);
70527080
RUN_TEST(ocaml_function);
70537081
RUN_TEST(erlang_function);

0 commit comments

Comments
 (0)