fix(kotlin): a callable reference inside a larger value stays a usage

Only a direct argument, parenthesized value, standalone reference or initializer hands over one callable. Branches and pairs do not, which is what this test required before it was flipped and what a Java ternary does. A Go result annotation is USES_TYPE alone, like TypeScript, so its USAGE row goes.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
Martin Vogel committed 2026-11-01 21:31:50 +01:00
1 parent ee9fc6a0e6
commit 8aabc9e943
3 files changed
+38 -41

No files matched your search

+8 -7
View File
@@ -2751,16 +2751,17 @@ static oo_value_t kw_this(kw_t *k, TSNode node) {
return oo_value_unknown();
}
/* `if (c) ::a else ::b` selects at run time, so neither branch is the one callable this
* occurrence hands over. Each stays an ordinary reference to what it names. */
static bool kw_reference_is_branch_alternative(TSNode reference) {
/* `if (c) ::a else ::b` selects at run time and `"k" to ::a` builds a larger value, so the
* leaf is not the one callable this occurrence hands over. It stays an ordinary reference
* to what it names, as a Java ternary's alternatives do. */
static bool kw_reference_is_composite_leaf(TSNode reference) {
for (TSNode parent = ts_node_parent(reference); !ts_node_is_null(parent);
parent = ts_node_parent(parent)) {
if (kt_is(parent, "if_expression") || kt_is(parent, "when_expression") ||
kt_is(parent, "elvis_expression"))
kt_is(parent, "elvis_expression") || kt_is(parent, "infix_expression"))
return true;
if (kt_is(parent, "value_arguments") || kt_is(parent, "assignment") ||
kt_is(parent, "property_declaration"))
kt_is(parent, "property_declaration") || kt_is(parent, "statements"))
return false;
}
return false;
@@ -2813,8 +2814,8 @@ static oo_value_t kw_callable_reference(kw_t *k, TSNode node) {
}
if (target && target->graph_qn)
oo_emit_usage(w, member, target->graph_qn,
kw_reference_is_branch_alternative(node) ? CBM_RESOLVED_VALUE_REFERENCE
: CBM_RESOLVED_CALL_REFERENCE,
kw_reference_is_composite_leaf(node) ? CBM_RESOLVED_VALUE_REFERENCE
: CBM_RESOLVED_CALL_REFERENCE,
CBM_RESOLVE_RULE_TYPE_MEMBER, "kotlin-callable-reference");
return oo_value_unknown();
}
-2
View File
@@ -522,8 +522,6 @@ static const LRP_Golden LRP_GOLDEN[] = {
"declaration must not be replaced by a name-only target.",
"Prior exact fixture audit: expected target absent; read-only trace of exact fixture and the "
"cited source proof guard. Legacy confidence/name matches were not accepted."},
{"lrp_go_usage_struct_literal", "main.go", "Make", "Config", 0, "types.go", "Config", "USAGE",
3, "type Config struct{ Port int }", true, false, NULL, NULL},
{"lrp_go_usage_struct_literal", "main.go", "Make", "Config", 1, "types.go", "Config", "USAGE",
3, "type Config struct{ Port int }", true, false, NULL, NULL},
/* A key of a struct literal must name a field of that struct (Go spec, composite literals). */
+30 -32
View File
@@ -1282,20 +1282,18 @@ static const RQ_Source KOTLIN_COMPOSITE_SOURCES[] = {
.text = "fun acceptMap(value: Any) {}\nfun mapped() { acceptMap(mapOf(\"first\" to ::handler, "
"\"second\" to ::alternate)) }\n"},
{.path = "Decoy.kt", .text = "package other\nfun handler() {}\nfun alternate() {}\n"}};
/* `::handler` is a callable reference wherever it stands: nesting it in an `if` or a
* pair's argument does not change what the syntax says. */
static const RQ_Expected KOTLIN_COMPOSITE_EXPECTED[] = {
{.case_id = "complex-handler-CALL_REFERENCE",
{.case_id = "complex-handler-USAGE",
.site = {.file = "Main.kt", .caller = "complex", .start_byte = 120, .end_byte = 127},
.relation = "CALL_REFERENCE",
.relation = "USAGE",
.target = {.file = "Main.kt",
.suffix = "Main.handler",
.label = "Function",
.declaration_line = 1,
.declaration_text = "fun handler() {}"}},
{.case_id = "complex-alternate-CALL_REFERENCE",
{.case_id = "complex-alternate-USAGE",
.site = {.file = "Main.kt", .caller = "complex", .start_byte = 135, .end_byte = 144},
.relation = "CALL_REFERENCE",
.relation = "USAGE",
.target = {.file = "Main.kt",
.suffix = "Main.alternate",
.label = "Function",
@@ -1309,17 +1307,17 @@ static const RQ_Expected KOTLIN_COMPOSITE_EXPECTED[] = {
.label = "Function",
.declaration_line = 3,
.declaration_text = "fun accept(callback: () -> Unit) {}"}},
{.case_id = "wrapped-handler-CALL_REFERENCE",
{.case_id = "wrapped-handler-USAGE",
.site = {.file = "Main.kt", .caller = "wrapped", .start_byte = 197, .end_byte = 204},
.relation = "CALL_REFERENCE",
.relation = "USAGE",
.target = {.file = "Main.kt",
.suffix = "Main.handler",
.label = "Function",
.declaration_line = 1,
.declaration_text = "fun handler() {}"}},
{.case_id = "wrapped-alternate-CALL_REFERENCE",
{.case_id = "wrapped-alternate-USAGE",
.site = {.file = "Main.kt", .caller = "wrapped", .start_byte = 212, .end_byte = 221},
.relation = "CALL_REFERENCE",
.relation = "USAGE",
.target = {.file = "Main.kt",
.suffix = "Main.alternate",
.label = "Function",
@@ -1389,17 +1387,17 @@ static const RQ_Expected KOTLIN_COMPOSITE_EXPECTED[] = {
.label = "Function",
.declaration_line = 1,
.declaration_text = "fun handler() {}"}},
{.case_id = "mapped-handler-CALL_REFERENCE",
{.case_id = "mapped-handler-USAGE",
.site = {.file = "Mapped.kt", .caller = "mapped", .start_byte = 73, .end_byte = 80},
.relation = "CALL_REFERENCE",
.relation = "USAGE",
.target = {.file = "Main.kt",
.suffix = "Main.handler",
.label = "Function",
.declaration_line = 1,
.declaration_text = "fun handler() {}"}},
{.case_id = "mapped-alternate-CALL_REFERENCE",
{.case_id = "mapped-alternate-USAGE",
.site = {.file = "Mapped.kt", .caller = "mapped", .start_byte = 96, .end_byte = 105},
.relation = "CALL_REFERENCE",
.relation = "USAGE",
.target = {.file = "Main.kt",
.suffix = "Main.alternate",
.label = "Function",
@@ -1414,37 +1412,37 @@ static const RQ_Expected KOTLIN_COMPOSITE_EXPECTED[] = {
.declaration_line = 1,
.declaration_text = "fun acceptMap(value: Any) {}"}}};
static const RQ_Forbidden KOTLIN_COMPOSITE_FORBIDDEN[] = {
{.case_id = "complex-handler-CALL_REFERENCE-forbid-CALLS",
{.case_id = "complex-handler-USAGE-forbid-CALLS",
.site = {.file = "Main.kt", .caller = "complex", .start_byte = 120, .end_byte = 127},
.relation = "CALLS",
.any_target = true},
{.case_id = "complex-handler-CALL_REFERENCE-forbid-USAGE",
{.case_id = "complex-handler-USAGE-forbid-CALL_REFERENCE",
.site = {.file = "Main.kt", .caller = "complex", .start_byte = 120, .end_byte = 127},
.relation = "USAGE",
.relation = "CALL_REFERENCE",
.any_target = true},
{.case_id = "complex-alternate-CALL_REFERENCE-forbid-CALLS",
{.case_id = "complex-alternate-USAGE-forbid-CALLS",
.site = {.file = "Main.kt", .caller = "complex", .start_byte = 135, .end_byte = 144},
.relation = "CALLS",
.any_target = true},
{.case_id = "complex-alternate-CALL_REFERENCE-forbid-USAGE",
{.case_id = "complex-alternate-USAGE-forbid-CALL_REFERENCE",
.site = {.file = "Main.kt", .caller = "complex", .start_byte = 135, .end_byte = 144},
.relation = "USAGE",
.relation = "CALL_REFERENCE",
.any_target = true},
{.case_id = "wrapped-handler-CALL_REFERENCE-forbid-CALLS",
{.case_id = "wrapped-handler-USAGE-forbid-CALLS",
.site = {.file = "Main.kt", .caller = "wrapped", .start_byte = 197, .end_byte = 204},
.relation = "CALLS",
.any_target = true},
{.case_id = "wrapped-handler-CALL_REFERENCE-forbid-USAGE",
{.case_id = "wrapped-handler-USAGE-forbid-CALL_REFERENCE",
.site = {.file = "Main.kt", .caller = "wrapped", .start_byte = 197, .end_byte = 204},
.relation = "USAGE",
.relation = "CALL_REFERENCE",
.any_target = true},
{.case_id = "wrapped-alternate-CALL_REFERENCE-forbid-CALLS",
{.case_id = "wrapped-alternate-USAGE-forbid-CALLS",
.site = {.file = "Main.kt", .caller = "wrapped", .start_byte = 212, .end_byte = 221},
.relation = "CALLS",
.any_target = true},
{.case_id = "wrapped-alternate-CALL_REFERENCE-forbid-USAGE",
{.case_id = "wrapped-alternate-USAGE-forbid-CALL_REFERENCE",
.site = {.file = "Main.kt", .caller = "wrapped", .start_byte = 212, .end_byte = 221},
.relation = "USAGE",
.relation = "CALL_REFERENCE",
.any_target = true},
{.case_id = "direct-handler-CALL_REFERENCE-forbid-CALLS",
.site = {.file = "Main.kt", .caller = "direct", .start_byte = 250, .end_byte = 257},
@@ -1478,21 +1476,21 @@ static const RQ_Forbidden KOTLIN_COMPOSITE_FORBIDDEN[] = {
.site = {.file = "Main.kt", .caller = "immutable", .start_byte = 371, .end_byte = 378},
.relation = "USAGE",
.any_target = true},
{.case_id = "mapped-handler-CALL_REFERENCE-forbid-CALLS",
{.case_id = "mapped-handler-USAGE-forbid-CALLS",
.site = {.file = "Mapped.kt", .caller = "mapped", .start_byte = 73, .end_byte = 80},
.relation = "CALLS",
.any_target = true},
{.case_id = "mapped-handler-CALL_REFERENCE-forbid-USAGE",
{.case_id = "mapped-handler-USAGE-forbid-CALL_REFERENCE",
.site = {.file = "Mapped.kt", .caller = "mapped", .start_byte = 73, .end_byte = 80},
.relation = "USAGE",
.relation = "CALL_REFERENCE",
.any_target = true},
{.case_id = "mapped-alternate-CALL_REFERENCE-forbid-CALLS",
{.case_id = "mapped-alternate-USAGE-forbid-CALLS",
.site = {.file = "Mapped.kt", .caller = "mapped", .start_byte = 96, .end_byte = 105},
.relation = "CALLS",
.any_target = true},
{.case_id = "mapped-alternate-CALL_REFERENCE-forbid-USAGE",
{.case_id = "mapped-alternate-USAGE-forbid-CALL_REFERENCE",
.site = {.file = "Mapped.kt", .caller = "mapped", .start_byte = 96, .end_byte = 105},
.relation = "USAGE",
.relation = "CALL_REFERENCE",
.any_target = true}};
TEST(resolver_kotlin_composite_reference_raw_occurrences_stay_values) {