Skip to main content

rust_asm/
builder.rs

1use std::collections::HashMap;
2
3use crate::class_reader::{AttributeInfo, CodeAttribute, CpInfo, ExceptionTableEntry};
4use crate::insn::{
5    FieldInsnNode, Insn, InsnList, InsnNode, LdcInsnNode, LdcValue, MemberRef, MethodInsnNode,
6    VarInsnNode,
7};
8use crate::nodes::{ClassNode, FieldNode, MethodNode};
9use crate::opcodes;
10
11#[derive(Debug, Default)]
12pub struct ConstantPoolBuilder {
13    cp: Vec<CpInfo>,
14    utf8: HashMap<String, u16>,
15    class: HashMap<String, u16>,
16    string: HashMap<String, u16>,
17    name_and_type: HashMap<(String, String), u16>,
18    field_ref: HashMap<(String, String, String), u16>,
19    method_ref: HashMap<(String, String, String), u16>,
20}
21
22impl ConstantPoolBuilder {
23    pub fn new() -> Self {
24        Self {
25            cp: vec![CpInfo::Unusable],
26            ..Default::default()
27        }
28    }
29
30    pub fn into_pool(self) -> Vec<CpInfo> {
31        self.cp
32    }
33
34    pub fn utf8(&mut self, value: &str) -> u16 {
35        if let Some(index) = self.utf8.get(value) {
36            return *index;
37        }
38        let index = self.push(CpInfo::Utf8(value.to_string()));
39        self.utf8.insert(value.to_string(), index);
40        index
41    }
42
43    pub fn class(&mut self, name: &str) -> u16 {
44        if let Some(index) = self.class.get(name) {
45            return *index;
46        }
47        let name_index = self.utf8(name);
48        let index = self.push(CpInfo::Class { name_index });
49        self.class.insert(name.to_string(), index);
50        index
51    }
52
53    pub fn string(&mut self, value: &str) -> u16 {
54        if let Some(index) = self.string.get(value) {
55            return *index;
56        }
57        let string_index = self.utf8(value);
58        let index = self.push(CpInfo::String { string_index });
59        self.string.insert(value.to_string(), index);
60        index
61    }
62
63    pub fn name_and_type(&mut self, name: &str, descriptor: &str) -> u16 {
64        let key = (name.to_string(), descriptor.to_string());
65        if let Some(index) = self.name_and_type.get(&key) {
66            return *index;
67        }
68        let name_index = self.utf8(name);
69        let descriptor_index = self.utf8(descriptor);
70        let index = self.push(CpInfo::NameAndType {
71            name_index,
72            descriptor_index,
73        });
74        self.name_and_type.insert(key, index);
75        index
76    }
77
78    pub fn field_ref(&mut self, owner: &str, name: &str, descriptor: &str) -> u16 {
79        let key = (owner.to_string(), name.to_string(), descriptor.to_string());
80        if let Some(index) = self.field_ref.get(&key) {
81            return *index;
82        }
83        let class_index = self.class(owner);
84        let name_and_type_index = self.name_and_type(name, descriptor);
85        let index = self.push(CpInfo::Fieldref {
86            class_index,
87            name_and_type_index,
88        });
89        self.field_ref.insert(key, index);
90        index
91    }
92
93    pub fn method_ref(&mut self, owner: &str, name: &str, descriptor: &str) -> u16 {
94        let key = (owner.to_string(), name.to_string(), descriptor.to_string());
95        if let Some(index) = self.method_ref.get(&key) {
96            return *index;
97        }
98        let class_index = self.class(owner);
99        let name_and_type_index = self.name_and_type(name, descriptor);
100        let index = self.push(CpInfo::Methodref {
101            class_index,
102            name_and_type_index,
103        });
104        self.method_ref.insert(key, index);
105        index
106    }
107
108    fn push(&mut self, entry: CpInfo) -> u16 {
109        self.cp.push(entry);
110        (self.cp.len() - 1) as u16
111    }
112}
113
114pub struct ClassBuilder {
115    minor_version: u16,
116    major_version: u16,
117    access_flags: u16,
118    name: String,
119    super_name: Option<String>,
120    interfaces: Vec<String>,
121    fields: Vec<FieldBuilder>,
122    methods: Vec<MethodBuilder>,
123    attributes: Vec<AttributeInfo>,
124    source_file: Option<String>,
125    cp: ConstantPoolBuilder,
126}
127
128impl ClassBuilder {
129    pub fn new(name: &str, super_name: &str) -> Self {
130        Self {
131            minor_version: 0,
132            major_version: 52,
133            access_flags: 0,
134            name: name.to_string(),
135            super_name: Some(super_name.to_string()),
136            interfaces: Vec::new(),
137            fields: Vec::new(),
138            methods: Vec::new(),
139            attributes: Vec::new(),
140            source_file: None,
141            cp: ConstantPoolBuilder::new(),
142        }
143    }
144
145    pub fn version(&mut self, major: u16, minor: u16) -> &mut Self {
146        self.major_version = major;
147        self.minor_version = minor;
148        self
149    }
150
151    pub fn access_flags(&mut self, flags: u16) -> &mut Self {
152        self.access_flags = flags;
153        self
154    }
155
156    pub fn add_interface(&mut self, name: &str) -> &mut Self {
157        self.interfaces.push(name.to_string());
158        self
159    }
160
161    pub fn add_field(&mut self, field: FieldBuilder) -> &mut Self {
162        self.fields.push(field);
163        self
164    }
165
166    pub fn add_method(&mut self, method: MethodBuilder) -> &mut Self {
167        self.methods.push(method);
168        self
169    }
170
171    pub fn add_attribute(&mut self, attr: AttributeInfo) -> &mut Self {
172        self.attributes.push(attr);
173        self
174    }
175
176    pub fn source_file(&mut self, name: &str) -> &mut Self {
177        self.source_file = Some(name.to_string());
178        self
179    }
180
181    pub fn build(mut self) -> ClassNode {
182        let this_class = self.cp.class(&self.name);
183        let super_class = match self.super_name.as_deref() {
184            Some(name) => self.cp.class(name),
185            None => 0,
186        };
187
188        let mut interface_indices = Vec::with_capacity(self.interfaces.len());
189        for name in &self.interfaces {
190            interface_indices.push(self.cp.class(name));
191        }
192
193        let mut fields = Vec::with_capacity(self.fields.len());
194        for field in self.fields {
195            let name_index = self.cp.utf8(&field.name);
196            let descriptor_index = self.cp.utf8(&field.descriptor);
197            fields.push(FieldNode {
198                access_flags: field.access_flags,
199                name_index,
200                descriptor_index,
201                name: field.name,
202                descriptor: field.descriptor,
203                attributes: field.attributes,
204            });
205        }
206
207        let mut methods = Vec::with_capacity(self.methods.len());
208        for method in self.methods {
209            let name_index = self.cp.utf8(&method.name);
210            let descriptor_index = self.cp.utf8(&method.descriptor);
211            let code = method.code.map(|code| code.build(&mut self.cp));
212            methods.push(MethodNode {
213                access_flags: method.access_flags,
214                name_index,
215                descriptor_index,
216                name: method.name,
217                descriptor: method.descriptor,
218                code,
219                attributes: method.attributes,
220            });
221        }
222
223        if let Some(source_name) = self.source_file.as_ref() {
224            let source_index = self.cp.utf8(source_name);
225            self.attributes
226                .push(AttributeInfo::SourceFile { sourcefile_index: source_index });
227        }
228
229        ClassNode {
230            minor_version: self.minor_version,
231            major_version: self.major_version,
232            access_flags: self.access_flags,
233            constant_pool: self.cp.into_pool(),
234            this_class,
235            super_class,
236            name: self.name,
237            super_name: self.super_name,
238            source_file: self.source_file.clone(),
239            interfaces: self.interfaces,
240            interface_indices,
241            fields,
242            methods,
243            attributes: self.attributes,
244        }
245    }
246}
247
248pub struct FieldBuilder {
249    access_flags: u16,
250    name: String,
251    descriptor: String,
252    attributes: Vec<AttributeInfo>,
253}
254
255impl FieldBuilder {
256    pub fn new(access_flags: u16, name: &str, descriptor: &str) -> Self {
257        Self {
258            access_flags,
259            name: name.to_string(),
260            descriptor: descriptor.to_string(),
261            attributes: Vec::new(),
262        }
263    }
264
265    pub fn add_attribute(&mut self, attr: AttributeInfo) -> &mut Self {
266        self.attributes.push(attr);
267        self
268    }
269}
270
271pub struct MethodBuilder {
272    access_flags: u16,
273    name: String,
274    descriptor: String,
275    code: Option<CodeBody>,
276    attributes: Vec<AttributeInfo>,
277}
278
279impl MethodBuilder {
280    pub fn new(access_flags: u16, name: &str, descriptor: &str) -> Self {
281        Self {
282            access_flags,
283            name: name.to_string(),
284            descriptor: descriptor.to_string(),
285            code: None,
286            attributes: Vec::new(),
287        }
288    }
289
290    pub fn code(&mut self, max_stack: u16, max_locals: u16) -> &mut InsnList {
291        if self.code.is_none() {
292            self.code = Some(CodeBody::new(max_stack, max_locals, InsnList::new()));
293        }
294        let code = self.code.as_mut().expect("code should be initialized");
295        code.max_stack = max_stack;
296        code.max_locals = max_locals;
297        &mut code.insns
298    }
299
300    pub fn set_code(&mut self, max_stack: u16, max_locals: u16, insns: InsnList) -> &mut Self {
301        self.code = Some(CodeBody::new(max_stack, max_locals, insns));
302        self
303    }
304
305    pub fn add_attribute(&mut self, attr: AttributeInfo) -> &mut Self {
306        self.attributes.push(attr);
307        self
308    }
309
310    pub fn add_code_exception(&mut self, entry: ExceptionTableEntry) -> &mut Self {
311        if let Some(code) = &mut self.code {
312            code.exception_table.push(entry);
313        }
314        self
315    }
316
317    pub fn add_code_attribute(&mut self, attr: AttributeInfo) -> &mut Self {
318        if let Some(code) = &mut self.code {
319            code.attributes.push(attr);
320        }
321        self
322    }
323}
324
325struct CodeBody {
326    max_stack: u16,
327    max_locals: u16,
328    insns: InsnList,
329    exception_table: Vec<ExceptionTableEntry>,
330    attributes: Vec<AttributeInfo>,
331}
332
333impl CodeBody {
334    fn new(max_stack: u16, max_locals: u16, insns: InsnList) -> Self {
335        Self {
336            max_stack,
337            max_locals,
338            insns,
339            exception_table: Vec::new(),
340            attributes: Vec::new(),
341        }
342    }
343
344    fn build(self, cp: &mut ConstantPoolBuilder) -> CodeAttribute {
345        let mut code = Vec::new();
346        let mut instructions = Vec::new();
347        for insn in self.insns.into_insns() {
348            let resolved = emit_insn(&mut code, insn, cp);
349            instructions.push(resolved);
350        }
351        CodeAttribute {
352            max_stack: self.max_stack,
353            max_locals: self.max_locals,
354            code,
355            instructions,
356            insn_nodes: Vec::new(),
357            exception_table: self.exception_table,
358            try_catch_blocks: Vec::new(),
359            attributes: self.attributes,
360        }
361    }
362}
363
364fn build_code_attribute(
365    max_stack: u16,
366    max_locals: u16,
367    insns: InsnList,
368    cp: &mut ConstantPoolBuilder,
369    exception_table: Vec<ExceptionTableEntry>,
370    attributes: Vec<AttributeInfo>,
371) -> CodeAttribute {
372    CodeBody {
373        max_stack,
374        max_locals,
375        insns,
376        exception_table,
377        attributes,
378    }
379    .build(cp)
380}
381
382fn emit_insn(code: &mut Vec<u8>, insn: Insn, cp: &mut ConstantPoolBuilder) -> Insn {
383    let offset = code.len();
384    match insn {
385        Insn::Simple(node) => {
386            code.push(node.opcode);
387            Insn::Simple(node)
388        }
389        Insn::Int(node) => {
390            code.push(node.insn.opcode);
391            match node.insn.opcode {
392                opcodes::BIPUSH => write_i1(code, node.operand as i8),
393                opcodes::SIPUSH => write_i2(code, node.operand as i16),
394                opcodes::NEWARRAY => write_u1(code, node.operand as u8),
395                _ => write_i1(code, node.operand as i8),
396            }
397            Insn::Int(node)
398        }
399        Insn::Var(node) => {
400            code.push(node.insn.opcode);
401            write_u1(code, node.var_index as u8);
402            Insn::Var(node)
403        }
404        Insn::Type(node) => {
405            code.push(node.insn.opcode);
406            write_u2(code, node.type_index);
407            Insn::Type(node)
408        }
409        Insn::Field(node) => {
410            code.push(node.insn.opcode);
411            let (index, resolved) = resolve_field_ref(node, cp);
412            write_u2(code, index);
413            Insn::Field(resolved)
414        }
415        Insn::Method(node) => {
416            code.push(node.insn.opcode);
417            let (index, resolved) = resolve_method_ref(node, cp);
418            write_u2(code, index);
419            Insn::Method(resolved)
420        }
421        Insn::InvokeInterface(node) => {
422            code.push(node.insn.opcode);
423            write_u2(code, node.method_index);
424            write_u1(code, node.count);
425            write_u1(code, 0);
426            Insn::InvokeInterface(node)
427        }
428        Insn::InvokeDynamic(node) => {
429            code.push(node.insn.opcode);
430            write_u2(code, node.method_index);
431            write_u2(code, 0);
432            Insn::InvokeDynamic(node)
433        }
434        Insn::Jump(node) => {
435            code.push(node.insn.opcode);
436            match node.insn.opcode {
437                opcodes::GOTO_W | opcodes::JSR_W => write_i4(code, node.offset),
438                _ => write_i2(code, node.offset as i16),
439            }
440            Insn::Jump(node)
441        }
442        Insn::Ldc(node) => {
443            let (opcode, index, resolved) = resolve_ldc(node, cp);
444            code.push(opcode);
445            if opcode == opcodes::LDC {
446                write_u1(code, index as u8);
447            } else {
448                write_u2(code, index);
449            }
450            Insn::Ldc(resolved)
451        }
452        Insn::Iinc(node) => {
453            code.push(node.insn.opcode);
454            write_u1(code, node.var_index as u8);
455            write_i1(code, node.increment as i8);
456            Insn::Iinc(node)
457        }
458        Insn::TableSwitch(node) => {
459            code.push(node.insn.opcode);
460            write_switch_padding(code, offset);
461            write_i4(code, node.default_offset);
462            write_i4(code, node.low);
463            write_i4(code, node.high);
464            for value in &node.offsets {
465                write_i4(code, *value);
466            }
467            Insn::TableSwitch(node)
468        }
469        Insn::LookupSwitch(node) => {
470            code.push(node.insn.opcode);
471            write_switch_padding(code, offset);
472            write_i4(code, node.default_offset);
473            write_i4(code, node.pairs.len() as i32);
474            for (key, value) in &node.pairs {
475                write_i4(code, *key);
476                write_i4(code, *value);
477            }
478            Insn::LookupSwitch(node)
479        }
480        Insn::MultiANewArray(node) => {
481            code.push(node.insn.opcode);
482            write_u2(code, node.type_index);
483            write_u1(code, node.dimensions);
484            Insn::MultiANewArray(node)
485        }
486    }
487}
488
489fn write_u2(out: &mut Vec<u8>, value: u16) {
490    out.extend_from_slice(&value.to_be_bytes());
491}
492
493fn write_u1(out: &mut Vec<u8>, value: u8) {
494    out.push(value);
495}
496
497fn write_i1(out: &mut Vec<u8>, value: i8) {
498    out.push(value as u8);
499}
500
501fn write_i2(out: &mut Vec<u8>, value: i16) {
502    out.extend_from_slice(&value.to_be_bytes());
503}
504
505fn write_i4(out: &mut Vec<u8>, value: i32) {
506    out.extend_from_slice(&value.to_be_bytes());
507}
508
509fn write_switch_padding(out: &mut Vec<u8>, opcode_offset: usize) {
510    let mut padding = (4 - ((opcode_offset + 1) % 4)) % 4;
511    while padding > 0 {
512        out.push(0);
513        padding -= 1;
514    }
515}
516
517fn resolve_field_ref(node: FieldInsnNode, cp: &mut ConstantPoolBuilder) -> (u16, FieldInsnNode) {
518    match node.field_ref {
519        MemberRef::Index(index) => (index, node),
520        MemberRef::Symbolic {
521            owner,
522            name,
523            descriptor,
524        } => {
525            let index = cp.field_ref(&owner, &name, &descriptor);
526            (
527                index,
528                FieldInsnNode {
529                    insn: node.insn,
530                    field_ref: MemberRef::Index(index),
531                },
532            )
533        }
534    }
535}
536
537fn resolve_method_ref(
538    node: MethodInsnNode,
539    cp: &mut ConstantPoolBuilder,
540) -> (u16, MethodInsnNode) {
541    match node.method_ref {
542        MemberRef::Index(index) => (index, node),
543        MemberRef::Symbolic {
544            owner,
545            name,
546            descriptor,
547        } => {
548            let index = cp.method_ref(&owner, &name, &descriptor);
549            (
550                index,
551                MethodInsnNode {
552                    insn: node.insn,
553                    method_ref: MemberRef::Index(index),
554                },
555            )
556        }
557    }
558}
559
560fn resolve_ldc(node: LdcInsnNode, cp: &mut ConstantPoolBuilder) -> (u8, u16, LdcInsnNode) {
561    match node.value {
562        LdcValue::Index(index) => {
563            let opcode = if index <= 0xFF {
564                opcodes::LDC
565            } else {
566                opcodes::LDC_W
567            };
568            (
569                opcode,
570                index,
571                LdcInsnNode {
572                    insn: InsnNode { opcode },
573                    value: LdcValue::Index(index),
574                },
575            )
576        }
577        LdcValue::String(value) => {
578            let index = cp.string(&value);
579            let opcode = if index <= 0xFF {
580                opcodes::LDC
581            } else {
582                opcodes::LDC_W
583            };
584            (
585                opcode,
586                index,
587                LdcInsnNode {
588                    insn: InsnNode { opcode },
589                    value: LdcValue::Index(index),
590                },
591            )
592        }
593    }
594}
595
596struct FieldData {
597    access_flags: u16,
598    name: String,
599    descriptor: String,
600    attributes: Vec<AttributeInfo>,
601}
602
603struct MethodData {
604    access_flags: u16,
605    name: String,
606    descriptor: String,
607    code: Option<CodeAttribute>,
608    attributes: Vec<AttributeInfo>,
609}
610
611pub struct ClassWriter {
612    options: u32,
613    minor_version: u16,
614    major_version: u16,
615    access_flags: u16,
616    name: String,
617    super_name: Option<String>,
618    interfaces: Vec<String>,
619    fields: Vec<FieldData>,
620    methods: Vec<MethodData>,
621    attributes: Vec<AttributeInfo>,
622    source_file: Option<String>,
623    cp: ConstantPoolBuilder,
624}
625
626impl ClassWriter {
627    pub fn new(options: u32) -> Self {
628        Self {
629            options,
630            minor_version: 0,
631            major_version: 52,
632            access_flags: 0,
633            name: String::new(),
634            super_name: None,
635            interfaces: Vec::new(),
636            fields: Vec::new(),
637            methods: Vec::new(),
638            attributes: Vec::new(),
639            source_file: None,
640            cp: ConstantPoolBuilder::new(),
641        }
642    }
643
644    pub fn visit(
645        &mut self,
646        major: u16,
647        minor: u16,
648        access_flags: u16,
649        name: &str,
650        super_name: Option<&str>,
651        interfaces: &[&str],
652    ) -> &mut Self {
653        self.major_version = major;
654        self.minor_version = minor;
655        self.access_flags = access_flags;
656        self.name = name.to_string();
657        self.super_name = super_name.map(|value| value.to_string());
658        self.interfaces = interfaces.iter().map(|value| (*value).to_string()).collect();
659        self
660    }
661
662    pub fn visit_source_file(&mut self, name: &str) -> &mut Self {
663        self.source_file = Some(name.to_string());
664        self
665    }
666
667    pub fn visit_method(
668        &mut self,
669        access_flags: u16,
670        name: &str,
671        descriptor: &str,
672    ) -> MethodVisitor {
673        MethodVisitor::new(access_flags, name, descriptor)
674    }
675
676    pub fn visit_field(
677        &mut self,
678        access_flags: u16,
679        name: &str,
680        descriptor: &str,
681    ) -> FieldVisitor {
682        FieldVisitor::new(access_flags, name, descriptor)
683    }
684
685    pub fn add_attribute(&mut self, attr: AttributeInfo) -> &mut Self {
686        self.attributes.push(attr);
687        self
688    }
689
690    pub fn visit_end(&mut self) {}
691
692    pub fn to_class_node(mut self) -> Result<ClassNode, String> {
693        if self.name.is_empty() {
694            return Err("missing class name, call visit() first".to_string());
695        }
696
697        let this_class = self.cp.class(&self.name);
698        let super_class = match self.super_name.as_deref() {
699            Some(name) => self.cp.class(name),
700            None => 0,
701        };
702
703        let mut interface_indices = Vec::with_capacity(self.interfaces.len());
704        for name in &self.interfaces {
705            interface_indices.push(self.cp.class(name));
706        }
707
708        let mut fields = Vec::with_capacity(self.fields.len());
709        for field in self.fields {
710            let name_index = self.cp.utf8(&field.name);
711            let descriptor_index = self.cp.utf8(&field.descriptor);
712            fields.push(FieldNode {
713                access_flags: field.access_flags,
714                name_index,
715                descriptor_index,
716                name: field.name,
717                descriptor: field.descriptor,
718                attributes: field.attributes,
719            });
720        }
721
722        let mut methods = Vec::with_capacity(self.methods.len());
723        for method in self.methods {
724            let name_index = self.cp.utf8(&method.name);
725            let descriptor_index = self.cp.utf8(&method.descriptor);
726            methods.push(MethodNode {
727                access_flags: method.access_flags,
728                name_index,
729                descriptor_index,
730                name: method.name,
731                descriptor: method.descriptor,
732                code: method.code,
733                attributes: method.attributes,
734            });
735        }
736
737        if let Some(source_name) = self.source_file.as_ref() {
738            let source_index = self.cp.utf8(source_name);
739            self.attributes
740                .push(AttributeInfo::SourceFile { sourcefile_index: source_index });
741        }
742
743        Ok(ClassNode {
744            minor_version: self.minor_version,
745            major_version: self.major_version,
746            access_flags: self.access_flags,
747            constant_pool: self.cp.into_pool(),
748            this_class,
749            super_class,
750            name: self.name,
751            super_name: self.super_name,
752            source_file: self.source_file.clone(),
753            interfaces: self.interfaces,
754            interface_indices,
755            fields,
756            methods,
757            attributes: self.attributes,
758        })
759    }
760
761    pub fn to_bytes(self) -> Result<Vec<u8>, crate::class_writer::ClassWriteError> {
762        let options = self.options;
763        let class_node = self
764            .to_class_node()
765            .map_err(crate::class_writer::ClassWriteError::FrameComputation)?;
766        let writer = crate::class_writer::ClassWriter::new(options);
767        writer.to_bytes(&class_node)
768    }
769}
770
771pub struct MethodVisitor {
772    access_flags: u16,
773    name: String,
774    descriptor: String,
775    has_code: bool,
776    max_stack: u16,
777    max_locals: u16,
778    insns: InsnList,
779    exception_table: Vec<ExceptionTableEntry>,
780    code_attributes: Vec<AttributeInfo>,
781    attributes: Vec<AttributeInfo>,
782}
783
784impl MethodVisitor {
785    fn new(access_flags: u16, name: &str, descriptor: &str) -> Self {
786        Self {
787            access_flags,
788            name: name.to_string(),
789            descriptor: descriptor.to_string(),
790            has_code: false,
791            max_stack: 0,
792            max_locals: 0,
793            insns: InsnList::new(),
794            exception_table: Vec::new(),
795            code_attributes: Vec::new(),
796            attributes: Vec::new(),
797        }
798    }
799
800    pub fn visit_code(&mut self) -> &mut Self {
801        self.has_code = true;
802        self
803    }
804
805    pub fn visit_insn(&mut self, opcode: u8) -> &mut Self {
806        self.insns.add(InsnNode { opcode });
807        self
808    }
809
810    pub fn visit_var_insn(&mut self, opcode: u8, var_index: u16) -> &mut Self {
811        self.insns.add(VarInsnNode {
812            insn: InsnNode { opcode },
813            var_index,
814        });
815        self
816    }
817
818    pub fn visit_field_insn(
819        &mut self,
820        opcode: u8,
821        owner: &str,
822        name: &str,
823        descriptor: &str,
824    ) -> &mut Self {
825        self.insns.add(FieldInsnNode::new(opcode, owner, name, descriptor));
826        self
827    }
828
829    pub fn visit_method_insn(
830        &mut self,
831        opcode: u8,
832        owner: &str,
833        name: &str,
834        descriptor: &str,
835        _is_interface: bool,
836    ) -> &mut Self {
837        self.insns.add(MethodInsnNode::new(opcode, owner, name, descriptor));
838        self
839    }
840
841    pub fn visit_ldc_insn(&mut self, value: &str) -> &mut Self {
842        self.insns.add(LdcInsnNode::string(value));
843        self
844    }
845
846    pub fn visit_maxs(&mut self, max_stack: u16, max_locals: u16) -> &mut Self {
847        self.max_stack = max_stack;
848        self.max_locals = max_locals;
849        self
850    }
851
852    pub fn visit_end(mut self, class: &mut ClassWriter) {
853        let code = if self.has_code || !self.insns.insns().is_empty() {
854            Some(build_code_attribute(
855                self.max_stack,
856                self.max_locals,
857                self.insns,
858                &mut class.cp,
859                std::mem::take(&mut self.exception_table),
860                std::mem::take(&mut self.code_attributes),
861            ))
862        } else {
863            None
864        };
865        class.methods.push(MethodData {
866            access_flags: self.access_flags,
867            name: self.name,
868            descriptor: self.descriptor,
869            code,
870            attributes: std::mem::take(&mut self.attributes),
871        });
872    }
873}
874
875pub struct FieldVisitor {
876    access_flags: u16,
877    name: String,
878    descriptor: String,
879    attributes: Vec<AttributeInfo>,
880}
881
882impl FieldVisitor {
883    fn new(access_flags: u16, name: &str, descriptor: &str) -> Self {
884        Self {
885            access_flags,
886            name: name.to_string(),
887            descriptor: descriptor.to_string(),
888            attributes: Vec::new(),
889        }
890    }
891
892    pub fn add_attribute(&mut self, attr: AttributeInfo) -> &mut Self {
893        self.attributes.push(attr);
894        self
895    }
896
897    pub fn visit_end(self, class: &mut ClassWriter) {
898        class.fields.push(FieldData {
899            access_flags: self.access_flags,
900            name: self.name,
901            descriptor: self.descriptor,
902            attributes: self.attributes,
903        });
904    }
905}