@@ -65,60 +65,53 @@ static const char *itoa_log(int val) {
6565/* Append a JSON-escaped string value to buf at position *pos.
6666 * Writes: ,"key":"escaped_value"
6767 * Handles: \, ", \n, \r, \t */
68- // NOLINTNEXTLINE(readability-function-cognitive-complexity)
68+ static int def_json_escape_char (char * buf , size_t avail , char ch ) {
69+ char esc = 0 ;
70+ switch (ch ) {
71+ case '"' :
72+ esc = '"' ;
73+ break ;
74+ case '\\' :
75+ esc = '\\' ;
76+ break ;
77+ case '\n' :
78+ esc = 'n' ;
79+ break ;
80+ case '\r' :
81+ esc = 'r' ;
82+ break ;
83+ case '\t' :
84+ esc = 't' ;
85+ break ;
86+ default :
87+ if (avail >= 1 ) {
88+ buf [0 ] = ch ;
89+ }
90+ return 1 ;
91+ }
92+ if (avail >= 2 ) {
93+ buf [0 ] = '\\' ;
94+ buf [1 ] = esc ;
95+ }
96+ return 2 ;
97+ }
98+
6999static void append_json_string (char * buf , size_t bufsize , size_t * pos , const char * key ,
70100 const char * val ) {
71- if (!val || ! val [0 ]) {
101+ if (!val || val [0 ] == '\0' ) {
72102 return ;
73103 }
74104 if (* pos >= bufsize - 10 ) {
75105 return ;
76106 }
77-
78107 size_t p = * pos ;
79- /* ,\"key\":\" */
80108 int w = snprintf (buf + p , bufsize - p , ",\"%s\":\"" , key );
81109 if (w <= 0 || (size_t )w >= bufsize - p ) {
82110 return ;
83111 }
84112 p += (size_t )w ;
85-
86113 for (const char * s = val ; * s && p < bufsize - 3 ; s ++ ) {
87- switch (* s ) {
88- case '"' :
89- buf [p ++ ] = '\\' ;
90- if (p < bufsize - 2 ) {
91- buf [p ++ ] = '"' ;
92- }
93- break ;
94- case '\\' :
95- buf [p ++ ] = '\\' ;
96- if (p < bufsize - 2 ) {
97- buf [p ++ ] = '\\' ;
98- }
99- break ;
100- case '\n' :
101- buf [p ++ ] = '\\' ;
102- if (p < bufsize - 2 ) {
103- buf [p ++ ] = 'n' ;
104- }
105- break ;
106- case '\r' :
107- buf [p ++ ] = '\\' ;
108- if (p < bufsize - 2 ) {
109- buf [p ++ ] = 'r' ;
110- }
111- break ;
112- case '\t' :
113- buf [p ++ ] = '\\' ;
114- if (p < bufsize - 2 ) {
115- buf [p ++ ] = 't' ;
116- }
117- break ;
118- default :
119- buf [p ++ ] = * s ;
120- break ;
121- }
114+ p += (size_t )def_json_escape_char (buf + p , bufsize - p - 2 , * s );
122115 }
123116 if (p < bufsize - 1 ) {
124117 buf [p ++ ] = '"' ;
@@ -196,7 +189,61 @@ static void build_def_props(char *buf, size_t bufsize, const CBMDefinition *def)
196189 }
197190}
198191
199- // NOLINTNEXTLINE(readability-function-cognitive-complexity)
192+ /* Process one definition: create node, register, DEFINES + DEFINES_METHOD edges. */
193+ static void process_def (cbm_pipeline_ctx_t * ctx , const CBMDefinition * def , const char * rel ) {
194+ if (!def -> qualified_name || !def -> name ) {
195+ return ;
196+ }
197+ char props [2048 ];
198+ build_def_props (props , sizeof (props ), def );
199+ int64_t node_id = cbm_gbuf_upsert_node (
200+ ctx -> gbuf , def -> label ? def -> label : "Function" , def -> name , def -> qualified_name ,
201+ def -> file_path ? def -> file_path : rel , (int )def -> start_line , (int )def -> end_line , props );
202+ if (node_id > 0 && def -> label &&
203+ (strcmp (def -> label , "Function" ) == 0 || strcmp (def -> label , "Method" ) == 0 ||
204+ strcmp (def -> label , "Class" ) == 0 )) {
205+ cbm_registry_add (ctx -> registry , def -> name , def -> qualified_name , def -> label );
206+ }
207+ char * file_qn = cbm_pipeline_fqn_compute (ctx -> project_name , rel , "__file__" );
208+ const cbm_gbuf_node_t * file_node = cbm_gbuf_find_by_qn (ctx -> gbuf , file_qn );
209+ if (file_node && node_id > 0 ) {
210+ cbm_gbuf_insert_edge (ctx -> gbuf , file_node -> id , node_id , "DEFINES" , "{}" );
211+ }
212+ free (file_qn );
213+ if (def -> parent_class && def -> label && strcmp (def -> label , "Method" ) == 0 ) {
214+ const cbm_gbuf_node_t * parent = cbm_gbuf_find_by_qn (ctx -> gbuf , def -> parent_class );
215+ if (parent && node_id > 0 ) {
216+ cbm_gbuf_insert_edge (ctx -> gbuf , parent -> id , node_id , "DEFINES_METHOD" , "{}" );
217+ }
218+ }
219+ }
220+
221+ /* Create IMPORTS edges for one file's imports. */
222+ static int create_import_edges_for_file (cbm_pipeline_ctx_t * ctx , const CBMFileResult * result ,
223+ const char * rel ) {
224+ int count = 0 ;
225+ for (int j = 0 ; j < result -> imports .count ; j ++ ) {
226+ const CBMImport * imp = & result -> imports .items [j ];
227+ if (!imp -> module_path ) {
228+ continue ;
229+ }
230+ char * target_qn = cbm_pipeline_fqn_module (ctx -> project_name , imp -> module_path );
231+ const cbm_gbuf_node_t * target = cbm_gbuf_find_by_qn (ctx -> gbuf , target_qn );
232+ char * file_qn = cbm_pipeline_fqn_compute (ctx -> project_name , rel , "__file__" );
233+ const cbm_gbuf_node_t * source_node = cbm_gbuf_find_by_qn (ctx -> gbuf , file_qn );
234+ if (source_node && target ) {
235+ char imp_props [256 ];
236+ snprintf (imp_props , sizeof (imp_props ), "{\"local_name\":\"%s\"}" ,
237+ imp -> local_name ? imp -> local_name : "" );
238+ cbm_gbuf_insert_edge (ctx -> gbuf , source_node -> id , target -> id , "IMPORTS" , imp_props );
239+ count ++ ;
240+ }
241+ free (target_qn );
242+ free (file_qn );
243+ }
244+ return count ;
245+ }
246+
200247int cbm_pipeline_pass_definitions (cbm_pipeline_ctx_t * ctx , const cbm_file_info_t * files ,
201248 int file_count ) {
202249 cbm_log_info ("pass.start" , "pass" , "definitions" , "files" , itoa_log (file_count ));
@@ -240,75 +287,14 @@ int cbm_pipeline_pass_definitions(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t
240287
241288 /* Create nodes for each definition */
242289 for (int d = 0 ; d < result -> defs .count ; d ++ ) {
243- CBMDefinition * def = & result -> defs .items [d ];
244- if (!def -> qualified_name || !def -> name ) {
245- continue ;
246- }
247-
248- char props [2048 ];
249- build_def_props (props , sizeof (props ), def );
250-
251- int64_t node_id =
252- cbm_gbuf_upsert_node (ctx -> gbuf , def -> label ? def -> label : "Function" , def -> name ,
253- def -> qualified_name , def -> file_path ? def -> file_path : rel ,
254- (int )def -> start_line , (int )def -> end_line , props );
255-
256- /* Register callable symbols in the registry */
257- if (node_id > 0 && def -> label &&
258- (strcmp (def -> label , "Function" ) == 0 || strcmp (def -> label , "Method" ) == 0 ||
259- strcmp (def -> label , "Class" ) == 0 )) {
260- cbm_registry_add (ctx -> registry , def -> name , def -> qualified_name , def -> label );
261- }
262-
263- /* DEFINES edge: File node → Definition node */
264- const char * file_qn_name = "__file__" ;
265- char * file_qn = cbm_pipeline_fqn_compute (ctx -> project_name , rel , file_qn_name );
266- const cbm_gbuf_node_t * file_node = cbm_gbuf_find_by_qn (ctx -> gbuf , file_qn );
267- if (file_node && node_id > 0 ) {
268- cbm_gbuf_insert_edge (ctx -> gbuf , file_node -> id , node_id , "DEFINES" , "{}" );
269- }
270- free (file_qn );
271-
272- /* DEFINES_METHOD edge: Class → Method */
273- if (def -> parent_class && def -> label && strcmp (def -> label , "Method" ) == 0 ) {
274- const cbm_gbuf_node_t * parent = cbm_gbuf_find_by_qn (ctx -> gbuf , def -> parent_class );
275- if (parent && node_id > 0 ) {
276- cbm_gbuf_insert_edge (ctx -> gbuf , parent -> id , node_id , "DEFINES_METHOD" , "{}" );
277- }
278- }
279-
290+ process_def (ctx , & result -> defs .items [d ], rel );
280291 total_defs ++ ;
281292 }
282293
283294 /* Store calls for pass_calls (we save them in the extraction results
284295 * for now — a future optimization would batch these) */
285296 total_calls += result -> calls .count ;
286- total_imports += result -> imports .count ;
287-
288- /* Store per-file import map for later use by pass_calls.
289- * For each import, create an IMPORTS edge: File → imported module. */
290- for (int j = 0 ; j < result -> imports .count ; j ++ ) {
291- CBMImport * imp = & result -> imports .items [j ];
292- if (!imp -> module_path ) {
293- continue ;
294- }
295-
296- /* Find or create the target module node */
297- char * target_qn = cbm_pipeline_fqn_module (ctx -> project_name , imp -> module_path );
298- const cbm_gbuf_node_t * target = cbm_gbuf_find_by_qn (ctx -> gbuf , target_qn );
299-
300- char * file_qn = cbm_pipeline_fqn_compute (ctx -> project_name , rel , "__file__" );
301- const cbm_gbuf_node_t * source_node = cbm_gbuf_find_by_qn (ctx -> gbuf , file_qn );
302-
303- if (source_node && target ) {
304- char imp_props [256 ];
305- snprintf (imp_props , sizeof (imp_props ), "{\"local_name\":\"%s\"}" ,
306- imp -> local_name ? imp -> local_name : "" );
307- cbm_gbuf_insert_edge (ctx -> gbuf , source_node -> id , target -> id , "IMPORTS" , imp_props );
308- }
309- free (target_qn );
310- free (file_qn );
311- }
297+ total_imports += create_import_edges_for_file (ctx , result , rel );
312298
313299 /* Cache or free the extraction result */
314300 if (ctx -> result_cache ) {
0 commit comments