C++ operators represented by expression nodes are real invocations only when overload resolution finds a concrete function. Emit exact-occurrence raw candidates here; requires_lsp_resolution keeps primitive/pointer syntax from falling through to textual registry lookup and fabricating CALLS edges.
| 2388 | // candidates here; requires_lsp_resolution keeps primitive/pointer syntax from |
| 2389 | // falling through to textual registry lookup and fabricating CALLS edges. |
| 2390 | static void extract_cpp_operator_call(CBMExtractCtx *ctx, TSNode node, const char *kind, |
| 2391 | const char *enclosing_func_qn) { |
| 2392 | if (strcmp(kind, "subscript_expression") == 0) { |
| 2393 | TSNode receiver = ts_node_child_by_field_name(node, TS_FIELD("argument")); |
| 2394 | TSNode index = ts_node_child_by_field_name(node, TS_FIELD("index")); |
| 2395 | if (ts_node_is_null(receiver) && ts_node_named_child_count(node) > 0) { |
| 2396 | receiver = ts_node_named_child(node, 0); |
| 2397 | } |
| 2398 | if (ts_node_is_null(index) && ts_node_named_child_count(node) > 1) { |
| 2399 | index = ts_node_named_child(node, 1); |
| 2400 | } |
| 2401 | if (!ts_node_is_null(receiver) && !ts_node_is_null(index)) { |
| 2402 | push_cpp_semantic_call_candidate(ctx, node, "operator[]", enclosing_func_qn); |
| 2403 | } |
| 2404 | return; |
| 2405 | } |
| 2406 | |
| 2407 | if (strcmp(kind, "unary_expression") == 0 || strcmp(kind, "pointer_expression") == 0 || |
| 2408 | strcmp(kind, "update_expression") == 0) { |
| 2409 | TSNode operand = ts_node_child_by_field_name(node, TS_FIELD("argument")); |
| 2410 | if (ts_node_is_null(operand)) { |
| 2411 | operand = ts_node_child_by_field_name(node, TS_FIELD("operand")); |
| 2412 | } |
| 2413 | if (ts_node_is_null(operand) && ts_node_named_child_count(node) > 0) { |
| 2414 | operand = ts_node_named_child(node, 0); |
| 2415 | } |
| 2416 | const char *token = cpp_operator_token(ctx, node); |
| 2417 | bool unary_token = token && (strcmp(token, "-") == 0 || strcmp(token, "*") == 0 || |
| 2418 | strcmp(token, "!") == 0); |
| 2419 | bool update_token = token && (strcmp(token, "++") == 0 || strcmp(token, "--") == 0); |
| 2420 | /* `this` has the built-in pointer type in C++. Consequently `*this` is |
| 2421 | * always pointer dereference and can never dispatch an overloaded |
| 2422 | * operator*. Do not manufacture a semantic candidate for it. */ |
| 2423 | if (!ts_node_is_null(operand) && token && strcmp(token, "*") == 0 && |
| 2424 | strcmp(ts_node_type(operand), "this") == 0) { |
| 2425 | return; |
| 2426 | } |
| 2427 | if (!ts_node_is_null(operand) && |
| 2428 | ((strcmp(kind, "update_expression") == 0 && update_token) || |
| 2429 | (strcmp(kind, "update_expression") != 0 && unary_token))) { |
| 2430 | push_cpp_semantic_call_candidate( |
| 2431 | ctx, node, cbm_arena_sprintf(ctx->arena, "operator%s", token), enclosing_func_qn); |
| 2432 | } |
| 2433 | return; |
| 2434 | } |
| 2435 | |
| 2436 | if (strcmp(kind, "field_expression") == 0) { |
| 2437 | TSNode receiver = ts_node_child_by_field_name(node, TS_FIELD("argument")); |
| 2438 | TSNode member = ts_node_child_by_field_name(node, TS_FIELD("field")); |
| 2439 | const char *token = cpp_operator_token(ctx, node); |
| 2440 | if (!ts_node_is_null(receiver) && !ts_node_is_null(member) && token && |
| 2441 | strcmp(token, "->") == 0) { |
| 2442 | push_cpp_semantic_call_candidate(ctx, node, "operator->", enclosing_func_qn); |
| 2443 | } |
| 2444 | return; |
| 2445 | } |
| 2446 | |
| 2447 | if (strcmp(kind, "assignment_expression") == 0) { |
no test coverage detected