@@ -4440,6 +4440,25 @@ static void extract_class_methods(CBMExtractCtx *ctx, TSNode class_node, const c
44404440 }
44414441 }
44424442
4443+ // Java enums wrap methods inside enum_body_declarations; iterate
4444+ // through to reach the method_declaration nodes.
4445+ if (strcmp (ts_node_type (child ), "enum_body_declarations" ) == 0 ) {
4446+ uint32_t dc = ts_node_child_count (child );
4447+ for (uint32_t j = 0 ; j < dc ; j ++ ) {
4448+ TSNode dchild = ts_node_child (child , j );
4449+ if (ts_node_is_null (dchild ) ||
4450+ !cbm_kind_in_set (dchild , spec -> function_node_types )) {
4451+ continue ;
4452+ }
4453+ TSNode nn = resolve_method_name (dchild , ctx -> language );
4454+ if (ts_node_is_null (nn )) {
4455+ continue ;
4456+ }
4457+ push_method_def (ctx , dchild , class_node , class_qn , spec , nn );
4458+ }
4459+ continue ;
4460+ }
4461+
44434462 // Python wraps @classmethod / @staticmethod / @property methods in
44444463 // a decorated_definition node. Peek through it to find the inner
44454464 // function_definition so we still emit a Method entry.
@@ -6349,7 +6368,6 @@ static void push_class_body_children(TSNode node, const CBMLangSpec *spec, wd_st
63496368 if (strcmp (ck , "field_declaration_list" ) == 0 || strcmp (ck , "class_body" ) == 0 ||
63506369 strcmp (ck , "declaration_list" ) == 0 || strcmp (ck , "body" ) == 0 ||
63516370 strcmp (ck , "block" ) == 0 || strcmp (ck , "suite" ) == 0 ||
6352- strcmp (ck , "interface_body" ) == 0 || strcmp (ck , "enum_body" ) == 0 ||
63536371 // Groovy class bodies are a `closure` node; routing through the
63546372 // nested-class path keeps methods from being re-walked (and thus
63556373 // double-extracted) as top-level functions. Gated to Groovy so other
@@ -6915,3 +6933,54 @@ void cbm_extract_definitions(CBMExtractCtx *ctx) {
69156933 // Extract module-level variables
69166934 extract_variables (ctx , ctx -> root , spec );
69176935}
6936+
6937+ void cbm_dedup_class_method_functions (CBMFileResult * result ) {
6938+ if (!result || result -> defs .count < 2 ) {
6939+ return ;
6940+ }
6941+ CBMDefArray * defs = & result -> defs ;
6942+ for (int fi = defs -> count - 1 ; fi >= 0 ; fi -- ) {
6943+ CBMDefinition * func = & defs -> items [fi ];
6944+ if (!func -> label || strcmp (func -> label , "Function" ) != 0 ) {
6945+ continue ;
6946+ }
6947+ if (!func -> name || !func -> file_path ) {
6948+ continue ;
6949+ }
6950+ for (int mi = 0 ; mi < defs -> count ; mi ++ ) {
6951+ if (mi == fi ) {
6952+ continue ;
6953+ }
6954+ CBMDefinition * method = & defs -> items [mi ];
6955+ if (!method -> label || strcmp (method -> label , "Method" ) != 0 ) {
6956+ continue ;
6957+ }
6958+ if (!method -> name || strcmp (method -> name , func -> name ) != 0 ) {
6959+ continue ;
6960+ }
6961+ if (!method -> file_path || strcmp (method -> file_path , func -> file_path ) != 0 ) {
6962+ continue ;
6963+ }
6964+ if (method -> start_line != func -> start_line ) {
6965+ continue ;
6966+ }
6967+ const char * func_qn = func -> qualified_name ;
6968+ const char * method_qn = method -> qualified_name ;
6969+ if (func_qn && method_qn ) {
6970+ for (int ci = 0 ; ci < result -> calls .count ; ci ++ ) {
6971+ CBMCall * call = & result -> calls .items [ci ];
6972+ if (call -> enclosing_func_qn &&
6973+ strcmp (call -> enclosing_func_qn , func_qn ) == 0 ) {
6974+ call -> enclosing_func_qn = method_qn ;
6975+ }
6976+ }
6977+ }
6978+ if (fi < defs -> count - 1 ) {
6979+ memmove (& defs -> items [fi ], & defs -> items [fi + 1 ],
6980+ (size_t )(defs -> count - fi - 1 ) * sizeof (defs -> items [0 ]));
6981+ }
6982+ defs -> count -- ;
6983+ break ;
6984+ }
6985+ }
6986+ }
0 commit comments