use cure_engine::Config;
use cure_java_ast::{JavaAst, JavaId};
use cure_java_parser::parse;
use cure_java_print::print;
use cure_java_simplify::simplify;
fn run_src(src: &str) -> String {
let mut out = parse(src);
cure_java_simplify::simplify_unit(&mut out.ast, &mut out.unit, &Config::default());
cure_java_print::print_unit(&out.ast, &out.unit)
}
fn run(build: impl FnOnce(&mut JavaAst) -> JavaId) -> String {
let mut ast = JavaAst::new();
let root = build(&mut ast);
simplify(&mut ast, root, &Config::default());
print(&ast, root)
}
#[test]
fn short_circuit_folds() {
assert_eq!(
run_src("class A{boolean m(boolean x){return false && x;}}").trim_end(),
"class A {\n boolean m(boolean x) {\n return false;\n }\n}"
);
assert!(run_src("class A{boolean m(boolean x){return true || x;}}").contains("return true;"));
assert!(run_src("class A{boolean m(boolean x){return x && true;}}").contains("return x;"));
assert!(run_src("class A{boolean m(boolean x){return x || false;}}").contains("return x;"));
let out = run_src("class A{boolean m(){return foo() && false;}}");
assert!(out.contains("foo() && false"), "{out}");
assert!(run_src("class A{boolean m(boolean x){return false || x;}}").contains("return x;"));
}
#[test]
fn const_fold() {
assert!(run_src("class A{int m(){return 1 + 2;}}").contains("return 3;"));
assert!(run_src("class A{int m(){return 2 * 3;}}").contains("return 6;"));
assert!(run_src("class A{int m(){return 10 - 4;}}").contains("return 6;"));
assert!(run_src("class A{int m(){return 1 << 3;}}").contains("return 8;"));
assert!(run_src("class A{int m(){return 6 & 3;}}").contains("return 2;"));
assert!(run_src("class A{int m(){return 1 << 32;}}").contains("return 1;"));
assert!(run_src("class A{int m(){return 2147483647 + 1;}}").contains("return -2147483648;"));
assert!(run_src("class A{long m(){return 2L * 3L;}}").contains("return 6L;"));
let out = run_src("class A{int m(){return 1 / 0;}}");
assert!(out.contains("1 / 0"), "{out}");
assert!(run_src("class A{String m(){return \"ab\" + \"cd\";}}").contains(r#"return "abcd";"#));
let out = run_src("class A{int m(){return 0x1F;}}");
assert!(out.contains("0x1F"), "{out}");
}
#[test]
fn not_compare() {
assert!(run_src("class A{boolean m(int a, int b){return !(a == b);}}").contains("return a != b;"));
assert!(run_src("class A{boolean m(int a, int b){return !(a < b);}}").contains("return a >= b;"));
assert!(run_src("class A{boolean m(int a, int b){return !(a <= b);}}").contains("return a > b;"));
let out = run_src("class A{boolean m(double a, double b){return !(a < b);}}");
assert!(out.contains("!(a < b)"), "{out}");
assert!(run_src("class A{boolean m(Object a, Object b){return !(a == b);}}").contains("return a != b;"));
}
#[test]
fn ternary_folds() {
assert!(run_src("class A{int m(int x){return true ? 1 : x;}}").contains("return 1;"));
assert!(run_src("class A{int m(int x){return false ? x : 2;}}").contains("return 2;"));
assert!(run_src("class A{int m(boolean c, int x){return c ? x : x;}}").contains("return x;"));
let out = run_src("class A{int m(){return call() ? 1 : 1;}}");
assert!(out.contains("call() ? 1 : 1"), "{out}");
assert!(run_src("class A{boolean m(boolean c){return c ? true : false;}}").contains("return c;"));
assert!(run_src("class A{boolean m(boolean c){return c ? false : true;}}").contains("return !c;"));
}
#[test]
fn arith_zero() {
assert!(run_src("class A{int m(int x){return 0 * x;}}").contains("return 0;"));
assert!(run_src("class A{int m(int x){return x * 0;}}").contains("return 0;"));
let out = run_src("class A{int m(){return 0 * foo();}}");
assert!(out.contains("0 * foo()"), "{out}");
let out = run_src("class A{double m(double x){return 0 * x;}}");
assert!(out.contains("0 * x"), "{out}");
assert!(run_src("class A{int m(int x){return x - x;}}").contains("return 0;"));
assert!(run_src("class A{int m(int x){return x << 0;}}").contains("return x;"));
assert!(run_src("class A{int m(int x){return x >> 0;}}").contains("return x;"));
}
#[test]
fn dead_store() {
assert!(run_src("class A{int m(){int x = 1; x = 2; return x;}}").contains("return 2;"));
assert!(run_src("class A{int m(){int x; x = 1; x = 2; return x;}}").contains("return 2;"));
let out = run_src("class A{int m(){int x; x = foo(); x = 2; return x;}}");
assert!(out.contains("x = foo();"), "{out}");
let out = run_src("class A{int m(){int x = 1; x = x + 2; return x;}}");
assert!(out.contains("return 3;"), "{out}");
assert!(run_src("class A{int m(int b){int x = b; x = x + 2; return x;}}").contains("return b + 2;"));
}
#[test]
fn string_builder_fold() {
let out = run_src(r#"
class A {
String m(int a, String b) {
return new StringBuilder().append(a).append(b).toString();
}
}
"#);
assert!(out.contains("return \"\" + a + b;"), "{out}");
let out = run_src(r#"
class A {
String m(String a, String b) {
return new StringBuilder(a).append(b).toString();
}
}
"#);
assert!(out.contains("return a + b;"), "{out}");
let out = run_src(r#"
class A {
String m() {
return new StringBuilder().append("x").append("y").toString();
}
}
"#);
assert!(out.contains(r#"return "xy";"#), "{out}");
let out = run_src(r#"
class A {
StringBuilder m() {
return new StringBuilder(16);
}
}
"#);
assert!(out.contains("new StringBuilder(16)"), "{out}");
let out = run_src(r#"
class A {
int m() {
return new StringBuilder().append("x").toString().length();
}
}
"#);
assert!(out.contains("return 1;"), "{out}");
}
#[test]
fn box_unbox_chain() {
let out = run_src(r#"
class A {
int m() {
return Integer.valueOf(42).intValue();
}
}
"#);
assert!(out.contains("return 42;"), "{out}");
let out = run_src(r#"
class A {
boolean m(boolean x) {
return Boolean.valueOf(x).booleanValue();
}
}
"#);
assert!(out.contains("return x;"), "{out}");
let out = run_src(r#"
class A {
int m() {
return Integer.valueOf("42").intValue();
}
}
"#);
assert!(out.contains("Integer.valueOf(\"42\")"), "{out}");
}
#[test]
fn iterator_to_for_each() {
let out = run_src(r#"
class A {
int m(java.util.List<String> list) {
int n = 0;
for (java.util.Iterator<String> it = list.iterator(); it.hasNext(); ) {
String s = it.next();
n += s.length();
}
return n;
}
}
"#);
assert!(out.contains("for (String s : list) {"), "{out}");
assert!(!out.contains("Iterator"), "{out}");
let out = run_src(r#"
class A {
int m(java.util.List<String> list) {
int n = 0;
for (java.util.Iterator<String> it = list.iterator(); it.hasNext(); ) {
String s = it.next();
n += s.length() + it.hashCode();
}
return n;
}
}
"#);
assert!(out.contains("it.hashCode()"), "{out}");
}
#[test]
fn unreachable_opt_in() {
let out = run_src("class A{int m(){return 1; call();}}");
assert!(out.contains("call();"), "{out}");
let src = "class A{int m(){return 1; call();}}";
let mut o = parse(src);
let rules = cure_java_simplify::all_java_rules();
if let cure_java_ast::Member::Method { body: Some(b), .. } =
&mut o.unit.types[0].members[0].clone()
{
let report = cure_engine::simplify(&mut o.ast, *b, &rules, &Config::default());
assert!(report.edits >= 1);
let printed = cure_java_print::print(&o.ast, *b);
assert!(printed.contains("return 1;"));
assert!(!printed.contains("call();"), "{printed}");
}
}
#[test]
fn cmp_const_fold() {
assert!(run_src("class A{boolean m(){return 1 < 2;}}").contains("return true;"));
assert!(run_src("class A{boolean m(){return 2 == 3;}}").contains("return false;"));
assert!(run_src("class A{boolean m(){return 5L >= 5L;}}").contains("return true;"));
let out = run_src("class A{boolean m(){return 1.0 < 2.0;}}");
assert!(out.contains("1.0 < 2.0"), "{out}");
let out = run_src(r#"
class A {
String m(int x) {
boolean always = 2 > 1;
if (always) {
return "live";
} else {
return junk();
}
}
}
"#);
assert!(out.contains("return \"live\";"), "{out}");
assert!(!out.contains("junk()"), "{out}");
assert!(!out.contains("always"), "{out}");
}
#[test]
fn bit_identity_rules() {
assert!(run_src("class A{int m(int x){return x ^ 0;}}").contains("return x;"));
assert!(run_src("class A{int m(int x){return 0 | x;}}").contains("return x;"));
assert!(run_src("class A{int m(int x){return x & -1;}}").contains("return x;"));
assert!(run_src("class A{int m(int x){return x | -1;}}").contains("return -1;"));
assert!(run_src("class A{int m(int x){return x & 0;}}").contains("return 0;"));
assert!(run_src("class A{int m(int x){return x ^ x;}}").contains("return 0;"));
let out = run_src("class A{int m(){return foo() & 0;}}");
assert!(out.contains("& 0"), "{out}");
}
#[test]
fn arith_reassoc_rules() {
assert!(run_src("class A{int m(int x){return (x ^ 84) ^ 84;}}").contains("return x;"));
assert!(run_src("class A{int m(int x){return (x + 5) - 5;}}").contains("return x;"));
assert!(run_src("class A{int m(int x){return (x - 3) - 2;}}").contains("return x - 5;"));
assert!(run_src("class A{int m(int x){return (x + 1) + 2;}}").contains("return x + 3;"));
let out = run_src("class A{long m(long x){return (x + 5L) - 5L;}}");
assert!(out.contains("return x;"), "{out}");
}
#[test]
fn if_to_ternary_rules() {
assert!(run_src("class A{int m(boolean c){if (c) {return 1;} else {return 2;}}}").contains("return c ? 1 : 2;"));
assert!(run_src("class A{int m(boolean c){if (c) {return 1;} return 2;}}").contains("return c ? 1 : 2;"));
assert!(run_src("class A{boolean m(boolean c){if (c) {return true;} return false;}}").contains("return c;"));
assert!(run_src("class A{int m(boolean c){int r; if (c) {r = 1;} else {r = 2;} return r;}}").contains("return c ? 1 : 2;"));
let out = run_src("class A{int m(){if (check()) {return 1;} return 2;}}");
assert!(out.contains("check() ? 1 : 2"), "{out}");
}
#[test]
fn new_string_fold_rule() {
assert!(run_src("class A{String m(){return new String(\"lit\");}}").contains(r#"return "lit";"#));
let out = run_src("class A{String m(byte[] b){return new String(b);}}");
assert!(out.contains("new String(b)"), "{out}");
}
#[test]
fn loop_head_break_rules() {
let out = run_src("class A{int m(int n){int s=0; while (true) { if (n >= 5) { break; } s += n; n++; } return s;}}");
assert!(out.contains("while (n < 5)"), "{out}");
let out = run_src("class A{int m(int n){int s=0; while (true) { if (n >= 5) break; else { s += n; } n++; } return s;}}");
assert!(out.contains("while (n < 5)"), "{out}");
let out = run_src("class A{int m(int n){int s=0; while (true) { if (n > 100) { break; } if (n % 2 == 0) { n++; continue; } s += n; n++; } return s;}}");
assert!(out.contains("while (n <= 100)"), "{out}");
assert!(out.contains("continue;"), "{out}");
let out = run_src("class A{int m(){int s=0; outer: while (true) { while (true) { if (ok()) { break outer; } s++; } } }}");
assert!(out.contains("break outer;"), "{out}");
}
#[test]
fn while_iterator_to_for_each_rules() {
let out = run_src(r#"
class A {
int m(java.util.List<String> list) {
int n = 0;
java.util.Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
n += s.length();
}
return n;
}
}
"#);
assert!(out.contains("for (String s : list)"), "{out}");
assert!(!out.contains("Iterator"), "{out}");
let out = run_src(r#"
class A {
int m(java.util.List<String> list) {
int n = 0;
java.util.Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
n += s.length() + it.hashCode();
}
return n;
}
}
"#);
assert!(out.contains("it.hashCode()"), "{out}");
}
#[test]
fn decl_assign_merge_rule() {
assert!(run_src("class A{int m(){int x; x = 5; return x;}}").contains("return 5;"));
assert!(run_src("class A{int m(){int x; x = 1; int y; y = x + 1; return y;}}").contains("return 2;"));
let out = run_src("class A{int m(){int y; y = y + 1; return y;}}");
assert!(out.contains("return y + 1;") || out.contains("y = y + 1;"), "{out}");
}
#[test]
fn assign_propagation_rules() {
let out = run_src("class A{int m(int y){int x = 0; x = y; return x;}}");
assert!(out.contains("return y;"), "{out}");
let out = run_src("class A{int m(){int t = 0; t = foo(); int u = t; return u;}}");
assert!(out.contains("return foo();"), "{out}");
assert!(!out.contains("t = foo();"), "{out}");
assert!(!out.contains("int u"), "{out}");
let out = run_src("class A{int m(int y, int z){int x = 0; x = y; x = z; return x;}}");
assert!(out.contains("return z;"), "{out}");
assert!(!out.contains("x = y;"), "{out}");
assert!(!out.contains("return y;"), "{out}");
let out = run_src(
"class A{int m(int y){int x = 0; x = y; y = 9; System.out.println(y); return x;}}",
);
assert!(!out.contains("return y;"), "{out}");
let out = run_src("class A{int m(int y){int x = 0; x = y; y = 9; return x;}}");
assert!(out.contains("return y;"), "{out}");
}
#[test]
fn string_concat_reassoc_rules() {
let out = run_src("class A{String m(String x){return \"a\" + x + \"b\" + \"c\";}}");
assert!(out.contains(r#"return "a" + x + "bc";"#), "{out}");
let out = run_src("class A{String m(String x){return \"a\" + \"b\" + x;}}");
assert!(out.contains(r#"return "ab" + x;"#), "{out}");
}
#[test]
fn concat_value_of_drop_rule() {
let out = run_src("class A{String m(int n){return String.valueOf(n) + \"-\";}}");
assert!(out.contains("return n + \"-\";"), "{out}");
let out = run_src("class A{String m(int n, Object o){return String.valueOf(n) + o;}}");
assert!(out.contains("String.valueOf(n)"), "{out}");
}
#[test]
fn loop_register_tail_inline() {
let out = run_src("class A{int m(int x, int s){while (x < 5) { int v = x + s; x = v; } return x;}}");
assert!(out.contains("x = x + s;"), "{out}");
let out = run_src("class A{int m(){int i = 1; i = i; return i;}}");
assert!(out.contains("return 1;"), "{out}");
}
#[test]
fn trailing_continue_removed() {
let out = run_src("class A{int m(java.util.List<String> l){int n = 0; for (String s : l) { n += s.length(); continue; } return n;}}");
assert!(!out.contains("continue;"), "{out}");
let out = run_src("class A{int m(int a, int b){int n = 0; outer: while (a > 0) { while (b > 0) { n++; continue outer; } a--; } return n;}}");
assert!(out.contains("continue outer;"), "{out}");
let out = run_src("class A{int m(){int n = 0; self: while (n < 3) { n++; continue self; } return n;}}");
assert!(!out.contains("continue"), "{out}");
}
#[test]
fn multi_use_copy_propagation() {
let out = run_src("class A{int m(int y){int x = 0; int z = 0; x = y; if (x > 1) { z = x; } return x + z;}}");
assert!(out.contains("if (y > 1)"), "{out}");
assert!(out.contains("return y + z;"), "{out}");
assert!(!out.contains("x = y;"), "{out}");
let out = run_src(
"class A{int m(int y, int w){int x = 0; x = y; y = w; System.out.println(y); return x;}}",
);
assert!(out.contains("return x;"), "{out}");
assert!(!out.contains("return y;"), "{out}");
let out = run_src("class A{int m(int y, int w){int x = 0; x = y; y = w; return x;}}");
assert!(out.contains("return y;"), "{out}");
}
#[test]
fn string_builder_statement_chain() {
let out = run_src(r#"
class A {
String m(String x, String y) {
StringBuilder sb = new StringBuilder().append("h");
sb = sb.append(x);
StringBuilder sb2 = sb.append("-");
sb2 = sb2.append(y);
String s = sb2.toString();
return s;
}
}
"#);
assert!(out.contains(r#"return "h" + x + "-" + y;"#), "{out}");
let out = run_src(r#"
class A {
String m(String x) {
StringBuilder sb = new StringBuilder().append("h");
sb = sb.append(x);
int len = sb.length();
String s = sb.toString();
return s + len;
}
}
"#);
assert!(out.contains("new StringBuilder"), "{out}");
let out = run_src("class A{String m(){StringBuilder sb = new StringBuilder(); String s = sb.toString(); return s;}}");
assert!(out.contains("return \"\";"), "{out}");
}
#[test]
fn dad_artifact_class_name_and_trailing_return() {
let out = run_src("public class LDemo; {\n public Demo(int p1) {\n this.base = p1;\n return;\n }\n}\nclass Aux {\n int x;\n}");
assert!(out.contains("public class Demo {"), "{out}");
assert!(out.contains("this.base = p1;"), "{out}");
assert!(!out.contains("return;"), "{out}"); }
#[test]
fn trailing_return_rule() {
let out = run_src("class A{void m(){foo(); return;}}");
assert!(out.contains("foo();"), "{out}");
assert!(!out.contains("return;"), "{out}");
let out = run_src("class A{int m(){return 1;}}");
assert!(out.contains("return 1;"), "{out}");
let out = run_src("class A{void m(int x){if (x > 0) {return;} foo(); return;}}");
assert!(out.contains("if (x > 0) {"), "{out}");
let cnt = out.matches("return;").count();
assert_eq!(cnt, 1, "{out}"); }
#[test]
fn iterator_with_cast_and_paren() {
let out = run_src(r#"
class A {
void m(java.util.List<String> list) {
java.util.Iterator it = list.iterator();
while (it.hasNext()) {
String s = ((String) it.next());
System.out.println(s);
}
}
}
"#);
assert!(out.contains("for (String s : list)"), "{out}");
}
#[test]
fn store_kill_rules() {
let out = run_src("class A{int m(){int v = 0; foo(); v = 1; return v;}}");
assert!(out.contains("foo();"), "{out}");
assert!(out.contains("return 1;"), "{out}");
assert!(!out.contains("int v"), "{out}");
let out = run_src("class A{int m(int y){int v = 0; foo(); v = y; return v;}}");
assert!(out.contains("foo();"), "{out}");
assert!(out.contains("return y;"), "{out}");
let out = run_src("class A{int m(int y){int v = 0; v = 0; foo(); v = y; return v;}}");
assert!(!out.contains("v = 0;"), "{out}");
assert!(out.contains("return y;"), "{out}");
}
#[test]
fn store_kill_safety_cases() {
let out = run_src("class A{int m(){int v = bump(); v = 5; return v;}}");
assert!(out.contains("int v = bump();"), "{out}");
let out = run_src("class A{int m(int c){int v = 0; if (c > 0) { v = 1; } return v;}}");
assert!(out.contains("int v = 0;"), "{out}");
let out = run_src("class A{int m(){int v = 0; while (v < 3) { v = 9; } return v;}}");
assert!(out.contains("return 9;"), "{out}");
let out = run_src("class A{String m(){String v = \"\"; String w = v + \"x\"; v = \"y\"; return w;}}");
assert!(out.contains("return \"x\";"), "{out}");
}
#[test]
fn cff_nested_conditional() {
let src = r#"
public class NestC {
public static void main(String[] args) {
int x = 8;
String r = null;
int s = 0;
while (true) {
switch (s) {
case 0: {
if (x > 0) {
s = 1;
} else {
s = 5;
}
break;
}
case 1: {
if (x > 10) {
s = 2;
} else {
s = 3;
}
break;
}
case 2: {
r = "big";
s = 4;
break;
}
case 3: {
r = "mid";
s = 4;
break;
}
case 5: {
r = "neg";
s = 4;
break;
}
}
if (s == 4) {
break;
}
}
System.out.println("r=" + r);
}
}
"#;
let mut outcome = parse(src);
assert!(outcome.errors.is_empty());
let report = cure_java_simplify::simplify_unit(&mut outcome.ast, &mut outcome.unit, &Config::default());
let cleaned = cure_java_print::print_unit(&outcome.ast, &outcome.unit);
assert!(report.by_rule.contains_key("cff_recover"), "CFF 未触发:\n{cleaned}");
assert!(!cleaned.contains("switch"), "{cleaned}");
assert!(cleaned.contains("x > 0"), "{cleaned}");
assert!(cleaned.contains("x > 10"), "{cleaned}");
assert!(
cleaned.contains(r#"x > 0 ? x > 10 ? "big" : "mid" : "neg""#),
"{cleaned}"
);
}
#[test]
fn loop_head_break_dowhile_forms() {
let out = run_src(r#"
class A {
int m(java.util.List<String> l) {
int n = 0;
java.util.Iterator<String> it = l.iterator();
do {
if (it.hasNext()) {
n += it.next().length();
continue;
} else {
break;
}
} while (true);
return n;
}
}
"#);
assert!(out.contains("for (String e : l)"), "{out}");
assert!(!out.contains("do"), "{out}");
assert!(!out.contains("Iterator"), "{out}");
let out = run_src(r#"
class A {
int m(java.util.List<String> l) {
int n = 0;
java.util.Iterator<String> it = l.iterator();
while (true) {
if (it.hasNext()) {
n += 1;
continue;
} else {
break;
}
}
return n;
}
}
"#);
assert!(out.contains("while (it.hasNext())"), "{out}");
assert!(!out.contains("continue"), "{out}");
let out = run_src("class A{int m(int x){int s = 0; while (true) { if (x < 0) { break; } else { s += x; x--; continue; } } return s;}}");
assert!(out.contains("while (x >= 0)"), "{out}");
assert!(!out.contains("continue"), "{out}");
}
#[test]
fn inline_next_extraction_to_for_each() {
let out = run_src(r#"
class A {
void m(java.util.List<String> list) {
String acc = "";
java.util.Iterator it = list.iterator();
while (it.hasNext()) {
acc = acc + (String) it.next() + "-";
}
System.out.println(acc);
}
}
"#);
assert!(out.contains("for (String e : list)"), "{out}");
assert!(out.contains("acc = acc + e"), "{out}");
assert!(!out.contains("Iterator"), "{out}");
assert!(!out.contains("next()"), "{out}");
let out = run_src(r#"
class A {
void m(java.util.List<String> list) {
java.util.Iterator it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next() + it.next().length());
}
}
}
"#);
assert!(out.contains("it.next()"), "{out}");
}
#[test]
fn reassoc_i32_overflow_wraps() {
let out = run_src("class A{int f(int x){return (x + 2147483647) + 1;}}");
assert!(!out.contains("+ 2147483648"), "非法字面量泄漏: {out}");
assert!(out.contains("- 2147483648") || out.contains("+ -2147483648"), "{out}");
let back = parse(&out);
assert!(back.errors.is_empty(), "{:?}", back.errors);
let out = run_src("class A{long f(long x){return (x + 9223372036854775806L) + 2L;}}");
assert!(out.contains("- 9223372036854775808L") || out.contains("+ -9223372036854775808L"), "{out}");
}
#[test]
fn fold_i32_min_negation_refused() {
let mut out = parse("class A{int f(){int a = -3 - 4; int b = -2147483648 - 0; return -(-2147483648 - 0);}}");
cure_java_simplify::simplify_unit(&mut out.ast, &mut out.unit, &Config::default());
let printed = cure_java_print::print_unit(&out.ast, &out.unit);
assert!(!printed.contains("return 2147483648;"), "{printed}");
let back = parse(&printed);
assert!(back.errors.is_empty(), "{:?}", back.errors);
}
#[test]
fn fold_neg_normal_still_works() {
let _out = run_src("class A{int f(){int a = -3 - 4; return -a;}}");
let out2 = run_src("class A{int f(){return -(-7);}}");
assert!(out2.contains("return 7;"), "{out2}");
}
#[test]
fn inverse_pair_compound_cascades() {
let src = "class A{int f(){int a;a+=1;a-=1;a+=1;a-=1;return 7;}}";
let out = run_src(src);
assert!(out.contains("return 7;"), "{out}");
assert!(!out.contains("a += 1;") || !out.contains("a -= 1;"), "{out}");
let src2 = "class A{int f(){int a;a+=5;a-=5;return a;}}";
let out2 = run_src(src2);
assert!(out2.contains("return a;"), "{out2}");
assert!(!out2.contains("+= 5;") && !out2.contains("-= 5;"), "{out2}");
}
#[test]
fn inverse_pair_expanded_and_mixed_forms() {
let out = run_src("class A{int f(int x){x=x+5;x=x-5;return x;}}");
assert!(out.contains("return x;"), "{out}");
let out = run_src("class A{int f(int x){x+=5;x=x-5;return x;}}");
assert!(out.contains("return x;"), "{out}");
let out = run_src("class A{int f(int x){x^=42;x^=42;return x;}}");
assert!(out.contains("return x;"), "{out}");
let out = run_src("class A{int f(int x){x-=3;x+=3;return x;}}");
assert!(out.contains("return x;"), "{out}");
}
#[test]
fn inverse_pair_safety_guards() {
let out = run_src("class A{double f(double x){x+=1;x-=1;return x;}}");
assert!(out.contains("x += 1;"), "{out}");
let out = run_src("class A{int f;int g(){f+=1;f-=1;return f;}}");
assert!(out.contains("f += 1;"), "{out}");
let out = run_src("class A{int f(int x){x+=1;int y=x*2;x-=1;return y;}}");
assert!(out.contains("x += 1;"), "{out}");
let out = run_src("class A{int f(int x){x+=1;x-=2;return x;}}");
assert!(out.contains("x += 1;"), "{out}");
let out = run_src("class A{long f(long x){x+=9223372036854775807L;x-=9223372036854775807L;return x;}}");
assert!(out.contains("return x;"), "{out}");
assert!(!out.contains("+="), "{out}");
}
#[test]
fn register_accumulator_folds_to_return_expr() {
let out = run_src(
"class T{int fee(int base){int r2;r2=base;r2=r2+30;return r2;}}",
);
assert!(out.contains("return base + 30;"), "{out}");
let out = run_src(
"class T{int f(int b){int x=b;int y=8;y=y+1;x=x+30;return x+y;}}",
);
assert!(out.contains("return b + 39;"), "{out}");
let out = run_src("class T{int f(int b){int x=b;x+=30;return x;}}");
assert!(out.contains("return b + 30;"), "{out}");
let out = run_src("class T{int f(int b){int x=b;x+=1;x+=2;return x;}}");
assert!(out.contains("return b + 3;"), "{out}");
let out = run_src("class T{int f(int b){int x=b;x^=42;return x;}}");
assert!(out.contains("return b ^ 42;"), "{out}");
}
#[test]
fn assign_back_fold_safety_negatives() {
let out = run_src("class T{int f(){int x=5;int y=x;x=x+1;return y*10+x;}}");
assert!(out.contains("return 56;"), "{out}");
let out = run_src("class T{int f(){int x=5;int y=x;x=x+1;return y*10;}}");
assert!(out.contains("50"), "{out}");
let out = run_src("class T{int f(int b){int x=b;x=99;x=x+1;return x;}}");
assert!(out.contains("return 100;") || out.contains("x + 1"), "{out}");
let out = run_src("class T{int f(int b,boolean c){int x=b;if(c){x=x+1;}return x;}}");
assert!(out.contains("if"), "{out}");
let out = run_src("class T{int f(int b){int x=b;int y=0;x=x/0;return y;}}");
assert!(out.contains("/ 0"), "{out}");
let out = run_src("class T{int f(int b,int k){int x=b;x=x+k;return x;}}");
assert!(out.contains("x + k") || out.contains("x += k") || out.contains("b + k"), "{out}");
}
#[test]
fn dead_decl_removal_and_guards() {
let out = run_src("class T{int f(){int r1;return 7;}}");
assert!(out.contains("return 7;") && !out.contains("r1"), "{out}");
let out = run_src("class T{int f(){int x=5;return 7;}}");
assert!(!out.contains("int x"), "{out}");
let out = run_src("class T{int f(){int x=5;return x;}}");
assert!(out.contains("return 5;"), "{out}");
let out = run_src("class T{int f(){int x=foo();return 7;}}");
assert!(out.contains("foo();"), "{out}");
let out = run_src("class T{int f(){int x=1/0;return 7;}}");
assert!(out.contains("1 / 0"), "{out}");
}
#[test]
fn demo_register_noise_full_collapse() {
let out = run_src(
"class Ticket{int fee(int base){int r1;int r2;r1=base;r2=r1;r1+=7;r1-=7;\
boolean flag;flag=(2<3)&&true;if(flag){r2=r2+30;}r1=r2*1;int k=0x5A^0x5A;return r1+k;}}",
);
assert!(out.contains("return base + 30;"), "{out}");
}
#[test]
fn narrow_type_compound_not_folded() {
let out = run_src("class A{void m(){char ch='a';ch+=2;System.out.println(ch);}}");
assert!(out.contains("ch += 2;") || out.contains("ch = ch + 2;"), "{out}");
let out = run_src("class A{int m(){byte b=100;b+=100;return b;}}");
assert!(out.contains("return -56;"), "{out}");
let out = run_src("class A{int m(int x){int i=x;i+=5;return i;}}");
assert!(out.contains("return x + 5;"), "{out}");
}
#[test]
fn char_decl_int_literal_normalized() {
let out = run_src("class A{void m(){char c = 98;System.out.println(c);}}");
assert!(out.contains("'b'"), "{out}");
let out = run_src("class A{void m(){char c = 70000;System.out.println(c);}}");
assert!(out.contains("70000"), "{out}");
let out = run_src("class A{void m(){char c='x';System.out.println(c);}}");
assert!(out.contains("'x'"), "{out}");
}
#[test]
fn field_write_not_killed_as_dead_store() {
let out = run_src(
"class A{static A first;A next;static A add(A c){if(first!=null){c.next=first;first.prev=c;}first=c;return c;}}",
);
assert!(out.contains("first = c;"), "{out}");
let out = run_src("class T{boolean done;T set(int o){done=false;return this;}}");
assert!(out.contains("done = false;") || out.contains("done = false"), "{out}");
}
#[test]
fn alias_propagation_keeps_store_targets() {
let out = run_src(
"class B{static String[] r;static{char[] v=\"aq\".toCharArray();char[] t=v;for(int k=0;v.length>k;++k){t[k]=(char)(v[k]^123);}r=new String[]{new String(t).intern()};}}",
);
let has_decl = out.contains("char[] t = v;");
let store_uses_t = out.contains("t[k]");
assert_eq!(has_decl, store_uses_t, "{out}");
let back = parse(&out);
assert!(back.errors.is_empty(), "{:?}", back.errors);
}
#[test]
fn pure_call_stmt_deleted_not_bare_literal() {
let out = run_src("class A{void m(){String.valueOf(7);\"\".concat(\"\");}}");
assert!(out.contains("void m() {}"), "{out}");
let out = run_src("class A{void m(){foo();}}");
assert!(out.contains("foo();"), "{out}");
}
#[test]
fn null_not_inlined_into_receiver() {
let out = run_src("class A{void m(){O o=null;o.setArg(\"x\");}}");
assert!(out.contains("o.setArg") && (out.contains("O o = null;")), "{out}");
let back = parse(&out);
assert!(back.errors.is_empty(), "{:?}", back.errors);
}
#[test]
fn rethrow_only_catch_unwrapped() {
let out = run_src("class A{double m() throws E{try{if(d==0)return 0.0;}catch(E v){throw v;}return 1.0;}}");
assert!(!out.contains("try"), "{out}");
assert!(!out.contains("catch"), "{out}");
let out = run_src("class A{void m(){try{f();}catch(E e){throw e;}catch(R r){log(r);}}}");
assert!(out.contains("catch (R r)"), "{out}");
assert!(out.contains("catch (E e)"), "{out}");
let out2 = run_src("class A{void m() throws R{try{f();}catch(E e){log(e);}catch(R r){throw r;}}}");
assert!(!out2.contains("catch (R r)"), "{out2}");
assert!(out2.contains("catch (E e)"), "{out2}");
}
#[test]
fn sealed_interface_clause_order() {
let out = run_src("sealed interface S extends A permits C {}");
assert!(out.contains("extends A permits C"), "{out}");
let back = parse(&out);
assert!(back.errors.is_empty(), "{:?}", back.errors);
}
#[test]
fn multiline_package_with_comments() {
let src = "package com . foo // c\n .bar. // d\n baz;\nclass A{}";
let mut out = parse(src);
cure_java_simplify::simplify_unit(&mut out.ast, &mut out.unit, &Config::default());
let printed = cure_java_print::print_unit(&out.ast, &out.unit);
assert!(printed.contains("package com.foo.bar.baz;"), "{printed}");
let back = parse(&printed);
assert!(back.errors.is_empty(), "{:?}", back.errors);
}
#[test]
fn url_decode_fold_visible_only() {
let out = run_src(r#"class A{String m(){return java.net.URLDecoder.decode("%E4%BD%A0%E5%A5%BD%2C+world%21", "UTF-8");}}"#);
assert!(out.contains("你好, world!"), "{out}");
let out = run_src(r#"class A{String m(){return java.net.URLDecoder.decode("a+b", "UTF-8");}}"#);
assert!(out.contains("a b"), "{out}");
let out = run_src(r#"class A{static String s = java.net.URLDecoder.decode("%41%42", "UTF-8");}"#);
assert!(out.contains("s = \"AB\""), "{out}");
}
#[test]
fn url_decode_guards() {
let out = run_src(r#"class A{String m(){return java.net.URLDecoder.decode("%01%02", "UTF-8");}}"#);
assert!(out.contains("decode("), "{out}");
let out = run_src(r#"class A{String m(){return java.net.URLDecoder.decode("%zz", "UTF-8");}}"#);
assert!(out.contains("decode("), "{out}");
let out = run_src(r#"class A{String m(){return java.net.URLDecoder.decode("%41", "GBK");}}"#);
assert!(out.contains("decode("), "{out}");
let out = run_src(r#"class A{String m(){return java.net.URLDecoder.decode("%E4%BD", "UTF-8");}}"#);
assert!(out.contains("decode("), "{out}");
}
#[test]
fn field_init_root_folds() {
let out = run_src("class A{static int x=1+2;static long y=2L*3;static boolean b=true&&false;}");
assert!(out.contains("x = 3;"), "{out}");
assert!(out.contains("y = 6L;"), "{out}");
assert!(out.contains("b = false;"), "{out}");
}
#[test]
fn clinit_single_write_private_static_propagates() {
let out = run_src(
"class A{private static String a;static{a=\"SHA\";int x=1;int y=2;}static void m(){System.out.println(a);}}",
);
assert!(out.contains("println(\"SHA\");"), "{out}");
}
#[test]
fn clinit_dead_first_write_collapses_to_last() {
let out = run_src(
"class A{private static String a;static{a=\"X\";a=\"Y\";int x=1;int y=2;}static void m(){System.out.println(a);}}",
);
assert!(out.contains("a = \"Y\";"), "{out}");
assert!(out.contains("println(\"Y\");"), "{out}");
assert!(!out.contains("\"X\""), "{out}");
}
#[test]
fn clinit_write_in_method_no_propagation() {
let out = run_src(
"class A{private static String a;static{a=\"X\";int x=1;int y=2;}static void m(){a=\"Y\";}static void n(){System.out.println(a);}}",
);
assert!(out.contains("println(a);"), "{out}");
}
#[test]
fn clinit_read_only_rest_keeps_prefix_field_writes() {
let out = run_src(
"class A{private static String a;static{a=\"V\";int x=1;int y=2;java.util.Objects.requireNonNull(a);}static void m(){System.out.println(a);}}",
);
assert!(out.contains("a = \"V\";"), "{out}");
assert!(out.contains("requireNonNull(\"V\");"), "{out}");
assert!(out.contains("println(\"V\");"), "{out}");
assert!(!out.contains("int x = 1;"), "{out}");
}
#[test]
fn clinit_reassignment_in_rest_bails() {
let out = run_src(
"class A{static String a;static{a=\"V\";int x=1;int y=2;java.util.Objects.requireNonNull(a);a=\"W\";}static void m(){System.out.println(a);}}",
);
assert!(out.contains("a = \"V\";"), "{out}");
assert!(out.contains("a = \"W\";"), "{out}");
assert!(out.contains("requireNonNull(a);"), "{out}");
assert!(out.contains("println(a);"), "{out}");
}
#[test]
fn partial_statement_field_write_not_dumped() {
let out = run_src(
"class A{private static String a;static{int x=1;int y=2;int z=3;try{a=\"A\";System.out.println(a);}catch(Exception e){}}static void m(){System.out.println(a);}}",
);
assert_eq!(out.matches("a = \"A\";").count(), 1, "{out}");
assert!(out.contains("try"), "{out}");
assert!(out.contains("println(a);"), "{out}");
}
#[test]
fn const_field_method_name_collision() {
let out = run_src(
"class A{private static String a;static{a=\"S\";int x=1;int y=2;}static void a(int q){}static void m(){a(1);System.out.println(a);}}",
);
assert!(out.contains("a(1);"), "{out}");
assert!(out.contains("println(\"S\");"), "{out}");
}
#[test]
fn const_field_assign_target_preserved() {
let out = run_src(
"class A{private static String a;static{a=\"S\";int x=1;int y=2;System.out.println(a);}}",
);
assert!(out.contains("a = \"S\";"), "{out}");
assert!(out.contains("println(\"S\");"), "{out}");
}
#[test]
fn nested_class_write_blocks_private_propagation() {
let out = run_src(
"class A{private static String a;static{a=\"S\";int x=1;int y=2;}static class B{static void n(){a=\"T\";}}static void m(){System.out.println(a);}}",
);
assert!(out.contains("println(a);"), "{out}");
}
#[test]
fn nested_same_name_field_blocks_propagation() {
let out = run_src(
"class A{private static String a;static{a=\"S\";int x=1;int y=2;}static class B{String a;}static void m(){System.out.println(a);}}",
);
assert!(out.contains("println(a);"), "{out}");
}
#[test]
fn type_mismatch_long_int_not_propagated() {
let out = run_src(
"class A{static final long L=5;static void m(){System.out.println(L);}}",
);
assert!(out.contains("println(L);"), "{out}");
}
#[test]
fn this_a_write_blocks_propagation() {
let out = run_src(
"class A{private static String a;static{a=\"S\";int x=1;int y=2;}void m(){this.a=\"T\";}static void n(){System.out.println(a);}}",
);
assert!(out.contains("println(a);"), "{out}");
}
#[test]
fn decl_init_final_propagates_and_array_index_folds() {
let out = run_src(
"class A{static final String S=\"tag\";static final String[] T={\"p\",\"q\"};static void m(){System.out.println(S+T[1]);}}",
);
assert!(out.contains("println(\"tagq\");"), "{out}");
}
fn run_dead(src: &str) -> String {
let mut out = parse(src);
let cfg = Config { remove_dead_methods: true, ..Config::default() };
cure_java_simplify::simplify_unit(&mut out.ast, &mut out.unit, &cfg);
cure_java_print::print_unit(&out.ast, &out.unit)
}
#[test]
fn dead_private_fields_removed() {
let out = run_dead(
"class A{private static final boolean e=false;private static final String x=\"\";private static PrintWriter writer;private static int used=1;static void m(){System.out.println(used);}}",
);
assert!(!out.contains("boolean e"), "{out}");
assert!(!out.contains("String x"), "{out}");
assert!(!out.contains("PrintWriter writer"), "{out}");
assert!(out.contains("used"), "{out}");
}
#[test]
fn referenced_field_kept_and_default_keeps_dead_fields() {
let src = "class A{private int dead=0;private int live=1;int m(){return live;}}";
let out = run_dead(src);
assert!(!out.contains("dead"), "{out}");
assert!(out.contains("live"), "{out}");
let out2 = run_src(src);
assert!(out2.contains("dead"), "{out2}");
}
#[test]
fn field_side_effectful_init_kept() {
let out = run_dead(
"class A{private static Object o=System.getProperties();static void m(){}}",
);
assert!(out.contains("getProperties()"), "{out}");
}
#[test]
fn field_method_name_collision_field_removed() {
let out = run_dead(
"class A{private static final boolean e=false;static void e(int q){}static void m(){e(1);}}",
);
assert!(!out.contains("boolean e"), "{out}");
assert!(out.contains("e(1);"), "{out}");
}
#[test]
fn this_member_ref_keeps_field() {
let out = run_dead(
"class A{private static int e=0;int m(){return this.e;}}",
);
assert!(out.contains("e"), "{out}");
}
#[test]
fn noop_private_calls_removed() {
let out = run_dead(
"class A{private static java.util.Hashtable c;static{c=new java.util.Hashtable();int x=1;int y=2;b(c);g(c);}private static void b(java.util.Hashtable q){}private static void g(java.util.Hashtable q){System.out.println(q);}}",
);
assert!(!out.contains("b(c);"), "{out}");
assert!(out.contains("g(c);"), "{out}");
assert!(!out.contains("void b("), "{out}");
assert!(out.contains("void g("), "{out}");
}
#[test]
fn noop_call_impure_arg_kept() {
let out = run_dead(
"class A{static int[] arr=new int[]{1};private static void b(int q){}static{int x=1;int y=2;b(arr[0]);}}",
);
assert!(out.contains("b(arr[0]);"), "{out}");
}
#[test]
fn noop_call_overload_same_arity_kept() {
let out = run_dead(
"class A{private static void b(Object q){}public static void b(String q){}static{int x=1;int y=2;b((Object)null);}}",
);
assert!(out.contains("b((Object) null);"), "{out}");
assert!(out.contains("void b("), "{out}");
}
#[test]
fn noop_call_varargs_vetoed() {
let out = run_dead(
"class A{private static void b(int q){}static void b(int... q){}static{int x=1;int y=2;b(1);}}",
);
assert!(out.contains("b(1);"), "{out}");
}
#[test]
fn noop_call_methodref_vetoed() {
let out = run_dead(
"class A{private static void b(int q){}interface I{void r(int v);}I f(){return A::b;}static{int x=1;int y=2;b(1);}}",
);
assert!(out.contains("b(1);"), "{out}");
}
#[test]
fn dead_method_arity_separation() {
let out = run_dead(
"class A{private static void b(Object p,Object q){}public static String b(String s){return s;}static void m(){System.out.println(\"k\");}}",
);
assert!(!out.contains("(Object p, Object q)"), "{out}");
assert!(out.contains("String b(String s)"), "{out}");
}
#[test]
fn dead_code_default_off() {
let src = "class A{private static void b(int q){}static{int x=1;int y=2;b(1);}}";
let out = run_src(src);
assert!(out.contains("b(1);"), "{out}");
assert!(out.contains("void b("), "{out}");
}
#[test]
fn sub_block_truncation_folds_label_prefix() {
let out = run_src(
"class A{static String f;static{int x=1;int y=2;lbl:{f=\"java.math.BigInteger\";Class.forName(f);System.out.println(f);}}static void m(){System.out.println(f);}}",
);
assert!(out.contains("f = \"java.math.BigInteger\";"), "{out}");
assert!(out.contains("Class.forName(\"java.math.BigInteger\");"), "{out}");
assert!(out.contains("System.out.println(f);"), "{out}");
assert!(!out.contains("int x = 1;"), "{out}");
}
#[test]
fn class_forname_non_jdk_aborts() {
let out = run_src(
"class A{static String f;static{int x=1;int y=2;lbl:{f=\"com.foo.Missing\";Class.forName(f);System.out.println(f);}}static void m(){System.out.println(f);}}",
);
assert!(out.contains("Class.forName(f);"), "{out}");
assert!(!out.contains("int x = 1;"), "{out}");
}
#[test]
fn forname_unknown_class_name_aborts() {
let out = run_src(
"class A{static String f;static{int x=1;int y=2;Class.forName(f);}}static void m(){System.out.println(f);}}",
);
assert!(out.contains("Class.forName(f);"), "{out}");
}
#[test]
fn noop_call_type_resolves_overload() {
let out = run_dead(
"class A{private static java.util.Hashtable h;static{h=new java.util.Hashtable();int x=1;int y=2;e(h);}private static void e(java.util.Hashtable q){}public static void e(String q){System.out.println(q);}}",
);
assert!(!out.contains("e(h);"), "{out}");
assert!(!out.contains("void e(java.util.Hashtable"), "{out}");
assert!(out.contains("void e(String"), "{out}");
}
#[test]
fn noop_call_type_mismatch_kept() {
let out = run_dead(
"class A{static{int x=1;int y=2;e(\"s\");}private static void e(java.util.Hashtable q){}public static void e(String q){System.out.println(q);}}",
);
assert!(out.contains("e(\"s\");"), "{out}");
}
#[test]
fn noop_call_null_arg_ambiguous_kept() {
let out = run_dead(
"class A{static{int x=1;int y=2;e(null);}private static void e(java.util.Hashtable q){}public static void e(String q){System.out.println(q);}}",
);
assert!(out.contains("e(null);"), "{out}");
}
#[test]
fn unused_import_removed_with_dead_field() {
let out = run_dead(
"import java.io.PrintWriter;class A{private PrintWriter w;int m(){return 1;}}",
);
assert!(!out.contains("PrintWriter"), "{out}");
}
#[test]
fn used_import_kept() {
let out = run_dead(
"import java.io.PrintWriter;class A{PrintWriter w;int m(){return 1;}}",
);
assert!(out.contains("import java.io.PrintWriter;"), "{out}");
}
#[test]
fn generic_type_usage_keeps_import() {
let out = run_dead(
"import java.util.List;class A{java.util.Map<String, List> f;int m(){return 1;}}",
);
assert!(out.contains("import java.util.List;"), "{out}");
}
#[test]
fn import_used_by_class_literal_kept() {
let out = run_dead(
"import java.util.List;class A{boolean m(Class c){return List.class.isAssignableFrom(c);}}",
);
assert!(out.contains("import java.util.List;"), "{out}");
}
#[test]
fn import_used_by_instanceof_kept() {
let out = run_dead(
"import java.sql.SQLException;class A{boolean m(Object o){return o instanceof SQLException;}}",
);
assert!(out.contains("import java.sql.SQLException;"), "{out}");
}
#[test]
fn import_used_by_catch_type_kept() {
let out = run_dead(
"import java.io.UnsupportedEncodingException;class A{String m(String s){try{return new String(s.getBytes(\"UTF-8\"));}catch(UnsupportedEncodingException e){return s;}}}",
);
assert!(out.contains("import java.io.UnsupportedEncodingException;"), "{out}");
}
#[test]
fn nonfinal_reassign_in_rest_allows_materialize() {
let out = run_src(
"class A{static String c;static{c=\"V\";int x=1;int y=2;java.util.Objects.requireNonNull(c);c=\"W\";}static void m(){System.out.println(c);}}",
);
assert!(out.contains("c = \"V\";"), "{out}");
assert!(out.contains("c = \"W\";"), "{out}");
assert!(!out.contains("int x = 1;"), "{out}");
}
#[test]
fn final_reassign_in_rest_still_bails() {
let out = run_src(
"class A{static final String c;static{int x=1;int y=2;c=\"V\";java.util.Objects.requireNonNull(c);c=\"W\";}static void m(){System.out.println(c);}}",
);
let v_count = out.matches("c = \"V\";").count();
assert!(v_count <= 1, "{out}");
assert!(out.contains("c = \"W\";"), "{out}");
}
#[test]
fn ternary_equal_branch_respects_member_names() {
let out = run_src(
"class A{String m(Object o, boolean c){return c ? o.hashCode() : o.toString();}}",
);
assert!(out.contains("o.hashCode() : o.toString()"), "{out}");
let out2 = run_src(
"class A{String m(Object o, boolean c){return c ? o.toString() : o.toString();}}",
);
assert!(out2.contains("o.toString();"), "{out2}");
assert!(!out2.contains("?"), "{out2}");
let out3 = run_src(
"class A{int m(A x, boolean c){return c ? x.f : x.g;}}",
);
assert!(out3.contains("x.f : x.g"), "{out3}");
}
#[test]
fn lone_surrogate_roundtrip_preserved() {
let out = run_src("class A{String s=\"\\ud800\";String t=\"\\udfff\";char c='\\ud800';}");
assert!(out.contains("\\uD800"), "{out}");
assert!(out.contains("\\uDFFF"), "{out}");
assert!(!out.contains('\u{fffd}'), "{out}");
}
#[test]
fn lone_surrogate_concat_folds_correctly() {
let out = run_src("class A{String a=\"\\ud800\"+\"x\";String b=\"\\ud800\"+\"\\udfff\";}");
assert!(out.contains("\"\\uD800x\""), "{out}");
assert!(out.contains("\"\\uD800\\uDFFF\""), "{out}");
}
#[test]
fn escaping_alias_between_arrays_preserved() {
let out = run_src(
"class A{static Object b;static{int x=1;int y=2;char[] v9=\"\\u0016$\".toCharArray();char[] var17=v9;char[] var39=v9;var39[0]=(char)(var39[0]^22);System.out.println(var39[0]);var39[1]=(char)(var39[1]^22);b=new String(var17);}}",
);
assert!(out.contains("var39 = var17"), "{out}");
let literals = out.matches("new char[]").count();
assert!(literals <= 1, "{out}");
}
#[test]
fn try_with_resources_not_descended() {
let out = run_src(
"class A{static int closed;static int f;static{int x=1;int y=2;int z=3;try(java.util.List<String> r=java.util.List.of()){f=5;}catch(Exception e){}System.out.println(closed);}}",
);
assert!(out.contains("try ("), "{out}");
assert!(out.contains("close") || !out.contains("close"), "{out}");
let t = out.matches("try (").count();
assert!(t >= 1, "{out}");
}
#[test]
fn finally_effects_materialized() {
let out = run_src(
"class A{static String f;static{int x=1;int y=2;int z=3;try{int b=2;}finally{f=\"fin\";}System.out.println(f);}}",
);
assert!(out.contains("f = \"fin\";"), "{out}");
assert!(out.contains("System.out.println(f);"), "{out}");
}
#[test]
fn catch_clauses_visible_to_escaping() {
let out = run_src(
"class A{static String f;static String u;static{int x=1;int y=2;int z=3;lbl:{String s=\"v\";try{f=s;String t=u;}catch(Exception e){f=s;}}}}",
);
assert!(out.contains("f = \"v\";") || out.contains("f = s;"), "{out}");
}
#[test]
fn dead_store_sees_assign_target_index_reads() {
let out = run_src(
"class A{static char[] a;static{char[] arr=\"abc\".toCharArray();int j=0;lbl:{arr[j]='x';j++;String t=System.console()==null?null:null;arr[j]='q';}a=arr;}}",
);
assert!(
out.contains("arr[1] = 'q';")
|| (out.contains("j") && out.contains("arr[j] = 'q';")),
"{out}"
);
assert!(out.contains("'x'"), "{out}");
}
#[test]
fn long_domain_propagation_no_i32_wrap() {
let out = run_src(
"class A{static String g;static{long n=5;long y=n+2147483647;g=String.valueOf(y);}}",
);
assert!(out.contains("2147483652"), "{out}");
}
#[test]
fn char_domain_survives_materialization() {
let out = run_src(
"class A{static String h;static String u;static{int x=1;int y=2;int z=3;lbl:{char c='x';String t=u;h=String.valueOf(c);}}}",
);
assert!(out.contains("h = \"x\";"), "{out}");
}
#[test]
fn text_block_value_not_folded() {
let out = run_src(
"class A{void m(){assert(\"\"\"\n \\s\n \"\"\".equals(\" \\n\"));}}",
);
assert!(out.contains("\"\"\""), "{out}");
assert!(!out.contains("assert false;"), "{out}");
}
#[test]
fn mismatched_ctor_name_raw_preserved() {
let out = run_src("class Inner{int x;public Wrong(){x=1;}}");
assert!(out.contains("public Wrong(){x=1;}"), "{out}");
}
#[test]
fn ternary_equal_branch_respects_type_payloads() {
let out = run_src(
"class A{Object m(boolean f){return f?new FairSync():new NonfairSync();}class FairSync{}class NonfairSync{}}",
);
assert!(out.contains("new FairSync() : new NonfairSync()"), "{out}");
let out2 = run_src(
"class A{Object m(boolean f){return f?new FairSync():new FairSync();}class FairSync{}}",
);
assert!(out2.contains("new FairSync();"), "{out2}");
let out3 = run_src(
"class A{Object m(Object s, boolean c){return c?((String)s).length():((Integer)s).hashCode();}}",
);
assert!(out3.contains("((String) s).length()"), "{out3}");
let out4 = run_src(
"class A{Object m(boolean c){return c?new int[1]:new long[1];}}",
);
assert!(out4.contains("new int[1] : new long[1]"), "{out4}");
let out5 = run_src("class A{int m(boolean c){return c?0x1F:31;}}");
assert!(out5.contains("return 0x1F;") || out5.contains("return 31;"), "{out5}");
}
#[test]
fn rethrow_catch_removal_respects_later_catches() {
let out = run_src(
"class A{String d(String s){return s;}String m(StringBuilder b){try{return b.toString();}catch(IllegalStateException e){throw e;}catch(Throwable t){throw new RuntimeException(d(t.getMessage()));}}}",
);
assert!(out.contains("catch (IllegalStateException e)"), "{out}");
assert!(out.contains("catch (Throwable t)"), "{out}");
}
#[test]
fn new_string_unwrap_unit_level_identity_guard() {
let out = run_src(
"class A{String txt=new String(\"hello\");boolean c(){return txt==\"hello\";}}",
);
assert!(out.contains("new String(\"hello\")"), "{out}");
}
#[test]
fn qualified_new_with_type_args_roundtrip() {
let out = run_src(
"class A{class Inner{Inner(String s){}}Object m(A a){return a.new Inner(\"x\").new <String>Inner(\"y\");}}",
);
assert!(out.contains(".new <String>Inner(\"y\")"), "{out}");
}
#[test]
fn compound_assign_long_rhs_narrows() {
let out = run_src(
"class A{static int f;static{int x=1;int y=2;int z=3;byte b=100;b+=100L;int r=b+1;f=r;}}",
);
assert!(out.contains("f = -55;"), "{out}");
}
#[test]
fn int_compound_assign_long_rhs_wraps() {
let out = run_src(
"class A{static int f;static{int x=1;int y=2;int z=3;int i=1;i+=3000000000L;f=i;}}",
);
assert!(out.contains("f = -1294967295;"), "{out}");
}
#[test]
fn narrow_decl_int_literal_not_inlined_into_call_args() {
let out = run_src(
"class A{static void eat(byte a,short b){}static void m(){byte b=127;short s=1023;eat(b,s);}}",
);
assert!(out.contains("eat(b, s);"), "{out}");
}
#[test]
fn char_short_long_rhs_materialize_domains() {
let out = run_src(
"class A{static void eat(char c,short s){}static{int x=1;int y=2;int z=3;char c='a';c+=1L;short sh=1000;sh+=1L;String t=System.console()==null?null:null;eat(c,sh);}}",
);
assert!(out.contains("eat('b', ") || out.contains("eat(c, "), "{out}");
assert!(!out.contains("98L"), "{out}");
}
#[test]
fn user_class_named_string_not_folded() {
let out = run_src(
"class A{static class String{}Object m(){return new A.String();}}",
);
assert!(out.contains("new A.String();"), "{out}");
}
#[test]
fn nested_kill_in_do_while_not_statement_deleted() {
let out = run_src(
"class A{static boolean f=true;static void run(boolean c){f=true;do{f=false;work();}while(c);}}",
);
assert!(out.contains("do {"), "{out}");
assert!(out.contains("while (c);"), "{out}");
assert!(out.contains("work();"), "{out}");
}
#[test]
fn nested_kill_in_bare_block_not_statement_deleted() {
let out = run_src(
"class A{static int n;static boolean f=true;static void run(){f=true;{work();f=false;}n=1;}}",
);
assert!(out.contains("work();"), "{out}");
assert!(out.contains("f = false;"), "{out}");
}
#[test]
fn when_guard_sentinel_forms_all_parse() {
let src = r#"class WG {
String m(Object expr) {
return switch (expr) {
case Integer i when List.of(1,2).stream().anyMatch(x -> x < i) -> "lam";
case String s when (s instanceof String) -> "paren";
case Object rp when consult -> "bare";
case Number n when n.intValue() < 64 -> "cmp";
default -> "other";
};
}
int consult = 1;
}"#;
let out = run_src(src);
assert!(out.contains("anyMatch(x -> x < i)"), "{out}");
assert!(out.contains("when (s instanceof String)"), "{out}");
assert!(out.contains("when consult"), "{out}");
assert!(out.contains("when n.intValue() < 64"), "{out}");
}
#[test]
fn iterator_element_type_from_declaration() {
let out = run_src(
"class A{class W{byte[] data;}java.util.Map<W,Object> m=new java.util.HashMap<>();void k(java.util.Set<W> s){java.util.Iterator<W> it=m.keySet().iterator();while(it.hasNext()){s.add(it.next().data);}}}",
);
assert!(out.contains("for (W e : m.keySet())"), "{out}");
assert!(out.contains("e.data"), "{out}");
}
#[test]
fn signed_zero_not_folded_in_ternary() {
let out = run_src(
"class A{double m(boolean b){return b ? 0.0 : -0.0;}double n(boolean b){return b ? -0.0 : 0.0;}}",
);
assert!(out.contains("b ? 0.0 : -0.0;"), "{out}");
assert!(out.contains("b ? -0.0 : 0.0;"), "{out}");
}
#[test]
fn identity_assert_blocks_new_string_unwrap() {
let out = run_src(
"class A{void t(){String s1=new String(\"a\");String s2=new String(\"a\");org.junit.Assert.assertNotSame(s1,s2);}}",
);
assert!(out.contains("new String(\"a\")"), "{out}");
}
#[test]
fn dead_code_blind_refs_cover_raw_and_annotations() {
let out = run_dead(
"class A{private int helper(int y){return y;}void m(){@SuppressWarnings(\"x\")int r=helper(1);System.out.println(r);}}",
);
assert!(out.contains("helper"), "{out}");
let out2 = run_dead(
"class B{private static final int METHOD_NAME=1;@Method(name=METHOD_NAME) void t(){}}",
);
assert!(out2.contains("METHOD_NAME"), "{out2}");
let out3 = run_dead(
"enum C{A{void x(){work();}};private void work(){}}",
);
assert!(out3.contains("work"), "{out3}");
}
#[test]
fn dead_code_blind_refs_cover_annotation_raw_bodies() {
let out = run_dead(
"import java.util.concurrent.TimeUnit;\n@interface T{TimeUnit unit() default TimeUnit.SECONDS;}\nclass UsesIt{}",
);
assert!(out.contains("import java.util.concurrent.TimeUnit;"), "{out}");
let out2 = run_dead(
"class A{private static int helper(int x){return x;}private static final int MAGIC=42;private static final int DEAD=7;@interface R{class Inner{int g(){return helper(3)+MAGIC;}}}}",
);
assert!(out2.contains("helper"), "{out2}");
assert!(out2.contains("MAGIC"), "{out2}");
assert!(!out2.contains("DEAD"), "{out2}");
}
#[test]
fn dead_code_lambda_param_type_keeps_import() {
let out = run_dead(
"import java.util.Map;\nclass L{Object m(){java.util.function.Function<Map.Entry<String,Integer>,Integer> f=e->e.getValue();return f;}}",
);
assert!(out.contains("import java.util.Map;"), "{out}");
}
#[test]
fn dead_code_bare_methodsource_keeps_factory() {
let out = run_dead(
"class T{@org.junit.jupiter.params.provider.MethodSource void t(int x){}private static java.util.stream.Stream<org.junit.jupiter.params.Arguments> t(){return java.util.stream.Stream.of();}}",
);
assert!(out.contains("private static java.util.stream.Stream<org.junit.jupiter.params.Arguments> t()"), "{out}");
let out2 = run_dead(
"class T{@MethodSource void t(int x){}private static Object t(){return null;}}",
);
assert!(out2.contains("private static Object t()"), "{out2}");
let out3 = run_dead(
"class T{void t(int x){}private static Object t(){return null;}}",
);
assert!(!out3.contains("private static Object t()"), "{out3}");
}
#[test]
fn static_exec_labeled_break_in_loop() {
let out = run_src(
"class T{static int a;static{int x=0;outer:while(x<100){if(x==3){break outer;}x++;}a=x;}}",
);
assert!(out.contains("a = 3") || out.contains("a=3"), "{out}");
}
#[test]
fn static_exec_labeled_continue_in_loop() {
let out = run_src(
"class T{static int a;static{int x=0;int n=0;outer:while(x<6){x++;if(x%2==0){continue outer;}n++;}a=n;}}",
);
assert!(out.contains("a = 3") || out.contains("a=3"), "{out}");
}
#[test]
fn static_exec_labeled_block_break() {
let out = run_src(
"class T{static int a;static{int x=1;lbl:{if(x==1){break lbl;}x=100;}a=x;}}",
);
assert!(out.contains("a = 1") || out.contains("a=1"), "{out}");
}
#[test]
fn static_exec_switch_labeled_break_escapes() {
let out = run_src(
"class T{static int a;static{int x=0;outer:while(true){switch(x){case 0:x=1;break;default:x=50;break outer;}if(x==1){x=2;break;}}a=x;}}",
);
assert!(out.contains("a = 2") || out.contains("a=2"), "{out}");
}
#[test]
fn dead_code_witness_callee_keeps_method() {
let out = run_dead(
"class A{private <T> T pick(T x){return x;}String a=this.<String>pick(\"witness-call\");}",
);
assert!(out.contains("pick(T x)"), "{out}");
}
#[test]
fn dead_code_witness_method_ref_veto() {
let out = run_dead(
"class A{private static Object nil(){return null;}java.util.function.Supplier<Object> a=A::<String>nil;private static Object unused(){return null;}}",
);
assert!(out.contains("nil()"), "{out}");
assert!(!out.contains("unused()"), "{out}");
}
#[test]
fn p1_barrier_refused_inside_try() {
let src = "class T{static String r;static int k;static{k=2;try{r=opaque(1);}catch(RuntimeException e){r=\"caught\";}k=k+1;}static String opaque(int i){throw new RuntimeException(\"boom\");}}";
let out = run_src(src);
assert!(out.contains("try"), "{out}");
assert!(out.contains("catch"), "{out}");
assert!(out.contains("opaque(1)"), "{out}");
let src2 = "class T{static String r;static int k;static{k=2;try{r=opaque(1);}catch(RuntimeException e){r=\"caught\";k=99;}finally{k=k+1;}}static String opaque(int i){throw new RuntimeException(\"boom\");}}";
let out2 = run_src(src2);
assert!(out2.contains("finally"), "{out2}");
assert!(out2.contains("k = 99"), "{out2}");
}
#[test]
fn p1_barrier_still_works_outside_try() {
let out = run_src(
"class T{static String r;static{int y=1+2;r=Other.opaque(y);}}",
);
assert!(out.contains("Other.opaque(3)"), "{out}");
assert!(!out.contains("int y"), "{out}");
}
#[test]
fn new_string_identity_not_collapsed() {
let out = run_src(
"class T{void m(){Object one=new String(\"1243\");Object two=new String(\"1243\");if(one==two){throw new RuntimeException(\"same\");}}}",
);
assert!(out.contains("new String(\"1243\")"), "{out}");
let out2 = run_src(
"class T{static String r;static{r=new String(\"ab\").intern();}}",
);
assert!(out2.contains("\"ab\""), "{out2}");
}
#[test]
fn const_method_inline_overload_blind() {
let out = run_src(
"class T{static class B{int f(){return 1;}}private B a(String f,Object... args){return new B();}private B a(B b){return b;}int m(){return a(\"\").f();}}",
);
assert!(out.contains("a(\"\")"), "{out}");
}
#[test]
fn local_propagation_raw_receiver_refused() {
let out = run_src(
"class T{interface M{java.util.List list();}void m(M mock){java.util.List list=mock.list();list.add(\"test\");}}",
);
assert!(out.contains("java.util.List list = mock.list();"), "{out}");
let out2 = run_src(
"class T{static class B{int x(){return 1;}}static B make(){return new B();}int m(){B b=make();return b.x();}}",
);
assert!(out2.contains("return make().x();"), "{out2}");
}
#[test]
fn foreach_bare_next_statement_unconditional_only() {
let out = run_src(
"class T{void m(java.util.List<String> list){java.util.Iterator<String> it=list.iterator();while(it.hasNext()){try{it.next();}catch(Exception ignore){}}}}",
);
assert!(out.contains("while (it.hasNext())"), "{out}");
assert!(out.contains("it.next();"), "{out}");
assert!(!out.contains(" e;"), "{out}");
let out2 = run_src(
"class T{void m(java.util.List<String> list){java.util.Iterator<String> it=list.iterator();while(it.hasNext()){it.next();}}}",
);
assert!(out2.contains("for (String e : list)"), "{out2}");
assert!(!out2.contains("e;"), "{out2}");
}
#[test]
fn static_exec_try_window_barrier_refused() {
let out = run_src(
"class T{static String r;static int k;static{k=2;try{r=opaque(1);}catch(RuntimeException e){r=\"caught\";}k=k+1;}static String opaque(int i){throw new RuntimeException(\"boom\");}}",
);
assert!(out.contains("catch"), "{out}");
assert!(out.contains("k = k + 1") || out.contains("k = 3") || out.contains("k = 2"), "{out}");
}
#[test]
fn intern_arity_guard_offset_count() {
let out = run_src(
"class T{static String r;static{r=new String(\"abcdef\".toCharArray(),1,3).intern();}}",
);
assert!(out.contains("new String"), "{out}");
}
#[test]
fn foreach_conditional_consumption_refused() {
let out = run_src(
"class T{void m(java.util.List<String> list){java.util.Iterator<String> it=list.iterator();while(it.hasNext()){for(int k=0;k<3;k++){it.next();}}}}",
);
assert!(out.contains("while (it.hasNext())"), "{out}");
let out2 = run_src(
"class T{void m(java.util.List<String> list){java.util.Iterator<String> it=list.iterator();while(it.hasNext()){String s=it.hasNext()&&it.next()!=null?\"a\":\"b\";}}}",
);
assert!(out2.contains("while (it.hasNext())"), "{out2}");
let out3 = run_src(
"class T{String m(java.util.List<String> list){java.util.Iterator<String> it=list.iterator();String acc=\"\";while(it.hasNext()){acc=acc+it.next()+\"-\";}return acc;}}",
);
assert!(out3.contains("for (String e : list)"), "{out3}");
}
#[test]
fn foreach_var_avoids_catch_param() {
let out = run_src(
"class T{void m(java.util.List<String> list){java.util.Iterator<String> it=list.iterator();while(it.hasNext()){String s=it.next();try{System.out.println(s);}catch(Exception e){}}}}",
);
assert!(!out.contains("for (String e : list) {") || !out.contains("catch (Exception e)"), "{out}");
}
#[test]
fn foreach_lambda_deferred_consumption_refused() {
let out = run_src(
"class T{static int park(java.util.function.Supplier<?> s){return 0;}void m(java.util.List<String> list){java.util.Iterator<String> it=list.iterator();int n=0;while(it.hasNext()){park(()->it.next());n++;if(n>10){break;}}}}",
);
assert!(out.contains("while (it.hasNext())"), "{out}");
}
#[test]
fn foreach_assert_consumption_refused() {
let out = run_src(
"class T{void m(java.util.List<String> list){java.util.Iterator<String> it=list.iterator();int n=0;while(it.hasNext()){assert it.next()!=null;n++;if(n>10){break;}}}}",
);
assert!(out.contains("while (it.hasNext())"), "{out}");
}
#[test]
fn foreach_var_avoids_lambda_twr_instanceof_bindings() {
let out = run_src(
"class T{static int park(java.util.function.IntUnaryOperator s){return 0;}void m(java.util.List<String> list) throws Exception{java.util.Iterator<String> it=list.iterator();while(it.hasNext()){it.next();park(e->0);try(java.io.StringReader e=new java.io.StringReader(\"x\")){}Object o=\"y\";if(o instanceof String e){System.out.println(e);}}}}",
);
let fcount = out.matches("for (String e").count();
let ebinds = out.matches(" e").count();
assert!(fcount <= 1, "{out}");
if out.contains("for (String") {
let var = out
.lines()
.find(|l| l.contains("for (String"))
.and_then(|l| l.split("for (String ").nth(1))
.and_then(|r| r.split(" :").next())
.unwrap_or("");
assert_ne!(var.trim(), "e", "{out}");
}
let _ = ebinds;
}
#[test]
fn primitive_boxing_receiver_not_propagated() {
let out = run_src(
"class T{Object m(char c,int i){Object o=+c;Object p=i;return o.getClass().getSimpleName()+p.getClass().getSimpleName();}}",
);
assert!(out.contains("o.getClass()"), "{out}");
assert!(out.contains("p.getClass()"), "{out}");
assert!(!out.contains("65.getClass()"), "{out}");
let out2 = run_src(
"class T{final char c='A';Object m(){Object o=+c;return o.getClass().getSimpleName();}}",
);
assert!(out2.contains("o.getClass()"), "{out2}");
}
#[test]
fn raw_abstractset_receiver_refused() {
let out = run_src(
"class T{static java.util.AbstractSet<String> mk(){return null;}void m(Object o){java.util.AbstractSet s=mk();s.add(o);}}",
);
assert!(out.contains("java.util.AbstractSet s = mk();"), "{out}");
}
#[test]
fn vexec_materialization_restores_ref_decl_type() {
let out = run_src(
"class T{static java.util.List<String> out=new java.util.ArrayList<>();static{int i=1,j=2;Object o=i+j;out.add(\"h\"+o.hashCode());}}",
);
assert!(out.contains("Object o = 3;"), "{out}");
}
#[test]
fn boxing_receiver_call_member_index_forms() {
let out = run_src(
"class T{String m(String s,boolean c,Object x){Object o=c?'a':'b';o.hashCode();Character ch=s.charAt(0);return ch.toString();}}",
);
assert!(out.contains("o.hashCode()"), "{out}");
assert!(out.contains("ch.toString()"), "{out}");
}
#[test]
fn instanceof_operand_primitive_refused() {
let out = run_src(
"class T{void m(){Integer i=42;Object x=i;if(x instanceof Integer j){System.out.println(j);}}}",
);
assert!(out.contains("x instanceof Integer j"), "{out}");
}
#[test]
fn var_ternary_fold_refused() {
let out = run_src(
"class T{void m(){var o1=false?new Object(){}:null;Runnable r=()->System.out.println(o1==o1);r.run();var o2=true?null:new Object(){};r=()->System.out.println(o2==o2);r.run();}}",
);
assert!(out.contains("var o1 = false ? new Object() {} : null;"), "{out}");
assert!(out.contains("var o2 = true ? null : new Object() {};"), "{out}");
}
#[test]
fn var_switch_yield_branch_kept() {
let out = run_src(
"class T{void m(){var o3=switch(0){default->{if(false)yield new Object(){};else yield null;}};System.out.println(o3);var o4=switch(0){default->{if(true)yield null;else yield new Object(){};}};System.out.println(o4);}}",
);
assert!(out.contains("if (false)"), "{out}");
assert!(out.contains("yield new Object() {};"), "{out}");
assert!(out.contains("if (true)"), "{out}");
}
#[test]
fn explicit_type_ternary_still_folds() {
let out = run_src(
"class T{void m(){Object o=false?new Object(){}:null;System.out.println(o==o);}}",
);
assert!(out.contains("Object o = null;"), "{out}");
}
#[test]
fn var_identical_arm_ternary_still_folds() {
let out = run_src("class T{void m(boolean c){var x=c?\"a\":\"a\";System.out.println(x);}}");
assert!(!out.contains("?"), "{out}");
assert!(out.contains("System.out.println(\"a\");"), "{out}");
}
#[test]
fn array_base_newarray_parenthesized() {
let out = run_src(
"class Q{String f(){return \"x\";}}class T{void m(){Q[] a=new Q[1];String s=a[0].f();System.out.println(s);}}",
);
assert!(out.contains("(new Q[1])[0].f()"), "{out}");
}
#[test]
fn array_base_generic_decl_inlin_refused() {
let out = run_src(
"class T{class A<X>{class B<W>{public X rett(){return null;}}}class C extends A<String>{{B<?>[] b2=new B[1];String s2=b2[0].rett();System.out.println(s2);}}}",
);
assert!(out.contains("B<?>[] b2 = new B[1];"), "{out}");
assert!(out.contains("b2[0].rett()"), "{out}");
}
#[test]
fn if_true_break_in_case_group_kept() {
let out = run_src(
"class T{void m(int c){switch(c){case 1:if(true)break;int i=1;default:i=2;System.out.println(i);}}}",
);
assert!(out.contains("if (true)"), "{out}");
assert!(out.contains("int i = 1;"), "{out}");
}
#[test]
fn if_true_break_block_trailing_deleted() {
let out = run_src(
"class T{void m(boolean c){while(c){if(true)break;foo();}}void foo(){}}",
);
assert!(out.contains("break;"), "{out}");
assert!(!out.contains("foo();"), "{out}");
}
#[test]
fn receiver_new_type_mismatch_refused() {
let out = run_src(
"interface I{Object clone() throws CloneNotSupportedException;}class C implements I{public Object clone(){return null;}}class T{Object m(){try{I a0=new C();return a0.clone();}catch(CloneNotSupportedException e){return null;}}}",
);
assert!(out.contains("I a0 = new C();"), "{out}");
assert!(out.contains("a0.clone()"), "{out}");
}
#[test]
fn receiver_new_same_name_still_inlines() {
let out = run_src(
"class F{void bar(){}}class T{void m(){F f=new F();f.bar();}}",
);
assert!(out.contains("new F().bar()"), "{out}");
}
#[test]
fn receiver_diamond_refused() {
let out = run_src(
"class TS{TS(String s){}}class T{void m(){java.util.List<String> l=new java.util.ArrayList<>();l.stream().forEach(TS::new);}}",
);
assert!(out.contains("List<String> l = new java.util.ArrayList<>();"), "{out}");
assert!(out.contains("l.stream()"), "{out}");
}
#[test]
fn multi_annotation_dims_all_positions() {
let out = run_src(
"class T{@interface A1{}@interface A2{}void m(int x @A1 @A2 []){}int f @A1 @A2 [];void n(){int y @A1 @A2 []=null;}}",
);
assert!(out.contains("int x @A1 @A2 []"), "{out}");
assert!(out.contains("int f @A1 @A2 []"), "{out}");
assert!(out.contains("int y @A1 @A2 []"), "{out}");
}
#[test]
fn enum_double_comma_no_growth() {
let p1 = run_src("enum G{A, , B}");
let p2 = run_src(&p1);
assert_eq!(p1, p2, "not idempotent: {p1}");
}
#[test]
fn unit_raws_visible_to_import_analysis() {
let out = run_dead(
"import java.util.List;\nclass A{int m(){return 1;}}\n<T> { private List<T> x; }\n",
);
assert!(out.contains("import java.util.List;"), "{out}");
}
#[test]
fn type_side_dims_annotations_all_positions() {
let out = run_src(
"class T{@interface A{}int @A [] f3;void m3(int @A [] x){}T(int @A [] x){}void n(){int @A [] l3=null;for(int @A [] fe:new int[2][]){}}}",
);
assert!(out.contains("@A [] f3;"), "{out}");
assert!(out.contains("m3(int @A [] x)"), "{out}");
assert!(out.contains("T(int @A [] x)"), "{out}");
assert!(out.contains("@A [] l3"), "{out}");
assert!(out.contains("int @A [] fe"), "{out}");
}
#[test]
fn subsequent_declarator_dims_annotations_raw() {
let out = run_src(
"class T{@interface A{}int a1, b1 @A [];void n(){int la, lb @A [];for(int i, j @A [];;){break;}}}",
);
assert!(out.contains("b1 @A []"), "{out}");
assert!(out.contains("lb @A []"), "{out}");
assert!(out.contains("j @A []"), "{out}");
}
#[test]
fn param_dims_annos_method_raw_not_over_swallow() {
let out = run_src(
"class T{@interface A{}void m1(int x @A []){}int q(){return 1+1;}}",
);
assert!(out.contains("return 2;"), "{out}");
assert!(out.contains("int x @A []"), "{out}");
}
#[test]
fn const_method_inline_statement_position_guard() {
let out = run_src(
"class T{static class S{public int a;}static class B{public S a=new S();}static B mk(String s){return new B();}static final S e(String str){return mk(str).a;}void use(){e(\"x\");S q=e(\"y\");}}",
);
assert!(out.contains("e(\"x\");"), "{out}");
}