@@ -838,6 +838,8 @@ pub struct RemappedFrameIter<'r, 'data> {
838838 had_mappings : bool ,
839839 /// Whether this method has any line-based mappings.
840840 has_line_info : bool ,
841+ /// Whether any frame was successfully matched by iterate_with_lines.
842+ matched_any : bool ,
841843 /// The source file of the outer class for synthesis.
842844 outer_source_file : Option < & ' data str > ,
843845}
@@ -851,6 +853,7 @@ impl<'r, 'data> RemappedFrameIter<'r, 'data> {
851853 skip_count : 0 ,
852854 had_mappings : false ,
853855 has_line_info : false ,
856+ matched_any : false ,
854857 outer_source_file : None ,
855858 }
856859 }
@@ -871,6 +874,7 @@ impl<'r, 'data> RemappedFrameIter<'r, 'data> {
871874 skip_count,
872875 had_mappings,
873876 has_line_info,
877+ matched_any : false ,
874878 outer_source_file,
875879 }
876880 }
@@ -883,6 +887,7 @@ impl<'r, 'data> RemappedFrameIter<'r, 'data> {
883887 skip_count : 0 ,
884888 had_mappings : false ,
885889 has_line_info : false ,
890+ matched_any : false ,
886891 outer_source_file : None ,
887892 }
888893 }
@@ -932,9 +937,20 @@ impl<'r, 'data> RemappedFrameIter<'r, 'data> {
932937 & mut members,
933938 self . outer_source_file ,
934939 self . has_line_info ,
940+ & mut self . pending_frames ,
935941 ) ;
936- self . inner = Some ( ( cache, frame, members) ) ;
937- mapped
942+ if mapped. is_some ( ) {
943+ self . matched_any = true ;
944+ self . inner = Some ( ( cache, frame, members) ) ;
945+ mapped
946+ } else if !self . matched_any && self . has_line_info {
947+ // Outside-range fallback: no member matched the frame line.
948+ // Remap only the class name, keeping the obfuscated method name
949+ // and the original line.
950+ Some ( cache. remap_class_only ( & frame, self . outer_source_file ) )
951+ } else {
952+ None
953+ }
938954 } else {
939955 let mapped =
940956 iterate_without_lines ( cache, & mut frame, & mut members, self . outer_source_file ) ;
@@ -965,6 +981,7 @@ fn iterate_with_lines<'a>(
965981 members : & mut std:: slice:: Iter < ' _ , raw:: Member > ,
966982 outer_source_file : Option < & str > ,
967983 has_line_info : bool ,
984+ pending_frames : & mut Vec < StackFrame < ' a > > ,
968985) -> Option < StackFrame < ' a > > {
969986 let frame_line = frame. line . unwrap_or ( 0 ) ;
970987 for member in members {
@@ -974,14 +991,47 @@ fn iterate_with_lines<'a>(
974991 }
975992 // If the mapping entry has no line range, determine output line.
976993 if member. endline == 0 {
977- let output_line = if !member. has_line_mapping ( ) {
994+ if !member. has_line_mapping ( ) {
978995 // Bare method mapping: pass through frame line.
979- frame. line
980- } else if member. original_startline > 0 && member. original_startline != u32:: MAX {
981- Some ( member. original_startline as usize )
982- } else {
983- None
984- } ;
996+ return map_member_without_lines (
997+ cache,
998+ frame,
999+ member,
1000+ outer_source_file,
1001+ frame. line ,
1002+ ) ;
1003+ }
1004+ // Span expansion: if the original range spans multiple lines,
1005+ // emit one frame per original line.
1006+ if member. original_endline != u32:: MAX
1007+ && member. original_endline > member. original_startline
1008+ {
1009+ let first_line = member. original_startline as usize ;
1010+ let last_line = member. original_endline as usize ;
1011+ let mut first_frame = None ;
1012+ for line in first_line..=last_line {
1013+ if let Some ( f) = map_member_without_lines (
1014+ cache,
1015+ frame,
1016+ member,
1017+ outer_source_file,
1018+ Some ( line) ,
1019+ ) {
1020+ if first_frame. is_none ( ) {
1021+ first_frame = Some ( f) ;
1022+ } else {
1023+ pending_frames. push ( f) ;
1024+ }
1025+ }
1026+ }
1027+ return first_frame;
1028+ }
1029+ let output_line =
1030+ if member. original_startline > 0 && member. original_startline != u32:: MAX {
1031+ Some ( member. original_startline as usize )
1032+ } else {
1033+ None
1034+ } ;
9851035 return map_member_without_lines ( cache, frame, member, outer_source_file, output_line) ;
9861036 }
9871037 // skip any members which do not match our frames line
0 commit comments