Skip to content

Commit 94d628e

Browse files
committed
feat(r8-tests): Add R8 method overloading tests
1 parent 6e5070b commit 94d628e

File tree

2 files changed

+131
-0
lines changed

2 files changed

+131
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# R8 Method Overloading fixtures: failures & required behavior changes
2+
3+
Ported from upstream R8 retrace fixtures/tests:
4+
- `src/test/java/com/android/tools/r8/retrace/stacktraces/OverloadedWithAndWithoutRangeStackTrace.java`
5+
- `src/test/java/com/android/tools/r8/retrace/stacktraces/OverloadSameLineTest.java`
6+
- `src/test/java/com/android/tools/r8/retrace/RetraceMappingWithOverloadsTest.java`
7+
8+
This doc lists **only the failing tests** and explains, one-by-one, what would need to change in `rust-proguard` to match upstream R8 retrace behavior.
9+
10+
## `test_retrace_mapping_with_overloads_api_has_3_candidates`
11+
12+
- **Upstream behavior** (`RetraceMappingWithOverloadsTest`): `lookupMethod("a")` on class `A` yields **3** method elements for the residual name `a`:
13+
- `select(java.util.List)` (no line info)
14+
- `sync()` (line-mapped range)
15+
- `cancel(java.lang.String[])` (no line info)
16+
- **Current crate behavior**: `ProguardMapper::remap_frame(StackFrame::new("A","a",0))` yields **2** candidates.
17+
- **Why it fails**:
18+
- This crate treats `line = 0` as “no line information” and may be **filtering out** line-ranged candidates (like `sync()`) unless a concrete line is provided.
19+
- Alternatively, it may be collapsing/choosing a subset when multiple candidates exist without a line.
20+
- **What needs fixing**:
21+
- **API semantics**: align “method lookup with no line” behavior with R8 retrace’s `lookupMethod`, which includes both:
22+
- base/no-line mappings, and
23+
- line-ranged mappings (as candidates) even when the position is unknown.
24+

tests/r8-method-overloading.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//! Tests for R8 retrace "Method Overloading" fixtures.
2+
//!
3+
//! Ported from the upstream R8 retrace fixtures in:
4+
//! - `src/test/java/com/android/tools/r8/retrace/stacktraces/OverloadedWithAndWithoutRangeStackTrace.java`
5+
//! - `src/test/java/com/android/tools/r8/retrace/stacktraces/OverloadSameLineTest.java`
6+
//! - `src/test/java/com/android/tools/r8/retrace/RetraceMappingWithOverloadsTest.java`
7+
#![allow(clippy::unwrap_used)]
8+
9+
use proguard::{ProguardCache, ProguardMapper, ProguardMapping, StackFrame};
10+
11+
fn assert_remap_stacktrace(mapping: &str, input: &str, expected: &str) {
12+
let mapper = ProguardMapper::from(mapping);
13+
let actual = mapper.remap_stacktrace(input).unwrap();
14+
assert_eq!(actual.trim_end(), expected.trim_end());
15+
16+
let mapping = ProguardMapping::new(mapping.as_bytes());
17+
let mut buf = Vec::new();
18+
ProguardCache::write(&mapping, &mut buf).unwrap();
19+
let cache = ProguardCache::parse(&buf).unwrap();
20+
cache.test();
21+
22+
let actual = cache.remap_stacktrace(input).unwrap();
23+
assert_eq!(actual.trim_end(), expected.trim_end());
24+
}
25+
26+
// =============================================================================
27+
// OverloadedWithAndWithoutRangeStackTrace
28+
// =============================================================================
29+
30+
const OVERLOADED_WITH_AND_WITHOUT_RANGE_MAPPING: &str = r#"some.Class -> A:
31+
java.util.List select(java.util.List) -> a
32+
3:3:void sync():425:425 -> a
33+
void cancel(java.lang.String[]) -> a
34+
"#;
35+
36+
#[test]
37+
fn test_overloaded_with_and_without_range_stacktrace() {
38+
let input = r#" at A.a(SourceFile:3)
39+
"#;
40+
41+
// This crate normalizes indentation to 4 spaces for parsed frames.
42+
let expected = r#" at some.Class.sync(Class.java:425)
43+
"#;
44+
45+
assert_remap_stacktrace(OVERLOADED_WITH_AND_WITHOUT_RANGE_MAPPING, input, expected);
46+
}
47+
48+
// =============================================================================
49+
// OverloadSameLineTest
50+
// =============================================================================
51+
52+
const OVERLOAD_SAME_LINE_MAPPING: &str = r#"com.android.tools.r8.naming.retrace.Main -> foo.a:
53+
1:1:void overload():7:7 -> overload
54+
1:1:void overload(java.lang.String):13:13 -> overload
55+
1:1:void overload(int):15:15 -> overload
56+
"#;
57+
58+
#[test]
59+
fn test_overload_same_line_stacktrace() {
60+
let input = r#"Exception in thread "main" java.lang.NullPointerException
61+
at foo.a.overload(Main.java:1)
62+
"#;
63+
64+
// Upstream emits 3 alternatives (one per overload) for the same minified position.
65+
// This crate emits alternatives as duplicate frames (no `<OR>` markers).
66+
let expected = r#"Exception in thread "main" java.lang.NullPointerException
67+
at com.android.tools.r8.naming.retrace.Main.overload(Main.java:7)
68+
at com.android.tools.r8.naming.retrace.Main.overload(Main.java:13)
69+
at com.android.tools.r8.naming.retrace.Main.overload(Main.java:15)
70+
"#;
71+
72+
assert_remap_stacktrace(OVERLOAD_SAME_LINE_MAPPING, input, expected);
73+
}
74+
75+
// =============================================================================
76+
// RetraceMappingWithOverloadsTest (API-level behavior)
77+
// =============================================================================
78+
79+
const RETRACE_MAPPING_WITH_OVERLOADS_MAPPING: &str = r#"some.Class -> A:
80+
java.util.List select(java.util.List) -> a
81+
3:3:void sync():425:425 -> a
82+
4:5:void sync():427:428 -> a
83+
void cancel(java.lang.String[]) -> a
84+
"#;
85+
86+
#[test]
87+
fn test_retrace_mapping_with_overloads_api_has_3_candidates() {
88+
let mapper = ProguardMapper::from(RETRACE_MAPPING_WITH_OVERLOADS_MAPPING);
89+
90+
// Equivalent to upstream's `retracer.retraceClass(A).lookupMethod("a")` size == 3:
91+
// - select(java.util.List)
92+
// - sync() (line-mapped range)
93+
// - cancel(java.lang.String[])
94+
let frame = StackFrame::new("A", "a", 0);
95+
let remapped: Vec<_> = mapper.remap_frame(&frame).collect();
96+
assert_eq!(remapped.len(), 3);
97+
}
98+
99+
#[test]
100+
fn test_retrace_mapping_with_overloads_api_includes_sync_with_line() {
101+
let mapper = ProguardMapper::from(RETRACE_MAPPING_WITH_OVERLOADS_MAPPING);
102+
103+
// When the minified line hits the `sync()` mapping range, it should produce a `sync` candidate.
104+
let frame = StackFrame::new("A", "a", 3);
105+
let remapped: Vec<_> = mapper.remap_frame(&frame).collect();
106+
assert!(remapped.iter().any(|f| f.method() == "sync"));
107+
}

0 commit comments

Comments
 (0)