use cure_engine::Config;
use cure_java_parser::parse;
use cure_java_simplify::simplify_unit;
use cure_java_print::print_unit;
fn run_src(src: &str) -> String {
let mut out = parse(src);
simplify_unit(&mut out.ast, &mut out.unit, &Config::default());
print_unit(&out.ast, &out.unit)
}
#[test]
fn null_arg_keeps_typed_var_form() {
let out = run_src(
r#"
public class NullArg {
public static void main(String[] args) {
String s = null;
StringBuilder sb = new StringBuilder();
sb.append(s);
System.out.println(sb.length());
}
}
"#,
);
assert!(
out.contains("sb.append(s);"),
"null 单次使用位于重载族实参位:必须保持变量形态(声明类型 = 消歧依据)\n{out}"
);
assert!(
!out.contains("append(null)"),
"append(null) 不可编译(CharSequence/char[] 二义)\n{out}"
);
}
#[test]
fn null_return_position_still_propagates() {
let out = run_src(
r#"
public class NullRet {
static String f(int x) {
String s = null;
if (x > 0) {
s = "pos";
}
return s;
}
public static void main(String[] args) {
System.out.println(f(1) + f(-1));
}
}
"#,
);
assert!(out.contains("return"), "return 必然保留\n{out}");
}
#[test]
fn null_cast_position_still_propagates() {
let out = run_src(
r#"
public class NullCast {
public static void main(String[] args) {
String s = null;
String t = (String) s;
System.out.println(t == null);
}
}
"#,
);
assert!(
!out.contains(") s;") || out.contains("(String) null"),
"Cast 位应放行内联((String) null 合法)\n{out}"
);
}
#[test]
fn while_iterator_opaque_type_stays_while() {
let out = run_src(
r#"
import java.util.Iterator;
import java.util.NoSuchElementException;
public class OpaqueSeqLoop {
static class Seq {
private final String[] items;
Seq(String[] items) { this.items = items; }
Iterator<String> iterator() {
return new Iterator<String>() {
int i = 0;
public boolean hasNext() { return i < items.length; }
public String next() {
if (!hasNext()) { throw new NoSuchElementException(); }
return items[i++];
}
};
}
}
static String firstNonEmpty(Seq seq) {
Iterator<String> it = seq.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.length() > 0) {
return s;
}
}
return "";
}
public static void main(String[] args) {
Seq seq = new Seq(new String[] {"", "hit", "x"});
System.out.println(firstNonEmpty(seq));
}
}
"#,
);
assert!(
out.contains("while (it.hasNext())"),
"不透明 Iterable(非白名单类型)必须保留 while 形态\n{out}"
);
assert!(
!out.contains("for (String s : seq)"),
"for-each 对非 Iterable 类型不可编译\n{out}"
);
}
#[test]
fn while_iterator_typed_list_still_recovers() {
let out = run_src(
r#"
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class TypedListLoop {
static int total(List<String> names) {
Iterator<String> it = names.iterator();
int n = 0;
while (it.hasNext()) {
String s = it.next();
n += s.length();
}
return n;
}
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("alpha");
names.add("beta");
System.out.println(total(names));
}
}
"#,
);
assert!(
out.contains("for (String s : names)"),
"List 白名单类型应还原 for-each\n{out}"
);
}
#[test]
fn const_method_inline_owner_guard() {
let out = run_src(
r#"
public class ValOf {
static java.lang.Integer TRUE_C = java.lang.Integer.valueOf(-1);
static java.lang.Boolean valueOf(boolean p) {
return !p ? Boolean.FALSE : Boolean.TRUE;
}
static Object bare() {
return valueOf(false);
}
static Object qualified() {
return ValOf.valueOf(true);
}
public static void main(String[] args) {
System.out.println(TRUE_C + "" + bare() + qualified());
}
}
"#,
);
assert!(
out.contains("Integer.valueOf(-1)"),
"Integer.valueOf 必须原样保留(归属不符)\n{out}"
);
assert!(!out.contains("!-1"), "撞名误内联的坏形态不得出现\n{out}");
assert!(
out.contains("return Boolean.TRUE;"),
"同类裸名 valueOf(false) 应内联并折叠\n{out}"
);
assert!(
out.contains("return Boolean.FALSE;"),
"同类限定 ValOf.valueOf(true) 应内联并折叠\n{out}"
);
}
#[test]
fn enum_constant_shadows_outer_const_field() {
let out = run_src(
r#"
public class Enc {
private static final java.lang.String b17 = "hm";
public static enum E {
a, b17;
private static final Enc.E[] c;
private E() {}
static {
c = new Enc.E[] {a, b17};
}
}
public static void main(String[] args) {
System.out.println(b17 + E.c[1]);
}
}
"#,
);
assert!(
out.contains("new Enc.E[] {a, b17}"),
"枚举常量 b17 不得被外层同名字段字面量替换\n{out}"
);
assert!(
!out.contains("{a, \"hm\"}"),
"坏形态(枚举常量→字符串字面量)不得出现\n{out}"
);
}
#[test]
fn typed_var_not_inlined_into_cast_position() {
let out = run_src(
r#"
public class CastPos {
static Object src() { return null; }
public static void main(String[] args) {
Object obj5 = src();
String s = (String) obj5;
boolean b = obj5 instanceof java.lang.String;
System.out.println(s + b);
}
}
"#,
);
assert!(
out.contains("(String) obj5"),
"cast 操作数位的 Object 中转变量必须保持变量形态\n{out}"
);
assert!(
out.contains("obj5 instanceof"),
"instanceof 被测式位同理保持变量形态\n{out}"
);
}
#[test]
fn while_iterator_no_post_loop_reference() {
let out = run_src(
r#"
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class PostUse {
static java.util.List<String> saved;
static int consume(List<String> src) {
Iterator<String> it = src.iterator();
int n = 0;
while (it.hasNext()) {
n += it.next().length();
}
// 循环后引用 it(状态机保存块的形状)
String marker = (it == null) ? "x" : "y";
return n + marker.length();
}
public static void main(String[] args) {
List<String> src = new ArrayList<>();
src.add("alpha");
System.out.println(consume(src));
}
}
"#,
);
assert!(
out.contains("while (it.hasNext())"),
"循环后仍引用迭代器 → 不得还原 for-each(声明会被消费)\n{out}"
);
}
#[test]
fn ctor_delegation_hoist_with_inline() {
let out = run_src(
r#"
public class Hoist {
Hoist(long p1, long p2) {}
Hoist(long p1, long p2, int p3, Object marker) {
long v5;
long v6 = 0L;
v5 = (p3 & 1) == 0 ? p1 : 0L;
v6 = (p3 & 2) == 0 ? p2 : 9223372036854775807L;
this(v5, v6);
Object[] box = new Object[] { Long.valueOf(v5), Long.valueOf(v6) };
System.out.println(box.length);
}
public static void main(String[] args) {
new Hoist(1L, 2L);
}
}
"#,
);
assert!(
out.contains("this((p3 & 1) == 0 ? p1 : 0L, (p3 & 2) == 0 ? p2 : 9223372036854775807L);"),
"委托须在首位且实参内联三元\n{out}"
);
}
#[test]
fn ctor_delegation_hoist_rejects_impure_pre() {
let out = run_src(
r#"
public class NoHoist {
NoHoist(int a) {}
NoHoist(int p, Object m) {
side(p);
this(p);
}
static int side(int x) { return x + 1; }
public static void main(String[] args) { new NoHoist(1); }
}
"#,
);
let side_pos = out.find("side(p);").unwrap_or(usize::MAX);
let this_pos = out.find("this(p);").unwrap_or(usize::MAX);
assert!(
side_pos < this_pos,
"不纯前置(裸调用)不得被跨过提升\n{out}"
);
}
#[test]
fn ctor_delegation_hoist_recursive_arg() {
let out = run_src(
r#"
public class RecHoist {
RecHoist(int a, int b) {}
RecHoist(int p1, Object m) {
int v6 = 0;
v6 = p1 + 1;
this(p1, v6);
System.out.println(v6);
}
public static void main(String[] args) { new RecHoist(7); }
}
"#,
);
assert!(
out.contains("this(p1, p1 + 1);"),
"实参内联:this(p1, p1 + 1)\n{out}"
);
}
#[test]
fn dead_pure_call_statements_removed() {
let out = run_src(
r#"
public class DeadCmp {
static long scale(long p0x, long p1x, String s) {
Long.compare(p1x, 0L);
if (p1x > 0L) {
Long.compare(p0x, 0L);
if (p0x > 0L) {
boolean empty = s.isEmpty();
return empty ? (p1x + p0x) / 2L : 0L;
}
}
java.util.Objects.toString(s);
return 0L;
}
public static void main(String[] args) {
System.out.println(scale(4L, 2L, "x"));
}
}
"#,
);
assert!(!out.contains(".compare("), "丢弃结果的 compare 语句应删除\n{out}");
assert!(!out.contains("Objects.toString"), "Objects.toString 语句应删除\n{out}");
assert!(out.contains("if (p1x > 0L)"), "真分支保留\n{out}");
}
#[test]
fn dead_pure_call_boxed_operand_kept() {
let out = run_src(
r#"
public class BoxedCmp {
static int f(Long x) {
Long.compare(x, 0L);
return x == null ? -1 : 1;
}
public static void main(String[] args) {
System.out.println(f(null));
}
}
"#,
);
assert!(out.contains("Long.compare(x, 0L);"), "装箱实参的 compare 保留(拆箱 NPE 语义)\n{out}");
}
#[test]
fn double_cast_object_hop_folded() {
let out = run_src(
r#"
public class CastFold {
static String f(android.view.View view) {
Object child = null;
if (view instanceof android.view.ViewGroup) {
child = ((android.view.ViewGroup) (Object) view).getChildAt(0);
}
return child == null ? "" : child.toString();
}
static String g(Object o) {
return ((String) (Object) o).trim();
}
public static void main(String[] args) {
System.out.println(f(null) + g("x"));
}
}
"#,
);
assert!(
!out.contains(") (Object) "),
"双重 cast 应折叠为单 cast\n{out}"
);
assert!(out.contains("(String) o"), "折叠后应保留单 cast\n{out}");
}
#[test]
fn double_cast_unrelated_interfaces_kept() {
let out = run_src(
r#"
interface A {}
interface B {}
public class CastKeep {
static A f(Object o) {
return (A) (Object) o;
}
public static void main(String[] args) {
System.out.println(f(null));
}
}
"#,
);
assert!(!out.contains("(Object) o"), "Object 中转应被折叠\n{out}");
}
#[test]
fn trailing_else_flatten() {
let out = run_src(
r#"
public class ElseFlat {
static int f(int x) {
if (x > 0) {
return 1;
} else {
int y = x * 2;
return y;
}
}
public static void main(String[] args) {
System.out.println(f(5) + f(-3));
}
}
"#,
);
assert!(!out.contains("} else {"), "尾随 else 应展平\n{out}");
}
#[test]
fn trailing_else_void_return_removed() {
let out = run_src(
r#"
public class VoidRet {
static void g(boolean c) {
if (c) {
System.out.println("yes");
return;
} else {
return;
}
}
public static void main(String[] args) { g(true); g(false); }
}
"#,
);
assert!(!out.contains("} else {"), "else 仅裸 return 应删除\n{out}");
}
#[test]
fn trailing_else_throw_kept_flattened() {
let out = run_src(
r#"
public class ThrowFlat {
static int h(int x) {
if (x < 0) {
throw new IllegalArgumentException("neg");
} else {
return x + 1;
}
}
public static void main(String[] args) {
System.out.println(h(1));
}
}
"#,
);
assert!(!out.contains("} else {"), "throw 终结的 else 也应展平\n{out}");
}