@@ -721,11 +721,6 @@ static bool cbm_source_nesting_exceeds(const char *source, int source_len, int c
721721 return false;
722722}
723723
724- static CBMFileResult * cbm_extract_file_impl (const char * source , int source_len ,
725- CBMLanguage language , const char * project ,
726- const char * rel_path , int64_t timeout_micros ,
727- const char * * extra_defines , const char * * include_paths );
728-
729724/* Best-effort parse-coverage collection (#963). Walks only the has_error paths
730725 * of the tree and records the 1-based line ranges of the TOP-MOST ERROR/MISSING
731726 * nodes (does not descend into an error subtree — one range per failed region).
@@ -849,6 +844,106 @@ static bool cbm_line_contains(const char *src, int src_len, uint32_t line, const
849844 return false;
850845}
851846
847+ static bool cbm_identifier_char (char c ) {
848+ return isalnum ((unsigned char )c ) || c == '_' ;
849+ }
850+
851+ /* Verify that the mapped original span contains callable-definition syntax,
852+ * not merely the name at a macro invocation or call site. */
853+ static bool cbm_span_contains_callable_def (const char * src , int src_len , uint32_t start_line ,
854+ uint32_t end_line , const char * name ) {
855+ if (!src || src_len <= 0 || !name || !name [0 ] || start_line == 0 || end_line < start_line ) {
856+ return false;
857+ }
858+ int span_start = 0 ;
859+ uint32_t line = 1 ;
860+ while (span_start < src_len && line < start_line ) {
861+ if (src [span_start ++ ] == '\n' ) {
862+ line ++ ;
863+ }
864+ }
865+ if (line != start_line ) {
866+ return false;
867+ }
868+ int span_end = span_start ;
869+ while (span_end < src_len && line <= end_line ) {
870+ if (src [span_end ++ ] == '\n' ) {
871+ line ++ ;
872+ }
873+ }
874+ size_t name_len = strlen (name );
875+ for (int pos = span_start ; pos + (int )name_len <= span_end ; pos ++ ) {
876+ if (strncmp (src + pos , name , name_len ) != 0 ||
877+ (pos > 0 && cbm_identifier_char (src [pos - 1 ])) ||
878+ (pos + (int )name_len < src_len && cbm_identifier_char (src [pos + name_len ]))) {
879+ continue ;
880+ }
881+ int before = pos ;
882+ while (before > span_start && isspace ((unsigned char )src [before - 1 ])) {
883+ before -- ;
884+ }
885+ if (before > span_start && strchr ("(,=!?[." , src [before - 1 ])) {
886+ continue ;
887+ }
888+ int open = pos + (int )name_len ;
889+ while (open < span_end && isspace ((unsigned char )src [open ])) {
890+ open ++ ;
891+ }
892+ if (open >= span_end || src [open ] != '(' ) {
893+ continue ;
894+ }
895+ int depth = 0 ;
896+ int close = -1 ;
897+ for (int i = open ; i < span_end ; i ++ ) {
898+ if (src [i ] == '(' ) {
899+ depth ++ ;
900+ } else if (src [i ] == ')' && -- depth == 0 ) {
901+ close = i ;
902+ break ;
903+ }
904+ }
905+ if (close < 0 ) {
906+ continue ;
907+ }
908+ for (int i = close + 1 ; i < span_end ; i ++ ) {
909+ if (src [i ] == '{' ) {
910+ return true;
911+ }
912+ if (src [i ] == ';' ) {
913+ break ;
914+ }
915+ }
916+ }
917+ return false;
918+ }
919+
920+ /* Remap an expanded-source definition back to the original input file. Every
921+ * line in the definition must be attributable to the main file; generated
922+ * macro bodies, included headers, and ambiguous spans fail closed. */
923+ static bool cbm_remap_preprocessed_def (CBMDefinition * def , const CBMPreprocessedSource * pp ) {
924+ if (!def || !pp || !pp -> original_line_by_expanded_line || !pp -> belongs_to_main_file ||
925+ def -> start_line == 0 || def -> end_line < def -> start_line ||
926+ def -> end_line > (uint32_t )pp -> expanded_line_count ) {
927+ return false;
928+ }
929+
930+ uint32_t original_start = pp -> original_line_by_expanded_line [def -> start_line ];
931+ uint32_t original_end = pp -> original_line_by_expanded_line [def -> end_line ];
932+ if (!original_start || !original_end || original_end < original_start ) {
933+ return false;
934+ }
935+ for (uint32_t line = def -> start_line ; line <= def -> end_line ; line ++ ) {
936+ if (!pp -> belongs_to_main_file [line ] || !pp -> original_line_by_expanded_line [line ]) {
937+ return false;
938+ }
939+ }
940+
941+ def -> start_line = original_start ;
942+ def -> end_line = original_end ;
943+ def -> lines = (int )(original_end - original_start + 1 );
944+ return true;
945+ }
946+
852947static void cbm_subtract_recovered_regions (cbm_error_regions_t * regs , const CBMDefArray * defs ) {
853948 int kept = 0 ;
854949 for (int i = 0 ; i < regs -> count ; i ++ ) {
@@ -886,17 +981,17 @@ static const char *cbm_error_ranges_str(CBMArena *a, const cbm_error_regions_t *
886981CBMFileResult * cbm_extract_file (const char * source , int source_len , CBMLanguage language ,
887982 const char * project , const char * rel_path , int64_t timeout_micros ,
888983 const char * * extra_defines , const char * * include_paths ) {
889- CBMFileResult * r = cbm_extract_file_impl ( source , source_len , language , project , rel_path ,
890- timeout_micros , extra_defines , include_paths );
891- cbm_index_mark_done ( rel_path );
984+ CBMFileResult * r =
985+ cbm_extract_file_ex ( source , source_len , language , project , rel_path , timeout_micros ,
986+ extra_defines , include_paths , NULL , NULL );
892987 return r ;
893988}
894989
895- static CBMFileResult * cbm_extract_file_impl (const char * source , int source_len ,
896- CBMLanguage language , const char * project ,
897- const char * rel_path , int64_t timeout_micros ,
898- const char * * extra_defines ,
899- const char * * include_paths ) {
990+ CBMFileResult * cbm_extract_file_ex (const char * source , int source_len , CBMLanguage language ,
991+ const char * project , const char * rel_path ,
992+ int64_t timeout_micros , const char * * extra_defines ,
993+ const char * * include_paths , const CBMMacroTable * macro_table ,
994+ const CBMReturnTypeTable * return_type_table ) {
900995 // Allocate result on heap (arena inside for all string data)
901996 enum { SINGLE = 1 };
902997 CBMFileResult * result = (CBMFileResult * )calloc (SINGLE , sizeof (CBMFileResult ));
@@ -926,6 +1021,7 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
9261021 if (!spec ) {
9271022 result -> has_error = true;
9281023 result -> error_msg = cbm_arena_strdup (a , "unsupported language" );
1024+ cbm_index_mark_done (rel_path );
9291025 return result ;
9301026 }
9311027
@@ -934,6 +1030,7 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
9341030 if (!ts_lang ) {
9351031 result -> has_error = true;
9361032 result -> error_msg = cbm_arena_strdup (a , "no tree-sitter grammar" );
1033+ cbm_index_mark_done (rel_path );
9371034 return result ;
9381035 }
9391036
@@ -953,6 +1050,7 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
9531050 if (!parser ) {
9541051 result -> has_error = true;
9551052 result -> error_msg = cbm_arena_strdup (a , "parser alloc failed" );
1053+ cbm_index_mark_done (rel_path );
9561054 return result ;
9571055 }
9581056
@@ -985,6 +1083,7 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
9851083 result -> has_error = true;
9861084 result -> error_msg =
9871085 cbm_arena_strdup (a , timeout_micros > 0 ? "parse timeout" : "parse failed" );
1086+ cbm_index_mark_done (rel_path );
9881087 return result ;
9891088 }
9901089
@@ -1009,6 +1108,8 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
10091108 .rel_path = rel_path ,
10101109 .module_qn = result -> module_qn ,
10111110 .root = root ,
1111+ .macro_table = macro_table ,
1112+ .return_type_table = return_type_table ,
10121113 };
10131114
10141115 // Run extractors: defs + imports use separate walks (unique recursion patterns),
@@ -1088,9 +1189,10 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
10881189 // Defs keep original-source line numbers; only CALLS are extracted from expanded source.
10891190 if (language == CBM_LANG_C || language == CBM_LANG_CPP || language == CBM_LANG_CUDA ) {
10901191 uint64_t pp_start = now_ns ();
1091- char * expanded = cbm_preprocess (source , source_len , rel_path , extra_defines , include_paths ,
1092- language != CBM_LANG_C );
1093- if (expanded ) {
1192+ CBMPreprocessedSource * preprocessed = cbm_preprocess_with_map (
1193+ source , source_len , rel_path , extra_defines , include_paths , language != CBM_LANG_C );
1194+ if (preprocessed && preprocessed -> source ) {
1195+ char * expanded = preprocessed -> source ;
10941196 int expanded_len = (int )strlen (expanded );
10951197 // Record calls count before second pass
10961198 int calls_before = result -> calls .count ;
@@ -1155,15 +1257,20 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
11551257 for (int i = defs_before ; i < result -> defs .count ; i ++ ) {
11561258 CBMDefinition * d = & result -> defs .items [i ];
11571259 bool adopt = false;
1158- for (int rj = 0 ; rj < raw_regs .count && !adopt ; rj ++ ) {
1159- if (d -> start_line <= raw_regs .ends [rj ] &&
1160- d -> end_line >= raw_regs .starts [rj ]) {
1161- adopt = true;
1260+ if (cbm_remap_preprocessed_def (d , preprocessed )) {
1261+ for (int rj = 0 ; rj < raw_regs .count && !adopt ; rj ++ ) {
1262+ if (d -> start_line <= raw_regs .ends [rj ] &&
1263+ d -> end_line >= raw_regs .starts [rj ]) {
1264+ adopt = true;
1265+ }
11621266 }
11631267 }
1164- if (adopt &&
1165- (!d -> name || !cbm_line_contains (source , source_len ,
1166- d -> start_line , d -> name ))) {
1268+ if (adopt && (!d -> name ||
1269+ !cbm_line_contains (source , source_len , d -> start_line ,
1270+ d -> name ) ||
1271+ !cbm_span_contains_callable_def (
1272+ source , source_len , d -> start_line , d -> end_line ,
1273+ d -> name ))) {
11671274 adopt = false;
11681275 }
11691276 for (int j = 0 ; j < defs_before && adopt ; j ++ ) {
@@ -1184,9 +1291,11 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
11841291 ts_tree_delete (pp_tree );
11851292 }
11861293 }
1187- cbm_preprocess_free ( expanded );
1294+ cbm_preprocessed_source_free ( preprocessed );
11881295 atomic_fetch_add (& total_files_preprocessed , 1 );
11891296 (void )calls_before ; // used for future logging
1297+ } else {
1298+ cbm_preprocessed_source_free (preprocessed );
11901299 }
11911300 atomic_fetch_add (& total_preprocess_ns , now_ns () - pp_start );
11921301 }
@@ -1318,6 +1427,7 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
13181427 // Retain tree for cross-file LSP reuse (caller frees via cbm_free_tree)
13191428 result -> cached_tree = tree ;
13201429 result -> cached_lang = language ;
1430+ cbm_index_mark_done (rel_path );
13211431 return result ;
13221432}
13231433
0 commit comments