@@ -817,6 +817,38 @@ static bool cbm_region_is_recovered(uint32_t rs, uint32_t re, const CBMDefArray
817817 return covered_to >= re ;
818818}
819819
820+ /* #961: true when 1-based `line` of `src` contains `name` (used to verify a
821+ * def recovered from EXPANDED source really lives on that ORIGINAL line —
822+ * rejects header-inlined defs whose physical expanded lines alias unrelated
823+ * raw lines when compile_commands include paths are present). */
824+ static bool cbm_line_contains (const char * src , int src_len , uint32_t line , const char * name ) {
825+ if (!src || !name || !name [0 ] || line == 0 ) {
826+ return false;
827+ }
828+ uint32_t cur = 1 ;
829+ int i = 0 ;
830+ while (i < src_len && cur < line ) {
831+ if (src [i ] == '\n' ) {
832+ cur ++ ;
833+ }
834+ i ++ ;
835+ }
836+ if (cur != line ) {
837+ return false;
838+ }
839+ int end = i ;
840+ while (end < src_len && src [end ] != '\n' ) {
841+ end ++ ;
842+ }
843+ size_t nlen = strlen (name );
844+ for (int j = i ; j + (int )nlen <= end ; j ++ ) {
845+ if (strncmp (src + j , name , nlen ) == 0 ) {
846+ return true;
847+ }
848+ }
849+ return false;
850+ }
851+
820852static void cbm_subtract_recovered_regions (cbm_error_regions_t * regs , const CBMDefArray * defs ) {
821853 int kept = 0 ;
822854 for (int i = 0 ; i < regs -> count ; i ++ ) {
@@ -1103,6 +1135,52 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
11031135 cbm_run_c_lsp (a , result , expanded , expanded_len , pp_root ,
11041136 language != CBM_LANG_C );
11051137
1138+ /* #961: a def whose body braces are split across
1139+ * #ifdef/#else branches parses as an ERROR region on the
1140+ * RAW source (both branches present at once -> unbalanced
1141+ * braces), so the raw defs walk silently dropped it. The
1142+ * expanded tree parses clean (simplecpp picked one
1143+ * branch) and same-file token lines stay aligned, so
1144+ * recover defs from it — adopting ONLY those that
1145+ * intersect a raw ERROR region, whose name is visible on
1146+ * the raw source line, and whose QN the raw pass did not
1147+ * already extract. */
1148+ if (ts_node_has_error (root )) {
1149+ cbm_error_regions_t raw_regs = {{0 }, {0 }, 0 };
1150+ cbm_collect_error_regions (root , & raw_regs );
1151+ if (raw_regs .count > 0 ) {
1152+ int defs_before = result -> defs .count ;
1153+ cbm_extract_definitions (& pp_ctx );
1154+ int w = defs_before ;
1155+ for (int i = defs_before ; i < result -> defs .count ; i ++ ) {
1156+ CBMDefinition * d = & result -> defs .items [i ];
1157+ 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;
1162+ }
1163+ }
1164+ if (adopt &&
1165+ (!d -> name || !cbm_line_contains (source , source_len ,
1166+ d -> start_line , d -> name ))) {
1167+ adopt = false;
1168+ }
1169+ for (int j = 0 ; j < defs_before && adopt ; j ++ ) {
1170+ const char * q = result -> defs .items [j ].qualified_name ;
1171+ if (q && d -> qualified_name &&
1172+ strcmp (q , d -> qualified_name ) == 0 ) {
1173+ adopt = false;
1174+ }
1175+ }
1176+ if (adopt ) {
1177+ result -> defs .items [w ++ ] = * d ;
1178+ }
1179+ }
1180+ result -> defs .count = w ;
1181+ }
1182+ }
1183+
11061184 ts_tree_delete (pp_tree );
11071185 }
11081186 }
0 commit comments