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}