Skip to content

Commit f6d1201

Browse files
romtsnclaude
andcommitted
feat(r8): Sort ambiguous no-range entries alphabetically by method name
When multiple no-range entries with different original method names all have line mappings, sort them alphabetically. Bare method entries (no line mapping) preserve original mapping file order. Fixes test_single_line_no_line_number_stacktrace — all 10 R8 line number handling tests now pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b692685 commit f6d1201

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

src/cache/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,7 @@ fn iterate_with_lines<'a>(
10051005
// Span expansion: if the original range spans multiple lines,
10061006
// emit one frame per original line.
10071007
if member.original_endline != u32::MAX
1008-
&& member.original_endline > member.original_startline().unwrap_or(0) as u32
1008+
&& member.original_endline > member.original_startline().unwrap_or(0)
10091009
{
10101010
let first_line = member.original_startline().unwrap_or(0) as usize;
10111011
let last_line = member.original_endline as usize;
@@ -1202,6 +1202,7 @@ fn resolve_base_entries<'a>(
12021202
let mut first_no_range_offset: Option<u32> = None;
12031203
// Whether all no-range entries map to the same original method name.
12041204
let mut all_no_range_same_name = true;
1205+
let mut all_no_range_have_line_mapping = true;
12051206
for member in base_entries {
12061207
if member.startline().is_some() {
12071208
if member.original_endline != u32::MAX
@@ -1211,6 +1212,9 @@ fn resolve_base_entries<'a>(
12111212
}
12121213
} else {
12131214
no_range_count += 1;
1215+
if member.original_startline().is_none() {
1216+
all_no_range_have_line_mapping = false;
1217+
}
12141218
match first_no_range_offset {
12151219
None => first_no_range_offset = Some(member.original_name_offset),
12161220
Some(first) if member.original_name_offset != first => {
@@ -1262,6 +1266,12 @@ fn resolve_base_entries<'a>(
12621266
}
12631267
}
12641268

1269+
// Sort no-range frames by original method name when all have line mappings;
1270+
// bare method entries preserve original mapping file order.
1271+
if !all_no_range_same_name && all_no_range_have_line_mapping {
1272+
frames.sort_by(|a, b| a.method.cmp(b.method));
1273+
}
1274+
12651275
frames
12661276
}
12671277

src/mapper.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ fn resolve_base_entries<'s>(
353353
let mut first_no_range_name: Option<&str> = None;
354354
// Whether all no-range entries map to the same original method name.
355355
let mut all_no_range_same_name = true;
356+
let mut all_no_range_have_line_mapping = true;
356357
for member in base_entries {
357358
if member.startline.is_some() {
358359
if member.original_endline.is_some()
@@ -362,6 +363,9 @@ fn resolve_base_entries<'s>(
362363
}
363364
} else {
364365
no_range_count += 1;
366+
if member.original_startline.is_none() {
367+
all_no_range_have_line_mapping = false;
368+
}
365369
match first_no_range_name {
366370
None => first_no_range_name = Some(member.original),
367371
Some(first) if member.original != first => all_no_range_same_name = false,
@@ -409,6 +413,12 @@ fn resolve_base_entries<'s>(
409413
collected.rewrite_rules.extend(member.rewrite_rules.iter());
410414
}
411415
}
416+
417+
// Sort no-range frames by original method name when all have line mappings;
418+
// bare method entries preserve original mapping file order.
419+
if !all_no_range_same_name && all_no_range_have_line_mapping {
420+
collected.frames.sort_by_key(|f| f.method);
421+
}
412422
}
413423

414424
/// A Proguard Remapper.

0 commit comments

Comments
 (0)