analysis: keep-lock mixin classes and plugins from mixins.json configs

This commit is contained in:
Loki 2026-10-10 10:02:38 +02:00
parent 6a68c9d69b
commit 21a7c3df1a
Signed by: boba
GPG key ID: 253067914055423B
5 changed files with 279 additions and 104 deletions

View file

@ -0,0 +1,75 @@
//! Mixin keep: classes listed in `*.mixins.json` (and the plugin) stay.
//!
//! The Mixin framework resolves mixin classes and their members by name at
//! runtime, so renaming them breaks the mod at startup. Entries use simple
//! names relative to the `package` field, which generic text patching can
//! never see - locking is the only sound answer.
#![allow(clippy::expect_used, clippy::unwrap_used)]
use noxis_analysis::Analysis;
use noxis_classfile::{ClassBuilder, Program, Resource, Version};
use noxis_core::Config;
const MIXINS: &str = r#"{
"package": "demo.mixin",
"plugin": "demo.mixin.Plugin",
"mixins": ["TargetMixin", "other.Helper"],
"client": ["ClientMixin"]
}"#;
const FABRIC: &str = r#"{
"id": "demo",
"mixins": ["demo.mixins.json"]
}"#;
fn sample() -> Program {
let mut program = Program {
classes: vec![
ClassBuilder::new("demo/mixin/TargetMixin", Some("java/lang/Object"))
.version(Version::JAVA_21)
.build(),
ClassBuilder::new("demo/mixin/other/Helper", Some("java/lang/Object"))
.version(Version::JAVA_21)
.build(),
ClassBuilder::new("demo/mixin/ClientMixin", Some("java/lang/Object"))
.version(Version::JAVA_21)
.build(),
ClassBuilder::new("demo/mixin/Plugin", Some("java/lang/Object"))
.version(Version::JAVA_21)
.build(),
ClassBuilder::new("demo/App", Some("java/lang/Object"))
.version(Version::JAVA_21)
.build(),
],
resources: Vec::new(),
};
program.resources.push(Resource {
path: "demo.mixins.json".into(),
data: MIXINS.as_bytes().to_vec(),
});
program.resources.push(Resource {
path: "fabric.mod.json".into(),
data: FABRIC.as_bytes().to_vec(),
});
program
}
#[test]
fn mixin_classes_and_plugin_stay() {
let program = sample();
let analysis = Analysis::run(&program, &Config::default()).expect("analysis");
for kept in [
"demo/mixin/TargetMixin",
"demo/mixin/other/Helper",
"demo/mixin/ClientMixin",
"demo/mixin/Plugin",
] {
assert!(analysis.is_locked(kept), "{kept} must survive renaming");
}
assert!(
!analysis.is_locked("demo/App"),
"ordinary classes must still rename"
);
}