| 3077 | } |
| 3078 | |
| 3079 | static void extract_func_def(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec *spec) { |
| 3080 | CBMArena *a = ctx->arena; |
| 3081 | |
| 3082 | TSNode name_node = cbm_resolve_func_name(node, ctx->language); |
| 3083 | if (ts_node_is_null(name_node)) { |
| 3084 | return; |
| 3085 | } |
| 3086 | |
| 3087 | char *name = cbm_func_name_node_text(a, name_node, ctx->source); |
| 3088 | if (!name || !name[0] || strcmp(name, "function") == 0) { |
| 3089 | return; |
| 3090 | } |
| 3091 | |
| 3092 | // Makefile special targets (.PHONY, .DEFAULT, .SUFFIXES, …) are directives, |
| 3093 | // not build-rule defs. Their leading '.' would also make cbm_fqn_compute |
| 3094 | // emit a "..PHONY" segment (a "double dot") and thus a malformed QN. Skip |
| 3095 | // any dot-prefixed Make target. |
| 3096 | if (ctx->language == CBM_LANG_MAKEFILE && name[0] == '.') { |
| 3097 | return; |
| 3098 | } |
| 3099 | |
| 3100 | TSNode func_node = unwrap_template_inner(node, ctx->language); |
| 3101 | |
| 3102 | CBMDefinition def; |
| 3103 | memset(&def, 0, sizeof(def)); |
| 3104 | |
| 3105 | def.name = name; |
| 3106 | /* Java/Go derive the module from the containing directory (package), so the |
| 3107 | * filename stem is NOT baked into the QN (Go func in myapp/db/conn.go -> |
| 3108 | * proj.myapp.db.Func, not proj.myapp.db.conn.Func). Other langs unchanged. */ |
| 3109 | def.qualified_name = |
| 3110 | cbm_fqn_compute_source_lang(a, ctx->project, ctx->rel_path, name, ctx->language); |
| 3111 | /* A free function declared inside a namespace (C++/C#/PHP) is qualified by |
| 3112 | * the namespace scope the def walk carries (enclosing_class_qn was extended |
| 3113 | * by is_namespace_scope_kind), so `ns::serialize` is `proj.file.ns.serialize` |
| 3114 | * — without this it collapses to the file scope and namespace-aware |
| 3115 | * resolution (ADL, namespace-function lookup) can never see it. Class methods |
| 3116 | * never reach here (they go through extract_class_methods), so a set |
| 3117 | * enclosing scope here is always a namespace. The out-of-line method path |
| 3118 | * below overrides this for `Ns::Cls::method` definitions. */ |
| 3119 | if (ctx->enclosing_class_qn && |
| 3120 | (ctx->language == CBM_LANG_CPP || ctx->language == CBM_LANG_CUDA)) { |
| 3121 | def.qualified_name = cbm_arena_sprintf(a, "%s.%s", ctx->enclosing_class_qn, name); |
| 3122 | } |
| 3123 | def.label = "Function"; |
| 3124 | def.file_path = ctx->rel_path; |
| 3125 | def.start_line = ts_node_start_point(node).row + TS_LINE_OFFSET; |
| 3126 | def.end_line = ts_node_end_point(node).row + TS_LINE_OFFSET; |
| 3127 | def.lines = (int)(def.end_line - def.start_line + TS_LINE_OFFSET); |
| 3128 | def.is_exported = cbm_is_exported(name, ctx->language); |
| 3129 | |
| 3130 | // Parameters — use func_node (inner function for templates) |
| 3131 | TSNode params = ts_node_child_by_field_name(func_node, TS_FIELD("parameters")); |
| 3132 | if (ts_node_is_null(params) && |
| 3133 | (ctx->language == CBM_LANG_C || ctx->language == CBM_LANG_CPP || |
| 3134 | ctx->language == CBM_LANG_CUDA || ctx->language == CBM_LANG_GLSL)) { |
| 3135 | params = find_c_params(func_node); |
| 3136 | } |
no test coverage detected