diff --git a/internal/cbm/lsp/oo_kotlin.c b/internal/cbm/lsp/oo_kotlin.c index a26986f6e..c5761964e 100644 --- a/internal/cbm/lsp/oo_kotlin.c +++ b/internal/cbm/lsp/oo_kotlin.c @@ -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(); } diff --git a/tests/test_lsp_resolution_probe.c b/tests/test_lsp_resolution_probe.c index 921151b5a..8bca057f5 100644 --- a/tests/test_lsp_resolution_probe.c +++ b/tests/test_lsp_resolution_probe.c @@ -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). */ diff --git a/tests/test_resolver_kotlin.c b/tests/test_resolver_kotlin.c index 01c282a4f..e3f50f36d 100644 --- a/tests/test_resolver_kotlin.c +++ b/tests/test_resolver_kotlin.c @@ -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) {