@@ -1033,43 +1033,29 @@ pub fn strip_basedirs(preprocessor_output: &[u8], basedirs: &[PathBuf]) -> Vec<u
10331033 return preprocessor_output. to_vec ( ) ;
10341034 }
10351035
1036- // Prepare normalized basedirs sorted by length (longest first) to match longest prefix first
1037- let basedirs_data: Vec < _ > = basedirs
1038- . iter ( )
1039- . map ( |basedir| {
1040- let basedir_str = basedir. to_string_lossy ( ) ;
1041- let trimmed = basedir_str. trim_end_matches ( '/' ) . trim_end_matches ( '\\' ) ;
1042- let normalized = normalize_path ( trimmed. as_bytes ( ) ) ;
1043- ( trimmed. as_bytes ( ) . to_vec ( ) , normalized, trimmed. len ( ) )
1044- } )
1045- . filter ( |( bytes, _, _) | !bytes. is_empty ( ) )
1046- . collect ( ) ;
1047-
1048- if basedirs_data. is_empty ( ) {
1049- return preprocessor_output. to_vec ( ) ;
1050- }
1051-
10521036 trace ! (
10531037 "Stripping basedirs from preprocessor output with length {}: {:?}" ,
10541038 preprocessor_output. len( ) ,
10551039 basedirs
10561040 ) ;
10571041
10581042 // Find all potential matches for each basedir using fast substring search
1059- // Store as (position, basedir_index, length) sorted by position
1060- let mut matches: Vec < ( usize , usize , usize ) > = Vec :: new ( ) ;
1043+ // Store as (position, length) sorted by position
1044+ let mut matches: Vec < ( usize , usize ) > = Vec :: new ( ) ;
10611045 #[ cfg( target_os = "windows" ) ]
1062- let preprocessor_output_normalized = normalize_path ( preprocessor_output) ;
1063-
1064- for ( basedir_idx, basedir) in basedirs_data. iter ( ) . enumerate ( ) {
1065- let basedir_len = basedir. 2 ;
1066- // Use memchr's fast substring search
1067- // Case sensitive
1068- #[ cfg( not( target_os = "windows" ) ) ]
1069- let finder = memchr:: memmem:: find_iter ( preprocessor_output, & basedir. 0 ) ;
1070- // Case insensitive
1046+ let preprocessor_output = & normalize_path ( preprocessor_output) ;
1047+
1048+ for basedir_path in basedirs. iter ( ) {
1049+ let basedir_str = basedir_path. to_string_lossy ( ) ;
1050+ let basedir = basedir_str
1051+ . trim_end_matches ( '/' )
1052+ . trim_end_matches ( '\\' )
1053+ . as_bytes ( ) ;
10711054 #[ cfg( target_os = "windows" ) ]
1072- let finder = memchr:: memmem:: find_iter ( & preprocessor_output_normalized, & basedir. 1 ) ;
1055+ // Case insensitive
1056+ let basedir = normalize_path ( basedir) ;
1057+ // Use memchr's fast substring search
1058+ let finder = memchr:: memmem:: find_iter ( preprocessor_output, & basedir) ;
10731059
10741060 for pos in finder {
10751061 // Check if this is a valid boundary (start, whitespace, quote, or '<')
@@ -1079,7 +1065,7 @@ pub fn strip_basedirs(preprocessor_output: &[u8], basedirs: &[PathBuf]) -> Vec<u
10791065 || preprocessor_output[ pos - 1 ] == b'<' ;
10801066
10811067 if is_boundary {
1082- matches. push ( ( pos, basedir_idx , basedir_len ) ) ;
1068+ matches. push ( ( pos, basedir . len ( ) ) ) ;
10831069 }
10841070 }
10851071 }
@@ -1089,13 +1075,13 @@ pub fn strip_basedirs(preprocessor_output: &[u8], basedirs: &[PathBuf]) -> Vec<u
10891075 }
10901076
10911077 // Sort matches by position, then by length descending (longest first for overlaps)
1092- matches. sort_by ( |a, b| a. 0 . cmp ( & b. 0 ) . then ( b. 2 . cmp ( & a. 2 ) ) ) ;
1078+ matches. sort_by ( |a, b| a. 0 . cmp ( & b. 0 ) . then ( b. 1 . cmp ( & a. 1 ) ) ) ;
10931079
10941080 // Remove overlapping matches, keeping the longest match at each position
10951081 let mut filtered_matches: Vec < ( usize , usize ) > = Vec :: new ( ) ;
10961082 let mut last_end = 0 ;
10971083
1098- for ( pos, _basedir_idx , len) in matches {
1084+ for ( pos, len) in matches {
10991085 if pos >= last_end {
11001086 filtered_matches. push ( ( pos, len) ) ;
11011087 last_end = pos + len;
@@ -1124,6 +1110,10 @@ pub fn strip_basedirs(preprocessor_output: &[u8], basedirs: &[PathBuf]) -> Vec<u
11241110/// Normalize path for case-insensitive comparison.
11251111/// On Windows: converts all backslashes to forward slashes;
11261112/// lowercases ASCII characters for consistency.
1113+ /// This function used for two purposes:
1114+ /// - basedir_path: already normalized by std::path::absolute,
1115+ /// but still can mismatch the case of the actual file name
1116+ /// - preprocessor_output: plain text
11271117#[ cfg( target_os = "windows" ) ]
11281118fn normalize_path ( path : & [ u8 ] ) -> Vec < u8 > {
11291119 path. iter ( )
@@ -1135,11 +1125,6 @@ fn normalize_path(path: &[u8]) -> Vec<u8> {
11351125 . collect ( )
11361126}
11371127
1138- #[ cfg( not( target_os = "windows" ) ) ]
1139- fn normalize_path ( path : & [ u8 ] ) -> Vec < u8 > {
1140- path. to_vec ( )
1141- }
1142-
11431128#[ cfg( test) ]
11441129mod tests {
11451130 use super :: { OsStrExt , TimeMacroFinder } ;
@@ -1407,14 +1392,15 @@ mod tests {
14071392 let basedir = PathBuf :: from ( "C:\\ Users\\ test\\ project" ) ;
14081393 let input = b"# 1 \" C:\\ Users\\ test\\ project\\ src\\ main.c\" " ;
14091394 let output = super :: strip_basedirs ( input, std:: slice:: from_ref ( & basedir) ) ;
1410- let expected = b"# 1 \" .\\ src\\ main.c\" " ;
1395+ // normalized backslash to slash
1396+ let expected = b"# 1 \" ./src/main.c\" " ;
14111397 assert_eq ! ( output, expected) ;
14121398
14131399 // With multiple trailing backslashes
14141400 let basedir = PathBuf :: from ( "C:\\ Users\\ test\\ project\\ \\ \\ " ) ;
14151401 let input = b"# 1 \" C:\\ Users\\ test\\ project\\ src\\ main.c\" " ;
14161402 let output = super :: strip_basedirs ( input, std:: slice:: from_ref ( & basedir) ) ;
1417- let expected = b"# 1 \" .\\ src\\ main.c\" " ;
1403+ let expected = b"# 1 \" ./ src/ main.c\" " ;
14181404 assert_eq ! ( output, expected) ;
14191405 }
14201406
@@ -1427,13 +1413,13 @@ mod tests {
14271413 let basedir = PathBuf :: from ( "C:\\ Users\\ test\\ project" ) ;
14281414 let input = b"# 1 \" C:/Users\\ test\\ project\\ src/main.c\" " ;
14291415 let output = super :: strip_basedirs ( input, std:: slice:: from_ref ( & basedir) ) ;
1430- let expected = b"# 1 \" .\\ src/main.c\" " ;
1416+ let expected = b"# 1 \" ./ src/main.c\" " ;
14311417 assert_eq ! ( output, expected, "Failed to strip mixed slash path" ) ;
14321418
14331419 // Also test the reverse case
14341420 let input = b"# 1 \" C:\\ Users/test/project/src\\ main.c\" " ;
14351421 let output = super :: strip_basedirs ( input, std:: slice:: from_ref ( & basedir) ) ;
1436- let expected = b"# 1 \" ./src\\ main.c\" " ;
1422+ let expected = b"# 1 \" ./src/ main.c\" " ;
14371423 assert_eq ! ( output, expected, "Failed to strip reverse mixed slash path" ) ;
14381424 }
14391425}
0 commit comments