Skip to main content

rust_asm/
class_reader.rs

1use crate::constant_pool::CpInfo;
2use crate::error::ClassReadError;
3use crate::insn::{
4    AbstractInsnNode, FieldInsnNode, IincInsnNode, Insn, InsnList, InsnNode, IntInsnNode,
5    InvokeDynamicInsnNode, InvokeInterfaceInsnNode, JumpInsnNode, LabelNode, LdcInsnNode, LdcValue,
6    LineNumberInsnNode, LookupSwitchInsnNode, MemberRef, MethodInsnNode, MultiANewArrayInsnNode,
7    TableSwitchInsnNode, TryCatchBlockNode, TypeInsnNode, VarInsnNode,
8};
9use crate::types::Type;
10use crate::{constants, opcodes};
11
12/// Represents a constant value loadable by the `LDC` (Load Constant) instruction.
13///
14/// This enum wraps various types of constants that can be stored in the constant pool
15/// and pushed onto the operand stack.
16#[derive(Debug, Clone)]
17pub enum LdcConstant {
18    /// A 32-bit integer constant.
19    Integer(i32),
20    /// A 32-bit floating-point constant.
21    Float(f32),
22    /// A 64-bit integer constant.
23    Long(i64),
24    /// A 64-bit floating-point constant.
25    Double(f64),
26    /// A string literal constant.
27    String(String),
28    /// A class constant (e.g., `String.class`).
29    Class(String),
30    /// A method type constant (MethodDescriptor).
31    MethodType(String),
32    /// A method handle constant.
33    MethodHandle {
34        reference_kind: u8,
35        reference_index: u16,
36    },
37    /// A dynamic constant (computed via `invokedynamic` bootstrap methods).
38    Dynamic,
39}
40
41/// A visitor to visit a Java field.
42///
43/// The methods of this trait must be called in the following order:
44/// `visit_end`.
45pub trait FieldVisitor {
46    /// Visits the end of the field.
47    ///
48    /// This method, which is the last one to be called, is used to inform the
49    /// visitor that all the annotations and attributes of the field have been visited.
50    fn visit_end(&mut self) {}
51}
52
53pub trait MethodVisitor {
54    /// Starts the visit of the method's code.
55    fn visit_code(&mut self) {}
56
57    /// Visits a zero-operand instruction.
58    ///
59    /// # Arguments
60    /// * `opcode` - The opcode of the instruction to be visited.
61    fn visit_insn(&mut self, _opcode: u8) {}
62
63    /// Visits an instruction with a single int operand.
64    fn visit_int_insn(&mut self, _opcode: u8, _operand: i32) {}
65
66    /// Visits a local variable instruction.
67    fn visit_var_insn(&mut self, _opcode: u8, _var_index: u16) {}
68
69    /// Visits a type instruction.
70    ///
71    /// # Arguments
72    /// * `opcode` - The opcode of the instruction.
73    /// * `type_name` - The internal name of the object or array class.
74    fn visit_type_insn(&mut self, _opcode: u8, _type_name: &str) {}
75
76    /// Visits a field instruction.
77    ///
78    /// # Arguments
79    /// * `opcode` - The opcode of the instruction.
80    /// * `owner` - The internal name of the field's owner class.
81    /// * `name` - The field's name.
82    /// * `desc` - The field's descriptor.
83    fn visit_field_insn(&mut self, _opcode: u8, _owner: &str, _name: &str, _desc: &str) {}
84    fn visit_method_insn(
85        &mut self,
86        _opcode: u8,
87        _owner: &str,
88        _name: &str,
89        _desc: &str,
90        _is_interface: bool,
91    ) {
92    }
93    fn visit_invoke_dynamic_insn(&mut self, _name: &str, _desc: &str) {}
94    /// Visits a jump instruction.
95    ///
96    /// # Arguments
97    /// * `opcode` - The opcode of the instruction.
98    /// * `target_offset` - The offset of the target instruction relative to the current instruction.
99    fn visit_jump_insn(&mut self, _opcode: u8, _target_offset: i32) {}
100
101    /// Visits an `LDC` instruction.
102    fn visit_ldc_insn(&mut self, _value: LdcConstant) {}
103    fn visit_iinc_insn(&mut self, _var_index: u16, _increment: i16) {}
104    fn visit_table_switch(&mut self, _default: i32, _low: i32, _high: i32, _targets: &[i32]) {}
105    fn visit_lookup_switch(&mut self, _default: i32, _pairs: &[(i32, i32)]) {}
106    fn visit_multi_anewarray_insn(&mut self, _type_name: &str, _dims: u8) {}
107    fn visit_maxs(&mut self, _max_stack: u16, _max_locals: u16) {}
108    fn visit_end(&mut self) {}
109}
110
111/// A visitor to visit a JPMS module descriptor.
112pub trait ModuleVisitor {
113    fn visit_main_class(&mut self, _main_class: &str) {}
114    fn visit_package(&mut self, _package: &str) {}
115    fn visit_require(&mut self, _module: &str, _access_flags: u16, _version: Option<&str>) {}
116    fn visit_export(&mut self, _package: &str, _access_flags: u16, _modules: &[String]) {}
117    fn visit_open(&mut self, _package: &str, _access_flags: u16, _modules: &[String]) {}
118    fn visit_use(&mut self, _service: &str) {}
119    fn visit_provide(&mut self, _service: &str, _providers: &[String]) {}
120    fn visit_end(&mut self) {}
121}
122
123/// A visitor to visit a Java class.
124///
125/// The methods of this trait must be called in the following order:
126/// `visit` -> `visit_source` -> `visit_module` -> (`visit_field` | `visit_method`)* -> `visit_end`.
127pub trait ClassVisitor {
128    /// Visits the header of the class.
129    ///
130    /// # Arguments
131    /// * `major` - The major version number of the class file.
132    /// * `minor` - The minor version number of the class file.
133    /// * `access_flags` - The class's access flags (see `Opcodes`).
134    /// * `name` - The internal name of the class.
135    /// * `super_name` - The internal name of the super class (e.g., `java/lang/String`, `a/b/c`).
136    ///   Use `None` for `Object`.
137    /// * `interfaces` - The internal names of the class's interfaces.
138    fn visit(
139        &mut self,
140        _major: u16,
141        _minor: u16,
142        _access_flags: u16,
143        _name: &str,
144        _super_name: Option<&str>,
145        _interfaces: &[String],
146    ) {
147    }
148
149    /// Visits the source file name of the class.
150    fn visit_source(&mut self, _source: &str) {}
151
152    /// Visits the JPMS module descriptor of this class, if this is a `module-info.class`.
153    fn visit_module(
154        &mut self,
155        _name: &str,
156        _access_flags: u16,
157        _version: Option<&str>,
158    ) -> Option<Box<dyn ModuleVisitor>> {
159        None
160    }
161
162    /// Visits a field of the class.
163    ///
164    /// Returns an optional `FieldVisitor` to visit the field's content.
165    fn visit_field(
166        &mut self,
167        _access_flags: u16,
168        _name: &str,
169        _descriptor: &str,
170    ) -> Option<Box<dyn FieldVisitor>> {
171        None
172    }
173
174    /// Visits a method of the class.
175    ///
176    /// Returns an optional `MethodVisitor` to visit the method's code.
177    fn visit_method(
178        &mut self,
179        _access_flags: u16,
180        _name: &str,
181        _descriptor: &str,
182    ) -> Option<Box<dyn MethodVisitor>> {
183        None
184    }
185
186    /// Visits the end of the class.
187    fn visit_end(&mut self) {}
188}
189
190/// A parser to make a [`ClassVisitor`] visit a `ClassFile` structure.
191///
192/// This class parses a byte array conforming to the Java class file format and
193/// calls the appropriate methods of a given class visitor for each field, method,
194/// and bytecode instruction encountered.
195pub struct ClassReader {
196    bytes: Vec<u8>,
197}
198
199impl ClassReader {
200    /// Constructs a new `ClassReader` with the given class file bytes.
201    ///
202    /// # Arguments
203    ///
204    /// * `bytes` - A byte slice containing the JVM class file data.
205    pub fn new(bytes: &[u8]) -> Self {
206        Self {
207            bytes: bytes.to_vec(),
208        }
209    }
210
211    /// Makes the given visitor visit the Java class of this `ClassReader`.
212    ///
213    /// This method parses the class file data and drives the visitor events.
214    ///
215    /// # Arguments
216    ///
217    /// * `visitor` - The visitor that must visit this class.
218    /// * `_options` - Option flags (currently unused, reserve for future parsing options like skipping debug info).
219    ///
220    /// # Errors
221    ///
222    /// Returns a [`ClassReadError`] if the class file is malformed or contains unsupported versions.
223    pub fn accept(
224        &self,
225        visitor: &mut dyn ClassVisitor,
226        _options: u32,
227    ) -> Result<(), ClassReadError> {
228        let class_file = read_class_file(&self.bytes)?;
229        let name = class_file.class_name(class_file.this_class)?.to_string();
230        let super_name = if class_file.super_class == 0 {
231            None
232        } else {
233            Some(class_file.class_name(class_file.super_class)?.to_string())
234        };
235        let mut interfaces = Vec::with_capacity(class_file.interfaces.len());
236        for index in &class_file.interfaces {
237            interfaces.push(class_file.class_name(*index)?.to_string());
238        }
239
240        visitor.visit(
241            class_file.major_version,
242            class_file.minor_version,
243            class_file.access_flags,
244            &name,
245            super_name.as_deref(),
246            &interfaces,
247        );
248
249        for attr in &class_file.attributes {
250            if let AttributeInfo::SourceFile { sourcefile_index } = attr {
251                let source = class_file.cp_utf8(*sourcefile_index)?;
252                visitor.visit_source(source);
253            }
254        }
255
256        if let Some(module_attr) = class_file.attributes.iter().find_map(|attr| match attr {
257            AttributeInfo::Module(module) => Some(module),
258            _ => None,
259        }) {
260            let version = if module_attr.module_version_index == 0 {
261                None
262            } else {
263                Some(class_file.cp_utf8(module_attr.module_version_index)?)
264            };
265            if let Some(mut mv) = visitor.visit_module(
266                class_file.module_name(module_attr.module_name_index)?,
267                module_attr.module_flags,
268                version,
269            ) {
270                if let Some(main_class_index) =
271                    class_file.attributes.iter().find_map(|attr| match attr {
272                        AttributeInfo::ModuleMainClass { main_class_index } => {
273                            Some(*main_class_index)
274                        }
275                        _ => None,
276                    })
277                {
278                    mv.visit_main_class(class_file.class_name(main_class_index)?);
279                }
280                if let Some(package_index_table) =
281                    class_file.attributes.iter().find_map(|attr| match attr {
282                        AttributeInfo::ModulePackages {
283                            package_index_table,
284                        } => Some(package_index_table.as_slice()),
285                        _ => None,
286                    })
287                {
288                    for package_index in package_index_table {
289                        mv.visit_package(class_file.package_name(*package_index)?);
290                    }
291                }
292                for require in &module_attr.requires {
293                    let version = if require.requires_version_index == 0 {
294                        None
295                    } else {
296                        Some(class_file.cp_utf8(require.requires_version_index)?)
297                    };
298                    mv.visit_require(
299                        class_file.module_name(require.requires_index)?,
300                        require.requires_flags,
301                        version,
302                    );
303                }
304                for export in &module_attr.exports {
305                    let modules = export
306                        .exports_to_index
307                        .iter()
308                        .map(|index| class_file.module_name(*index).map(str::to_string))
309                        .collect::<Result<Vec<_>, _>>()?;
310                    mv.visit_export(
311                        class_file.package_name(export.exports_index)?,
312                        export.exports_flags,
313                        &modules,
314                    );
315                }
316                for open in &module_attr.opens {
317                    let modules = open
318                        .opens_to_index
319                        .iter()
320                        .map(|index| class_file.module_name(*index).map(str::to_string))
321                        .collect::<Result<Vec<_>, _>>()?;
322                    mv.visit_open(
323                        class_file.package_name(open.opens_index)?,
324                        open.opens_flags,
325                        &modules,
326                    );
327                }
328                for uses_index in &module_attr.uses_index {
329                    mv.visit_use(class_file.class_name(*uses_index)?);
330                }
331                for provide in &module_attr.provides {
332                    let providers = provide
333                        .provides_with_index
334                        .iter()
335                        .map(|index| class_file.class_name(*index).map(str::to_string))
336                        .collect::<Result<Vec<_>, _>>()?;
337                    mv.visit_provide(class_file.class_name(provide.provides_index)?, &providers);
338                }
339                mv.visit_end();
340            }
341        }
342
343        for field in &class_file.fields {
344            let field_name = class_file.cp_utf8(field.name_index)?;
345            let field_desc = class_file.cp_utf8(field.descriptor_index)?;
346            if let Some(mut fv) = visitor.visit_field(field.access_flags, field_name, field_desc) {
347                fv.visit_end();
348            }
349        }
350
351        for method in &class_file.methods {
352            let method_name = class_file.cp_utf8(method.name_index)?;
353            let method_desc = class_file.cp_utf8(method.descriptor_index)?;
354            if let Some(mut mv) =
355                visitor.visit_method(method.access_flags, method_name, method_desc)
356            {
357                let code = method.attributes.iter().find_map(|attr| match attr {
358                    AttributeInfo::Code(code) => Some(code),
359                    _ => None,
360                });
361                if let Some(code) = code {
362                    mv.visit_code();
363                    let instructions = parse_code_instructions_with_offsets(&code.code)?;
364                    for instruction in instructions {
365                        visit_instruction(
366                            &class_file.constant_pool,
367                            instruction.offset as i32,
368                            instruction.insn,
369                            &mut *mv,
370                        )?;
371                    }
372                    mv.visit_maxs(code.max_stack, code.max_locals);
373                }
374                mv.visit_end();
375            }
376        }
377
378        visitor.visit_end();
379        Ok(())
380    }
381
382    /// Converts the read class data directly into a `ClassNode`.
383    ///
384    /// This is a convenience method that parses the bytes and builds a
385    /// complete object model of the class.
386    pub fn to_class_node(&self) -> Result<crate::nodes::ClassNode, ClassReadError> {
387        let class_file = read_class_file(&self.bytes)?;
388        class_file.to_class_node()
389    }
390}
391
392#[derive(Debug, Clone)]
393pub struct ClassFile {
394    pub minor_version: u16,
395    pub major_version: u16,
396    pub constant_pool: Vec<CpInfo>,
397    pub access_flags: u16,
398    pub this_class: u16,
399    pub super_class: u16,
400    pub interfaces: Vec<u16>,
401    pub fields: Vec<FieldInfo>,
402    pub methods: Vec<MethodInfo>,
403    pub attributes: Vec<AttributeInfo>,
404}
405
406impl ClassFile {
407    pub fn cp_utf8(&self, index: u16) -> Result<&str, ClassReadError> {
408        match self
409            .constant_pool
410            .get(index as usize)
411            .ok_or(ClassReadError::InvalidIndex(index))?
412        {
413            CpInfo::Utf8(value) => Ok(value.as_str()),
414            _ => Err(ClassReadError::InvalidIndex(index)),
415        }
416    }
417
418    pub fn class_name(&self, index: u16) -> Result<&str, ClassReadError> {
419        match self
420            .constant_pool
421            .get(index as usize)
422            .ok_or(ClassReadError::InvalidIndex(index))?
423        {
424            CpInfo::Class { name_index } => self.cp_utf8(*name_index),
425            _ => Err(ClassReadError::InvalidIndex(index)),
426        }
427    }
428
429    pub fn module_name(&self, index: u16) -> Result<&str, ClassReadError> {
430        match self
431            .constant_pool
432            .get(index as usize)
433            .ok_or(ClassReadError::InvalidIndex(index))?
434        {
435            CpInfo::Module { name_index } => self.cp_utf8(*name_index),
436            _ => Err(ClassReadError::InvalidIndex(index)),
437        }
438    }
439
440    pub fn package_name(&self, index: u16) -> Result<&str, ClassReadError> {
441        match self
442            .constant_pool
443            .get(index as usize)
444            .ok_or(ClassReadError::InvalidIndex(index))?
445        {
446            CpInfo::Package { name_index } => self.cp_utf8(*name_index),
447            _ => Err(ClassReadError::InvalidIndex(index)),
448        }
449    }
450
451    pub fn to_class_node(&self) -> Result<crate::nodes::ClassNode, ClassReadError> {
452        let name = self.class_name(self.this_class)?.to_string();
453        let super_name = if self.super_class == 0 {
454            None
455        } else {
456            Some(self.class_name(self.super_class)?.to_string())
457        };
458        let source_file = self.attributes.iter().find_map(|attr| match attr {
459            AttributeInfo::SourceFile { sourcefile_index } => self
460                .cp_utf8(*sourcefile_index)
461                .ok()
462                .map(|value| value.to_string()),
463            _ => None,
464        });
465        let mut interfaces = Vec::with_capacity(self.interfaces.len());
466        for index in &self.interfaces {
467            interfaces.push(self.class_name(*index)?.to_string());
468        }
469
470        let mut fields = Vec::with_capacity(self.fields.len());
471        for field in &self.fields {
472            let name = self.cp_utf8(field.name_index)?.to_string();
473            let descriptor = self.cp_utf8(field.descriptor_index)?.to_string();
474            fields.push(crate::nodes::FieldNode {
475                access_flags: field.access_flags,
476                name,
477                descriptor,
478                attributes: field.attributes.clone(),
479            });
480        }
481
482        let mut methods = Vec::with_capacity(self.methods.len());
483        for method in &self.methods {
484            let name = self.cp_utf8(method.name_index)?.to_string();
485            let descriptor = self.cp_utf8(method.descriptor_index)?.to_string();
486            let mut method_attributes = method.attributes.clone();
487            method_attributes.retain(|attr| !matches!(attr, AttributeInfo::Code(_)));
488            let code = method.attributes.iter().find_map(|attr| match attr {
489                AttributeInfo::Code(code) => Some(code),
490                _ => None,
491            });
492
493            let (
494                has_code,
495                max_stack,
496                max_locals,
497                instructions,
498                instruction_offsets,
499                insn_nodes,
500                exception_table,
501                try_catch_blocks,
502                line_numbers,
503                local_variables,
504                code_attributes,
505            ) = if let Some(code) = code {
506                let mut list = InsnList::new();
507                let mut instruction_offsets = Vec::with_capacity(code.instructions.len());
508                for insn in &code.instructions {
509                    list.add(insn.clone());
510                }
511                for node in parse_code_instructions_with_offsets(&code.code)? {
512                    instruction_offsets.push(node.offset);
513                }
514                let line_numbers = code
515                    .attributes
516                    .iter()
517                    .find_map(|attr| match attr {
518                        AttributeInfo::LineNumberTable { entries } => Some(entries.clone()),
519                        _ => None,
520                    })
521                    .unwrap_or_default();
522                let local_variables = code
523                    .attributes
524                    .iter()
525                    .find_map(|attr| match attr {
526                        AttributeInfo::LocalVariableTable { entries } => Some(entries.clone()),
527                        _ => None,
528                    })
529                    .unwrap_or_default();
530                (
531                    true,
532                    code.max_stack,
533                    code.max_locals,
534                    list,
535                    instruction_offsets,
536                    code.insn_nodes.clone(),
537                    code.exception_table.clone(),
538                    code.try_catch_blocks.clone(),
539                    line_numbers,
540                    local_variables,
541                    code.attributes.clone(),
542                )
543            } else {
544                (
545                    false,
546                    0,
547                    0,
548                    InsnList::new(),
549                    Vec::new(),
550                    Vec::new(),
551                    Vec::new(),
552                    Vec::new(),
553                    Vec::new(),
554                    Vec::new(),
555                    Vec::new(),
556                )
557            };
558            let method_parameters = method
559                .attributes
560                .iter()
561                .find_map(|attr| match attr {
562                    AttributeInfo::MethodParameters { parameters } => Some(parameters.clone()),
563                    _ => None,
564                })
565                .unwrap_or_default();
566            let exceptions = method
567                .attributes
568                .iter()
569                .find_map(|attr| match attr {
570                    AttributeInfo::Exceptions {
571                        exception_index_table,
572                    } => Some(exception_index_table),
573                    _ => None,
574                })
575                .map(|entries| -> Result<Vec<String>, ClassReadError> {
576                    let mut values = Vec::with_capacity(entries.len());
577                    for index in entries {
578                        values.push(self.class_name(*index)?.to_string());
579                    }
580                    Ok(values)
581                })
582                .transpose()?
583                .unwrap_or_default();
584            let signature = method.attributes.iter().find_map(|attr| match attr {
585                AttributeInfo::Signature { signature_index } => self
586                    .cp_utf8(*signature_index)
587                    .ok()
588                    .map(|value| value.to_string()),
589                _ => None,
590            });
591
592            methods.push(crate::nodes::MethodNode {
593                access_flags: method.access_flags,
594                name,
595                descriptor,
596                has_code,
597                max_stack,
598                max_locals,
599                instructions,
600                instruction_offsets,
601                insn_nodes,
602                exception_table,
603                try_catch_blocks,
604                line_numbers,
605                local_variables,
606                method_parameters,
607                exceptions,
608                signature,
609                code_attributes,
610                attributes: method_attributes,
611            });
612        }
613
614        let mut inner_classes = Vec::new();
615        for attr in &self.attributes {
616            if let AttributeInfo::InnerClasses { classes } = attr {
617                for entry in classes {
618                    let name = self.class_name(entry.inner_class_info_index)?.to_string();
619                    let outer_name = if entry.outer_class_info_index == 0 {
620                        None
621                    } else {
622                        Some(self.class_name(entry.outer_class_info_index)?.to_string())
623                    };
624                    let inner_name = if entry.inner_name_index == 0 {
625                        None
626                    } else {
627                        Some(self.cp_utf8(entry.inner_name_index)?.to_string())
628                    };
629                    inner_classes.push(crate::nodes::InnerClassNode {
630                        name,
631                        outer_name,
632                        inner_name,
633                        access_flags: entry.inner_class_access_flags,
634                    });
635                }
636            }
637        }
638
639        let mut outer_class = String::new();
640        if let Some(class_index) = self.attributes.iter().find_map(|attr| match attr {
641            AttributeInfo::EnclosingMethod { class_index, .. } => Some(*class_index),
642            _ => None,
643        }) {
644            outer_class = self.class_name(class_index)?.to_string();
645        }
646        if outer_class.is_empty() {
647            for attr in &self.attributes {
648                if let AttributeInfo::InnerClasses { classes } = attr
649                    && let Some(entry) = classes.iter().find(|entry| {
650                        entry.inner_class_info_index == self.this_class
651                            && entry.outer_class_info_index != 0
652                    })
653                {
654                    outer_class = self.class_name(entry.outer_class_info_index)?.to_string();
655                    break;
656                }
657            }
658        }
659
660        let module = self
661            .attributes
662            .iter()
663            .find_map(|attr| match attr {
664                AttributeInfo::Module(module) => Some(module),
665                _ => None,
666            })
667            .map(|module| {
668                let requires = module
669                    .requires
670                    .iter()
671                    .map(|require| {
672                        Ok(crate::nodes::ModuleRequireNode {
673                            module: self.module_name(require.requires_index)?.to_string(),
674                            access_flags: require.requires_flags,
675                            version: if require.requires_version_index == 0 {
676                                None
677                            } else {
678                                Some(self.cp_utf8(require.requires_version_index)?.to_string())
679                            },
680                        })
681                    })
682                    .collect::<Result<Vec<_>, ClassReadError>>()?;
683                let exports = module
684                    .exports
685                    .iter()
686                    .map(|export| {
687                        Ok(crate::nodes::ModuleExportNode {
688                            package: self.package_name(export.exports_index)?.to_string(),
689                            access_flags: export.exports_flags,
690                            modules: export
691                                .exports_to_index
692                                .iter()
693                                .map(|index| self.module_name(*index).map(str::to_string))
694                                .collect::<Result<Vec<_>, ClassReadError>>()?,
695                        })
696                    })
697                    .collect::<Result<Vec<_>, ClassReadError>>()?;
698                let opens = module
699                    .opens
700                    .iter()
701                    .map(|open| {
702                        Ok(crate::nodes::ModuleOpenNode {
703                            package: self.package_name(open.opens_index)?.to_string(),
704                            access_flags: open.opens_flags,
705                            modules: open
706                                .opens_to_index
707                                .iter()
708                                .map(|index| self.module_name(*index).map(str::to_string))
709                                .collect::<Result<Vec<_>, ClassReadError>>()?,
710                        })
711                    })
712                    .collect::<Result<Vec<_>, ClassReadError>>()?;
713                let provides = module
714                    .provides
715                    .iter()
716                    .map(|provide| {
717                        Ok(crate::nodes::ModuleProvideNode {
718                            service: self.class_name(provide.provides_index)?.to_string(),
719                            providers: provide
720                                .provides_with_index
721                                .iter()
722                                .map(|index| self.class_name(*index).map(str::to_string))
723                                .collect::<Result<Vec<_>, ClassReadError>>()?,
724                        })
725                    })
726                    .collect::<Result<Vec<_>, ClassReadError>>()?;
727                let packages = self
728                    .attributes
729                    .iter()
730                    .find_map(|attr| match attr {
731                        AttributeInfo::ModulePackages {
732                            package_index_table,
733                        } => Some(package_index_table),
734                        _ => None,
735                    })
736                    .map(|package_index_table| {
737                        package_index_table
738                            .iter()
739                            .map(|index| self.package_name(*index).map(str::to_string))
740                            .collect::<Result<Vec<_>, ClassReadError>>()
741                    })
742                    .transpose()?
743                    .unwrap_or_default();
744                let main_class = self
745                    .attributes
746                    .iter()
747                    .find_map(|attr| match attr {
748                        AttributeInfo::ModuleMainClass { main_class_index } => {
749                            Some(*main_class_index)
750                        }
751                        _ => None,
752                    })
753                    .map(|index| self.class_name(index).map(str::to_string))
754                    .transpose()?;
755
756                Ok(crate::nodes::ModuleNode {
757                    name: self.module_name(module.module_name_index)?.to_string(),
758                    access_flags: module.module_flags,
759                    version: if module.module_version_index == 0 {
760                        None
761                    } else {
762                        Some(self.cp_utf8(module.module_version_index)?.to_string())
763                    },
764                    requires,
765                    exports,
766                    opens,
767                    uses: module
768                        .uses_index
769                        .iter()
770                        .map(|index| self.class_name(*index).map(str::to_string))
771                        .collect::<Result<Vec<_>, ClassReadError>>()?,
772                    provides,
773                    packages,
774                    main_class,
775                })
776            })
777            .transpose()?;
778
779        let permitted_subclasses = self
780            .attributes
781            .iter()
782            .find_map(|attr| match attr {
783                AttributeInfo::PermittedSubclasses { classes } => Some(classes),
784                _ => None,
785            })
786            .map(|classes| {
787                classes
788                    .iter()
789                    .map(|index| self.class_name(*index).map(str::to_string))
790                    .collect::<Result<Vec<_>, ClassReadError>>()
791            })
792            .transpose()?
793            .unwrap_or_default();
794
795        let record_components = self
796            .attributes
797            .iter()
798            .find_map(|attr| match attr {
799                AttributeInfo::Record { components } => Some(components),
800                _ => None,
801            })
802            .map(|components| {
803                components
804                    .iter()
805                    .map(|comp| {
806                        Ok(crate::nodes::RecordComponentNode {
807                            name: self.cp_utf8(comp.name_index)?.to_string(),
808                            descriptor: self.cp_utf8(comp.descriptor_index)?.to_string(),
809                            attributes: comp.attributes.clone(),
810                        })
811                    })
812                    .collect::<Result<Vec<_>, ClassReadError>>()
813            })
814            .transpose()?
815            .unwrap_or_default();
816
817        Ok(crate::nodes::ClassNode {
818            minor_version: self.minor_version,
819            major_version: self.major_version,
820            access_flags: self.access_flags,
821            constant_pool: self.constant_pool.clone(),
822            this_class: self.this_class,
823            name,
824            super_name,
825            source_file,
826            interfaces,
827            interface_indices: self.interfaces.clone(),
828            fields,
829            methods,
830            attributes: self.attributes.clone(),
831            inner_classes,
832            outer_class,
833            module,
834            record_components,
835            permitted_subclasses,
836        })
837    }
838}
839
840#[derive(Debug, Clone)]
841pub struct FieldInfo {
842    pub access_flags: u16,
843    pub name_index: u16,
844    pub descriptor_index: u16,
845    pub attributes: Vec<AttributeInfo>,
846}
847
848#[derive(Debug, Clone)]
849pub struct MethodInfo {
850    pub access_flags: u16,
851    pub name_index: u16,
852    pub descriptor_index: u16,
853    pub attributes: Vec<AttributeInfo>,
854}
855
856#[derive(Debug, Clone)]
857pub struct RecordComponent {
858    pub name_index: u16,
859    pub descriptor_index: u16,
860    pub attributes: Vec<AttributeInfo>,
861}
862
863#[derive(Debug, Clone)]
864pub enum AttributeInfo {
865    Code(CodeAttribute),
866    ConstantValue { constantvalue_index: u16 },
867    Exceptions { exception_index_table: Vec<u16> },
868    SourceFile { sourcefile_index: u16 },
869    LineNumberTable { entries: Vec<LineNumber> },
870    LocalVariableTable { entries: Vec<LocalVariable> },
871    Signature { signature_index: u16 },
872    StackMapTable { entries: Vec<StackMapFrame> },
873    Deprecated,
874    Synthetic,
875    InnerClasses { classes: Vec<InnerClass> },
876    EnclosingMethod { class_index: u16, method_index: u16 },
877    Module(ModuleAttribute),
878    ModulePackages { package_index_table: Vec<u16> },
879    ModuleMainClass { main_class_index: u16 },
880    BootstrapMethods { methods: Vec<BootstrapMethod> },
881    MethodParameters { parameters: Vec<MethodParameter> },
882    RuntimeVisibleAnnotations { annotations: Vec<Annotation> },
883    RuntimeInvisibleAnnotations { annotations: Vec<Annotation> },
884    RuntimeVisibleParameterAnnotations { parameters: ParameterAnnotations },
885    RuntimeInvisibleParameterAnnotations { parameters: ParameterAnnotations },
886    RuntimeVisibleTypeAnnotations { annotations: Vec<TypeAnnotation> },
887    RuntimeInvisibleTypeAnnotations { annotations: Vec<TypeAnnotation> },
888    PermittedSubclasses { classes: Vec<u16> },
889    Record { components: Vec<RecordComponent> },
890    Unknown { name: String, info: Vec<u8> },
891}
892
893#[derive(Debug, Clone, PartialEq, Eq)]
894pub struct ModuleAttribute {
895    pub module_name_index: u16,
896    pub module_flags: u16,
897    pub module_version_index: u16,
898    pub requires: Vec<ModuleRequire>,
899    pub exports: Vec<ModuleExport>,
900    pub opens: Vec<ModuleOpen>,
901    pub uses_index: Vec<u16>,
902    pub provides: Vec<ModuleProvide>,
903}
904
905#[derive(Debug, Clone, PartialEq, Eq)]
906pub struct ModuleRequire {
907    pub requires_index: u16,
908    pub requires_flags: u16,
909    pub requires_version_index: u16,
910}
911
912#[derive(Debug, Clone, PartialEq, Eq)]
913pub struct ModuleExport {
914    pub exports_index: u16,
915    pub exports_flags: u16,
916    pub exports_to_index: Vec<u16>,
917}
918
919#[derive(Debug, Clone, PartialEq, Eq)]
920pub struct ModuleOpen {
921    pub opens_index: u16,
922    pub opens_flags: u16,
923    pub opens_to_index: Vec<u16>,
924}
925
926#[derive(Debug, Clone, PartialEq, Eq)]
927pub struct ModuleProvide {
928    pub provides_index: u16,
929    pub provides_with_index: Vec<u16>,
930}
931
932#[derive(Debug, Clone, PartialEq)]
933pub struct Annotation {
934    pub type_descriptor_index: u16,
935    pub element_value_pairs: Vec<ElementValuePair>,
936}
937
938#[derive(Debug, Clone, PartialEq)]
939pub struct ElementValuePair {
940    pub element_name_index: u16,
941    pub value: ElementValue,
942}
943
944#[derive(Debug, Clone, PartialEq)]
945pub enum ElementValue {
946    ConstValueIndex {
947        tag: u8,
948        const_value_index: u16,
949    },
950    EnumConstValue {
951        type_name_index: u16,
952        const_name_index: u16,
953    },
954    ClassInfoIndex {
955        class_info_index: u16,
956    },
957    AnnotationValue(Box<Annotation>),
958    ArrayValue(Vec<ElementValue>),
959}
960
961#[derive(Debug, Clone, PartialEq)]
962pub struct ParameterAnnotations {
963    pub parameters: Vec<Vec<Annotation>>,
964}
965
966#[derive(Debug, Clone, PartialEq)]
967pub struct TypeAnnotation {
968    pub target_type: u8,
969    pub target_info: TypeAnnotationTargetInfo,
970    pub target_path: TypePath,
971    pub annotation: Annotation,
972}
973
974#[derive(Debug, Clone, PartialEq)]
975pub struct TypePath {
976    pub path: Vec<TypePathEntry>,
977}
978
979#[derive(Debug, Clone, PartialEq)]
980pub struct TypePathEntry {
981    pub type_path_kind: u8,
982    pub type_argument_index: u8,
983}
984
985#[derive(Debug, Clone, PartialEq)]
986pub enum TypeAnnotationTargetInfo {
987    TypeParameter {
988        type_parameter_index: u8,
989    },
990    Supertype {
991        supertype_index: u16,
992    },
993    TypeParameterBound {
994        type_parameter_index: u8,
995        bound_index: u8,
996    },
997    Empty,
998    FormalParameter {
999        formal_parameter_index: u8,
1000    },
1001    Throws {
1002        throws_type_index: u16,
1003    },
1004    LocalVar {
1005        table: Vec<LocalVarTargetTableEntry>,
1006    },
1007    Catch {
1008        exception_table_index: u16,
1009    },
1010    Offset {
1011        offset: u16,
1012    },
1013    TypeArgument {
1014        offset: u16,
1015        type_argument_index: u8,
1016    },
1017}
1018
1019#[derive(Debug, Clone, PartialEq)]
1020pub struct LocalVarTargetTableEntry {
1021    pub start_pc: u16,
1022    pub length: u16,
1023    pub index: u16,
1024}
1025
1026#[derive(Debug, Clone)]
1027pub struct CodeAttribute {
1028    pub max_stack: u16,
1029    pub max_locals: u16,
1030    pub code: Vec<u8>,
1031    pub instructions: Vec<Insn>,
1032    pub insn_nodes: Vec<AbstractInsnNode>,
1033    pub exception_table: Vec<ExceptionTableEntry>,
1034    pub try_catch_blocks: Vec<TryCatchBlockNode>,
1035    pub attributes: Vec<AttributeInfo>,
1036}
1037
1038#[derive(Debug, Clone)]
1039pub struct ExceptionTableEntry {
1040    pub start_pc: u16,
1041    pub end_pc: u16,
1042    pub handler_pc: u16,
1043    pub catch_type: u16,
1044}
1045
1046#[derive(Debug, Clone)]
1047pub struct LineNumber {
1048    pub start_pc: u16,
1049    pub line_number: u16,
1050}
1051
1052#[derive(Debug, Clone)]
1053pub struct LocalVariable {
1054    pub start_pc: u16,
1055    pub length: u16,
1056    pub name_index: u16,
1057    pub descriptor_index: u16,
1058    pub index: u16,
1059}
1060
1061#[derive(Debug, Clone)]
1062pub struct InnerClass {
1063    pub inner_class_info_index: u16,
1064    pub outer_class_info_index: u16,
1065    pub inner_name_index: u16,
1066    pub inner_class_access_flags: u16,
1067}
1068
1069#[derive(Debug, Clone)]
1070pub struct BootstrapMethod {
1071    pub bootstrap_method_ref: u16,
1072    pub bootstrap_arguments: Vec<u16>,
1073}
1074
1075#[derive(Debug, Clone)]
1076pub struct MethodParameter {
1077    pub name_index: u16,
1078    pub access_flags: u16,
1079}
1080
1081#[derive(Debug, Clone, PartialEq, Eq)]
1082pub enum VerificationTypeInfo {
1083    Top,
1084    Integer,
1085    Float,
1086    Long,
1087    Double,
1088    Null,
1089    UninitializedThis,
1090    Object { cpool_index: u16 },
1091    Uninitialized { offset: u16 },
1092}
1093
1094#[derive(Debug, Clone)]
1095pub enum StackMapFrame {
1096    SameFrame {
1097        offset_delta: u16,
1098    },
1099    SameLocals1StackItemFrame {
1100        offset_delta: u16,
1101        stack: VerificationTypeInfo,
1102    },
1103    SameLocals1StackItemFrameExtended {
1104        offset_delta: u16,
1105        stack: VerificationTypeInfo,
1106    },
1107    ChopFrame {
1108        offset_delta: u16,
1109        k: u8,
1110    },
1111    SameFrameExtended {
1112        offset_delta: u16,
1113    },
1114    AppendFrame {
1115        offset_delta: u16,
1116        locals: Vec<VerificationTypeInfo>,
1117    },
1118    FullFrame {
1119        offset_delta: u16,
1120        locals: Vec<VerificationTypeInfo>,
1121        stack: Vec<VerificationTypeInfo>,
1122    },
1123}
1124
1125pub fn read_class_file(bytes: &[u8]) -> Result<ClassFile, ClassReadError> {
1126    let mut reader = ByteReader::new(bytes);
1127    let magic = reader.read_u4()?;
1128    if magic != 0xCAFEBABE {
1129        return Err(ClassReadError::InvalidMagic(magic));
1130    }
1131    let minor_version = reader.read_u2()?;
1132    let major_version = reader.read_u2()?;
1133    if major_version > constants::V25 {
1134        return Err(ClassReadError::InvalidClassVersion(major_version));
1135    }
1136    let constant_pool = read_constant_pool(&mut reader)?;
1137    let access_flags = reader.read_u2()?;
1138    let this_class = reader.read_u2()?;
1139    let super_class = reader.read_u2()?;
1140    let interfaces = read_u2_table(&mut reader)?;
1141    let fields = read_fields(&mut reader, &constant_pool)?;
1142    let methods = read_methods(&mut reader, &constant_pool)?;
1143    let attributes = read_attributes(&mut reader, &constant_pool)?;
1144
1145    Ok(ClassFile {
1146        minor_version,
1147        major_version,
1148        constant_pool,
1149        access_flags,
1150        this_class,
1151        super_class,
1152        interfaces,
1153        fields,
1154        methods,
1155        attributes,
1156    })
1157}
1158
1159fn read_constant_pool(reader: &mut ByteReader<'_>) -> Result<Vec<CpInfo>, ClassReadError> {
1160    let count = reader.read_u2()? as usize;
1161    let mut pool = Vec::with_capacity(count);
1162    pool.push(CpInfo::Unusable);
1163
1164    let mut index = 1;
1165    while index < count {
1166        let tag = reader.read_u1()?;
1167        let entry = match tag {
1168            1 => {
1169                let len = reader.read_u2()? as usize;
1170                let bytes = reader.read_bytes(len)?;
1171                let value = decode_modified_utf8(&bytes)?;
1172                CpInfo::Utf8(value)
1173            }
1174            3 => {
1175                let value = reader.read_u4()? as i32;
1176                CpInfo::Integer(value)
1177            }
1178            4 => {
1179                let value = f32::from_bits(reader.read_u4()?);
1180                CpInfo::Float(value)
1181            }
1182            5 => {
1183                let value = reader.read_u8()? as i64;
1184                CpInfo::Long(value)
1185            }
1186            6 => {
1187                let value = f64::from_bits(reader.read_u8()?);
1188                CpInfo::Double(value)
1189            }
1190            7 => CpInfo::Class {
1191                name_index: reader.read_u2()?,
1192            },
1193            8 => CpInfo::String {
1194                string_index: reader.read_u2()?,
1195            },
1196            9 => CpInfo::Fieldref {
1197                class_index: reader.read_u2()?,
1198                name_and_type_index: reader.read_u2()?,
1199            },
1200            10 => CpInfo::Methodref {
1201                class_index: reader.read_u2()?,
1202                name_and_type_index: reader.read_u2()?,
1203            },
1204            11 => CpInfo::InterfaceMethodref {
1205                class_index: reader.read_u2()?,
1206                name_and_type_index: reader.read_u2()?,
1207            },
1208            12 => CpInfo::NameAndType {
1209                name_index: reader.read_u2()?,
1210                descriptor_index: reader.read_u2()?,
1211            },
1212            15 => CpInfo::MethodHandle {
1213                reference_kind: reader.read_u1()?,
1214                reference_index: reader.read_u2()?,
1215            },
1216            16 => CpInfo::MethodType {
1217                descriptor_index: reader.read_u2()?,
1218            },
1219            17 => CpInfo::Dynamic {
1220                bootstrap_method_attr_index: reader.read_u2()?,
1221                name_and_type_index: reader.read_u2()?,
1222            },
1223            18 => CpInfo::InvokeDynamic {
1224                bootstrap_method_attr_index: reader.read_u2()?,
1225                name_and_type_index: reader.read_u2()?,
1226            },
1227            19 => CpInfo::Module {
1228                name_index: reader.read_u2()?,
1229            },
1230            20 => CpInfo::Package {
1231                name_index: reader.read_u2()?,
1232            },
1233            _ => return Err(ClassReadError::InvalidConstantPoolTag(tag)),
1234        };
1235
1236        pool.push(entry);
1237
1238        if tag == 5 || tag == 6 {
1239            pool.push(CpInfo::Unusable);
1240            index += 2;
1241        } else {
1242            index += 1;
1243        }
1244    }
1245
1246    Ok(pool)
1247}
1248
1249fn read_u2_table(reader: &mut ByteReader<'_>) -> Result<Vec<u16>, ClassReadError> {
1250    let count = reader.read_u2()? as usize;
1251    let mut values = Vec::with_capacity(count);
1252    for _ in 0..count {
1253        values.push(reader.read_u2()?);
1254    }
1255    Ok(values)
1256}
1257
1258fn read_fields(
1259    reader: &mut ByteReader<'_>,
1260    cp: &[CpInfo],
1261) -> Result<Vec<FieldInfo>, ClassReadError> {
1262    let count = reader.read_u2()? as usize;
1263    let mut fields = Vec::with_capacity(count);
1264    for _ in 0..count {
1265        let access_flags = reader.read_u2()?;
1266        let name_index = reader.read_u2()?;
1267        let descriptor_index = reader.read_u2()?;
1268        let attributes = read_attributes(reader, cp)?;
1269        fields.push(FieldInfo {
1270            access_flags,
1271            name_index,
1272            descriptor_index,
1273            attributes,
1274        });
1275    }
1276    Ok(fields)
1277}
1278
1279fn read_methods(
1280    reader: &mut ByteReader<'_>,
1281    cp: &[CpInfo],
1282) -> Result<Vec<MethodInfo>, ClassReadError> {
1283    let count = reader.read_u2()? as usize;
1284    let mut methods = Vec::with_capacity(count);
1285    for _ in 0..count {
1286        let access_flags = reader.read_u2()?;
1287        let name_index = reader.read_u2()?;
1288        let descriptor_index = reader.read_u2()?;
1289        let attributes = read_attributes(reader, cp)?;
1290        methods.push(MethodInfo {
1291            access_flags,
1292            name_index,
1293            descriptor_index,
1294            attributes,
1295        });
1296    }
1297    Ok(methods)
1298}
1299
1300fn read_attributes(
1301    reader: &mut ByteReader<'_>,
1302    cp: &[CpInfo],
1303) -> Result<Vec<AttributeInfo>, ClassReadError> {
1304    let count = reader.read_u2()? as usize;
1305    let mut attributes = Vec::with_capacity(count);
1306    for _ in 0..count {
1307        let name_index = reader.read_u2()?;
1308        let length = reader.read_u4()? as usize;
1309        let name = cp_utf8(cp, name_index)?;
1310        let info = reader.read_bytes(length)?;
1311        let attribute = parse_attribute(name, info, cp)?;
1312        attributes.push(attribute);
1313    }
1314    Ok(attributes)
1315}
1316
1317fn parse_attribute(
1318    name: &str,
1319    info: Vec<u8>,
1320    cp: &[CpInfo],
1321) -> Result<AttributeInfo, ClassReadError> {
1322    let mut reader = ByteReader::new(&info);
1323    let attribute = match name {
1324        "Code" => {
1325            let max_stack = reader.read_u2()?;
1326            let max_locals = reader.read_u2()?;
1327            let code_length = reader.read_u4()? as usize;
1328            let code = reader.read_bytes(code_length)?;
1329            let instructions = parse_code_instructions(&code)?;
1330            let exception_table_length = reader.read_u2()? as usize;
1331            let mut exception_table = Vec::with_capacity(exception_table_length);
1332            for _ in 0..exception_table_length {
1333                exception_table.push(ExceptionTableEntry {
1334                    start_pc: reader.read_u2()?,
1335                    end_pc: reader.read_u2()?,
1336                    handler_pc: reader.read_u2()?,
1337                    catch_type: reader.read_u2()?,
1338                });
1339            }
1340            let attributes = read_attributes(&mut reader, cp)?;
1341            let (mut insn_nodes, try_catch_blocks, label_by_offset) =
1342                build_insn_nodes(&code, &exception_table, cp)?;
1343            let line_numbers = attributes.iter().find_map(|attr| match attr {
1344                AttributeInfo::LineNumberTable { entries } => Some(entries.as_slice()),
1345                _ => None,
1346            });
1347            if let Some(entries) = line_numbers {
1348                insn_nodes = attach_line_numbers(insn_nodes, entries, &label_by_offset);
1349            }
1350            AttributeInfo::Code(CodeAttribute {
1351                max_stack,
1352                max_locals,
1353                code,
1354                instructions,
1355                insn_nodes,
1356                exception_table,
1357                try_catch_blocks,
1358                attributes,
1359            })
1360        }
1361        "ConstantValue" => AttributeInfo::ConstantValue {
1362            constantvalue_index: reader.read_u2()?,
1363        },
1364        "Exceptions" => {
1365            let count = reader.read_u2()? as usize;
1366            let mut exception_index_table = Vec::with_capacity(count);
1367            for _ in 0..count {
1368                exception_index_table.push(reader.read_u2()?);
1369            }
1370            AttributeInfo::Exceptions {
1371                exception_index_table,
1372            }
1373        }
1374        "SourceFile" => AttributeInfo::SourceFile {
1375            sourcefile_index: reader.read_u2()?,
1376        },
1377        "LineNumberTable" => {
1378            let count = reader.read_u2()? as usize;
1379            let mut entries = Vec::with_capacity(count);
1380            for _ in 0..count {
1381                entries.push(LineNumber {
1382                    start_pc: reader.read_u2()?,
1383                    line_number: reader.read_u2()?,
1384                });
1385            }
1386            AttributeInfo::LineNumberTable { entries }
1387        }
1388        "LocalVariableTable" => {
1389            let count = reader.read_u2()? as usize;
1390            let mut entries = Vec::with_capacity(count);
1391            for _ in 0..count {
1392                entries.push(LocalVariable {
1393                    start_pc: reader.read_u2()?,
1394                    length: reader.read_u2()?,
1395                    name_index: reader.read_u2()?,
1396                    descriptor_index: reader.read_u2()?,
1397                    index: reader.read_u2()?,
1398                });
1399            }
1400            AttributeInfo::LocalVariableTable { entries }
1401        }
1402        "Signature" => AttributeInfo::Signature {
1403            signature_index: reader.read_u2()?,
1404        },
1405        "StackMapTable" => {
1406            let count = reader.read_u2()? as usize;
1407            let mut entries = Vec::with_capacity(count);
1408            for _ in 0..count {
1409                let frame_type = reader.read_u1()?;
1410                let frame = match frame_type {
1411                    0..=63 => StackMapFrame::SameFrame {
1412                        offset_delta: frame_type as u16,
1413                    },
1414                    64..=127 => StackMapFrame::SameLocals1StackItemFrame {
1415                        offset_delta: (frame_type - 64) as u16,
1416                        stack: parse_verification_type(&mut reader)?,
1417                    },
1418                    247 => StackMapFrame::SameLocals1StackItemFrameExtended {
1419                        offset_delta: reader.read_u2()?,
1420                        stack: parse_verification_type(&mut reader)?,
1421                    },
1422                    248..=250 => StackMapFrame::ChopFrame {
1423                        offset_delta: reader.read_u2()?,
1424                        k: 251 - frame_type,
1425                    },
1426                    251 => StackMapFrame::SameFrameExtended {
1427                        offset_delta: reader.read_u2()?,
1428                    },
1429                    252..=254 => {
1430                        let offset_delta = reader.read_u2()?;
1431                        let locals_count = (frame_type - 251) as usize;
1432                        let mut locals = Vec::with_capacity(locals_count);
1433                        for _ in 0..locals_count {
1434                            locals.push(parse_verification_type(&mut reader)?);
1435                        }
1436                        StackMapFrame::AppendFrame {
1437                            offset_delta,
1438                            locals,
1439                        }
1440                    }
1441                    255 => {
1442                        let offset_delta = reader.read_u2()?;
1443                        let locals_count = reader.read_u2()? as usize;
1444                        let mut locals = Vec::with_capacity(locals_count);
1445                        for _ in 0..locals_count {
1446                            locals.push(parse_verification_type(&mut reader)?);
1447                        }
1448                        let stack_count = reader.read_u2()? as usize;
1449                        let mut stack = Vec::with_capacity(stack_count);
1450                        for _ in 0..stack_count {
1451                            stack.push(parse_verification_type(&mut reader)?);
1452                        }
1453                        StackMapFrame::FullFrame {
1454                            offset_delta,
1455                            locals,
1456                            stack,
1457                        }
1458                    }
1459                    _ => {
1460                        return Err(ClassReadError::InvalidAttribute(
1461                            "StackMapTable".to_string(),
1462                        ));
1463                    }
1464                };
1465                entries.push(frame);
1466            }
1467            AttributeInfo::StackMapTable { entries }
1468        }
1469        "Deprecated" => AttributeInfo::Deprecated,
1470        "Synthetic" => AttributeInfo::Synthetic,
1471        "InnerClasses" => {
1472            let count = reader.read_u2()? as usize;
1473            let mut classes = Vec::with_capacity(count);
1474            for _ in 0..count {
1475                classes.push(InnerClass {
1476                    inner_class_info_index: reader.read_u2()?,
1477                    outer_class_info_index: reader.read_u2()?,
1478                    inner_name_index: reader.read_u2()?,
1479                    inner_class_access_flags: reader.read_u2()?,
1480                });
1481            }
1482            AttributeInfo::InnerClasses { classes }
1483        }
1484        "EnclosingMethod" => AttributeInfo::EnclosingMethod {
1485            class_index: reader.read_u2()?,
1486            method_index: reader.read_u2()?,
1487        },
1488        "Module" => AttributeInfo::Module(parse_module_attribute(&mut reader)?),
1489        "ModulePackages" => {
1490            let count = reader.read_u2()? as usize;
1491            let mut package_index_table = Vec::with_capacity(count);
1492            for _ in 0..count {
1493                package_index_table.push(reader.read_u2()?);
1494            }
1495            AttributeInfo::ModulePackages {
1496                package_index_table,
1497            }
1498        }
1499        "ModuleMainClass" => AttributeInfo::ModuleMainClass {
1500            main_class_index: reader.read_u2()?,
1501        },
1502        "BootstrapMethods" => {
1503            let count = reader.read_u2()? as usize;
1504            let mut methods = Vec::with_capacity(count);
1505            for _ in 0..count {
1506                let bootstrap_method_ref = reader.read_u2()?;
1507                let arg_count = reader.read_u2()? as usize;
1508                let mut bootstrap_arguments = Vec::with_capacity(arg_count);
1509                for _ in 0..arg_count {
1510                    bootstrap_arguments.push(reader.read_u2()?);
1511                }
1512                methods.push(BootstrapMethod {
1513                    bootstrap_method_ref,
1514                    bootstrap_arguments,
1515                });
1516            }
1517            AttributeInfo::BootstrapMethods { methods }
1518        }
1519        "MethodParameters" => {
1520            let count = reader.read_u1()? as usize;
1521            let mut parameters = Vec::with_capacity(count);
1522            for _ in 0..count {
1523                parameters.push(MethodParameter {
1524                    name_index: reader.read_u2()?,
1525                    access_flags: reader.read_u2()?,
1526                });
1527            }
1528            AttributeInfo::MethodParameters { parameters }
1529        }
1530        "RuntimeVisibleAnnotations" => {
1531            let annotations = parse_annotations(&mut reader)?;
1532            AttributeInfo::RuntimeVisibleAnnotations { annotations }
1533        }
1534        "RuntimeInvisibleAnnotations" => {
1535            let annotations = parse_annotations(&mut reader)?;
1536            AttributeInfo::RuntimeInvisibleAnnotations { annotations }
1537        }
1538        "RuntimeVisibleParameterAnnotations" => {
1539            let parameters = parse_parameter_annotations(&mut reader)?;
1540            AttributeInfo::RuntimeVisibleParameterAnnotations { parameters }
1541        }
1542        "RuntimeInvisibleParameterAnnotations" => {
1543            let parameters = parse_parameter_annotations(&mut reader)?;
1544            AttributeInfo::RuntimeInvisibleParameterAnnotations { parameters }
1545        }
1546        "RuntimeVisibleTypeAnnotations" => {
1547            let annotations = parse_type_annotations(&mut reader)?;
1548            AttributeInfo::RuntimeVisibleTypeAnnotations { annotations }
1549        }
1550        "RuntimeInvisibleTypeAnnotations" => {
1551            let annotations = parse_type_annotations(&mut reader)?;
1552            AttributeInfo::RuntimeInvisibleTypeAnnotations { annotations }
1553        }
1554        "PermittedSubclasses" => {
1555            let count = reader.read_u2()? as usize;
1556            let mut classes = Vec::with_capacity(count);
1557            for _ in 0..count {
1558                classes.push(reader.read_u2()?);
1559            }
1560            AttributeInfo::PermittedSubclasses { classes }
1561        }
1562        "Record" => {
1563            let count = reader.read_u2()? as usize;
1564            let mut components = Vec::with_capacity(count);
1565            for _ in 0..count {
1566                let name_index = reader.read_u2()?;
1567                let descriptor_index = reader.read_u2()?;
1568                let attributes = read_attributes(&mut reader, cp)?;
1569                components.push(RecordComponent {
1570                    name_index,
1571                    descriptor_index,
1572                    attributes,
1573                });
1574            }
1575            AttributeInfo::Record { components }
1576        }
1577        _ => {
1578            return Ok(AttributeInfo::Unknown {
1579                name: name.to_string(),
1580                info,
1581            });
1582        }
1583    };
1584
1585    if reader.remaining() != 0 {
1586        return Err(ClassReadError::InvalidAttribute(name.to_string()));
1587    }
1588
1589    Ok(attribute)
1590}
1591
1592fn parse_module_attribute(reader: &mut ByteReader<'_>) -> Result<ModuleAttribute, ClassReadError> {
1593    let module_name_index = reader.read_u2()?;
1594    let module_flags = reader.read_u2()?;
1595    let module_version_index = reader.read_u2()?;
1596
1597    let requires_count = reader.read_u2()? as usize;
1598    let mut requires = Vec::with_capacity(requires_count);
1599    for _ in 0..requires_count {
1600        requires.push(ModuleRequire {
1601            requires_index: reader.read_u2()?,
1602            requires_flags: reader.read_u2()?,
1603            requires_version_index: reader.read_u2()?,
1604        });
1605    }
1606
1607    let exports_count = reader.read_u2()? as usize;
1608    let mut exports = Vec::with_capacity(exports_count);
1609    for _ in 0..exports_count {
1610        let exports_index = reader.read_u2()?;
1611        let exports_flags = reader.read_u2()?;
1612        let exports_to_count = reader.read_u2()? as usize;
1613        let mut exports_to_index = Vec::with_capacity(exports_to_count);
1614        for _ in 0..exports_to_count {
1615            exports_to_index.push(reader.read_u2()?);
1616        }
1617        exports.push(ModuleExport {
1618            exports_index,
1619            exports_flags,
1620            exports_to_index,
1621        });
1622    }
1623
1624    let opens_count = reader.read_u2()? as usize;
1625    let mut opens = Vec::with_capacity(opens_count);
1626    for _ in 0..opens_count {
1627        let opens_index = reader.read_u2()?;
1628        let opens_flags = reader.read_u2()?;
1629        let opens_to_count = reader.read_u2()? as usize;
1630        let mut opens_to_index = Vec::with_capacity(opens_to_count);
1631        for _ in 0..opens_to_count {
1632            opens_to_index.push(reader.read_u2()?);
1633        }
1634        opens.push(ModuleOpen {
1635            opens_index,
1636            opens_flags,
1637            opens_to_index,
1638        });
1639    }
1640
1641    let uses_count = reader.read_u2()? as usize;
1642    let mut uses_index = Vec::with_capacity(uses_count);
1643    for _ in 0..uses_count {
1644        uses_index.push(reader.read_u2()?);
1645    }
1646
1647    let provides_count = reader.read_u2()? as usize;
1648    let mut provides = Vec::with_capacity(provides_count);
1649    for _ in 0..provides_count {
1650        let provides_index = reader.read_u2()?;
1651        let provides_with_count = reader.read_u2()? as usize;
1652        let mut provides_with_index = Vec::with_capacity(provides_with_count);
1653        for _ in 0..provides_with_count {
1654            provides_with_index.push(reader.read_u2()?);
1655        }
1656        provides.push(ModuleProvide {
1657            provides_index,
1658            provides_with_index,
1659        });
1660    }
1661
1662    Ok(ModuleAttribute {
1663        module_name_index,
1664        module_flags,
1665        module_version_index,
1666        requires,
1667        exports,
1668        opens,
1669        uses_index,
1670        provides,
1671    })
1672}
1673
1674fn parse_annotations(reader: &mut ByteReader) -> Result<Vec<Annotation>, ClassReadError> {
1675    let num = reader.read_u2()? as usize;
1676    let mut out = Vec::with_capacity(num);
1677    for _ in 0..num {
1678        out.push(parse_annotation(reader)?);
1679    }
1680    Ok(out)
1681}
1682
1683fn parse_annotation(reader: &mut ByteReader) -> Result<Annotation, ClassReadError> {
1684    let type_descriptor_index = reader.read_u2()?;
1685    let num_pairs = reader.read_u2()? as usize;
1686    let mut element_value_pairs = Vec::with_capacity(num_pairs);
1687    for _ in 0..num_pairs {
1688        let element_name_index = reader.read_u2()?;
1689        let value = parse_element_value(reader)?;
1690        element_value_pairs.push(ElementValuePair {
1691            element_name_index,
1692            value,
1693        });
1694    }
1695    Ok(Annotation {
1696        type_descriptor_index,
1697        element_value_pairs,
1698    })
1699}
1700
1701fn parse_parameter_annotations(
1702    reader: &mut ByteReader,
1703) -> Result<ParameterAnnotations, ClassReadError> {
1704    let num_params = reader.read_u1()? as usize;
1705    let mut parameters = Vec::with_capacity(num_params);
1706    for _ in 0..num_params {
1707        let num_ann = reader.read_u2()? as usize;
1708        let mut anns = Vec::with_capacity(num_ann);
1709        for _ in 0..num_ann {
1710            anns.push(parse_annotation(reader)?);
1711        }
1712        parameters.push(anns);
1713    }
1714    Ok(ParameterAnnotations { parameters })
1715}
1716
1717fn parse_type_annotations(reader: &mut ByteReader) -> Result<Vec<TypeAnnotation>, ClassReadError> {
1718    let num = reader.read_u2()? as usize;
1719    let mut out = Vec::with_capacity(num);
1720    for _ in 0..num {
1721        out.push(parse_type_annotation(reader)?);
1722    }
1723    Ok(out)
1724}
1725
1726fn parse_type_annotation(reader: &mut ByteReader) -> Result<TypeAnnotation, ClassReadError> {
1727    let target_type = reader.read_u1()?;
1728    let target_info = parse_type_annotation_target_info(reader, target_type)?;
1729    let target_path = parse_type_path(reader)?;
1730    let annotation = parse_annotation(reader)?;
1731    Ok(TypeAnnotation {
1732        target_type,
1733        target_info,
1734        target_path,
1735        annotation,
1736    })
1737}
1738
1739fn parse_type_path(reader: &mut ByteReader) -> Result<TypePath, ClassReadError> {
1740    let path_length = reader.read_u1()? as usize;
1741    let mut path = Vec::with_capacity(path_length);
1742    for _ in 0..path_length {
1743        path.push(TypePathEntry {
1744            type_path_kind: reader.read_u1()?,
1745            type_argument_index: reader.read_u1()?,
1746        });
1747    }
1748    Ok(TypePath { path })
1749}
1750
1751fn parse_type_annotation_target_info(
1752    reader: &mut ByteReader,
1753    target_type: u8,
1754) -> Result<TypeAnnotationTargetInfo, ClassReadError> {
1755    use crate::constants::*;
1756
1757    let ti = match target_type {
1758        TA_TARGET_CLASS_TYPE_PARAMETER | TA_TARGET_METHOD_TYPE_PARAMETER => {
1759            TypeAnnotationTargetInfo::TypeParameter {
1760                type_parameter_index: reader.read_u1()?,
1761            }
1762        }
1763
1764        TA_TARGET_CLASS_EXTENDS => TypeAnnotationTargetInfo::Supertype {
1765            supertype_index: reader.read_u2()?,
1766        },
1767
1768        TA_TARGET_CLASS_TYPE_PARAMETER_BOUND | TA_TARGET_METHOD_TYPE_PARAMETER_BOUND => {
1769            TypeAnnotationTargetInfo::TypeParameterBound {
1770                type_parameter_index: reader.read_u1()?,
1771                bound_index: reader.read_u1()?,
1772            }
1773        }
1774
1775        TA_TARGET_FIELD | TA_TARGET_METHOD_RETURN | TA_TARGET_METHOD_RECEIVER => {
1776            TypeAnnotationTargetInfo::Empty
1777        }
1778
1779        TA_TARGET_METHOD_FORMAL_PARAMETER => TypeAnnotationTargetInfo::FormalParameter {
1780            formal_parameter_index: reader.read_u1()?,
1781        },
1782
1783        TA_TARGET_THROWS => TypeAnnotationTargetInfo::Throws {
1784            throws_type_index: reader.read_u2()?,
1785        },
1786
1787        TA_TARGET_LOCAL_VARIABLE | TA_TARGET_RESOURCE_VARIABLE => {
1788            let table_length = reader.read_u2()? as usize;
1789            let mut table = Vec::with_capacity(table_length);
1790            for _ in 0..table_length {
1791                table.push(LocalVarTargetTableEntry {
1792                    start_pc: reader.read_u2()?,
1793                    length: reader.read_u2()?,
1794                    index: reader.read_u2()?,
1795                });
1796            }
1797            TypeAnnotationTargetInfo::LocalVar { table }
1798        }
1799
1800        TA_TARGET_EXCEPTION_PARAMETER => TypeAnnotationTargetInfo::Catch {
1801            exception_table_index: reader.read_u2()?,
1802        },
1803
1804        TA_TARGET_INSTANCEOF
1805        | TA_TARGET_NEW
1806        | TA_TARGET_CONSTRUCTOR_REFERENCE_RECEIVER
1807        | TA_TARGET_METHOD_REFERENCE_RECEIVER => TypeAnnotationTargetInfo::Offset {
1808            offset: reader.read_u2()?,
1809        },
1810
1811        TA_TARGET_CAST
1812        | TA_TARGET_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
1813        | TA_TARGET_METHOD_INVOCATION_TYPE_ARGUMENT
1814        | TA_TARGET_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
1815        | TA_TARGET_METHOD_REFERENCE_TYPE_ARGUMENT => TypeAnnotationTargetInfo::TypeArgument {
1816            offset: reader.read_u2()?,
1817            type_argument_index: reader.read_u1()?,
1818        },
1819
1820        _ => {
1821            return Err(ClassReadError::InvalidAttribute(format!(
1822                "TypeAnnotationTargetInfo(target_type=0x{:02X})",
1823                target_type
1824            )));
1825        }
1826    };
1827
1828    Ok(ti)
1829}
1830
1831fn parse_element_value(reader: &mut ByteReader) -> Result<ElementValue, ClassReadError> {
1832    let tag = reader.read_u1()?;
1833    let v = match tag {
1834        b'B' | b'C' | b'D' | b'F' | b'I' | b'J' | b'S' | b'Z' | b's' => {
1835            ElementValue::ConstValueIndex {
1836                tag,
1837                const_value_index: reader.read_u2()?,
1838            }
1839        }
1840        b'e' => ElementValue::EnumConstValue {
1841            type_name_index: reader.read_u2()?,
1842            const_name_index: reader.read_u2()?,
1843        },
1844        b'c' => ElementValue::ClassInfoIndex {
1845            class_info_index: reader.read_u2()?,
1846        },
1847        b'@' => ElementValue::AnnotationValue(Box::new(parse_annotation(reader)?)),
1848        b'[' => {
1849            let n = reader.read_u2()? as usize;
1850            let mut items = Vec::with_capacity(n);
1851            for _ in 0..n {
1852                items.push(parse_element_value(reader)?);
1853            }
1854            ElementValue::ArrayValue(items)
1855        }
1856        _ => {
1857            return Err(ClassReadError::InvalidAttribute(
1858                "AnnotationElementValue".to_string(),
1859            ));
1860        }
1861    };
1862    Ok(v)
1863}
1864
1865fn parse_verification_type(
1866    reader: &mut ByteReader<'_>,
1867) -> Result<VerificationTypeInfo, ClassReadError> {
1868    let tag = reader.read_u1()?;
1869    let kind = match tag {
1870        0 => VerificationTypeInfo::Top,
1871        1 => VerificationTypeInfo::Integer,
1872        2 => VerificationTypeInfo::Float,
1873        3 => VerificationTypeInfo::Double,
1874        4 => VerificationTypeInfo::Long,
1875        5 => VerificationTypeInfo::Null,
1876        6 => VerificationTypeInfo::UninitializedThis,
1877        7 => VerificationTypeInfo::Object {
1878            cpool_index: reader.read_u2()?,
1879        },
1880        8 => VerificationTypeInfo::Uninitialized {
1881            offset: reader.read_u2()?,
1882        },
1883        _ => {
1884            return Err(ClassReadError::InvalidAttribute(
1885                "StackMapTable".to_string(),
1886            ));
1887        }
1888    };
1889    Ok(kind)
1890}
1891
1892fn cp_utf8(cp: &[CpInfo], index: u16) -> Result<&str, ClassReadError> {
1893    match cp.get(index as usize) {
1894        Some(CpInfo::Utf8(value)) => Ok(value.as_str()),
1895        _ => Err(ClassReadError::InvalidIndex(index)),
1896    }
1897}
1898
1899fn cp_class_name(cp: &[CpInfo], index: u16) -> Result<&str, ClassReadError> {
1900    match cp.get(index as usize) {
1901        Some(CpInfo::Class { name_index }) => cp_utf8(cp, *name_index),
1902        _ => Err(ClassReadError::InvalidIndex(index)),
1903    }
1904}
1905
1906fn cp_name_and_type(cp: &[CpInfo], index: u16) -> Result<(&str, &str), ClassReadError> {
1907    match cp.get(index as usize) {
1908        Some(CpInfo::NameAndType {
1909            name_index,
1910            descriptor_index,
1911        }) => Ok((cp_utf8(cp, *name_index)?, cp_utf8(cp, *descriptor_index)?)),
1912        _ => Err(ClassReadError::InvalidIndex(index)),
1913    }
1914}
1915
1916fn cp_field_ref(cp: &[CpInfo], index: u16) -> Result<(&str, &str, &str), ClassReadError> {
1917    match cp.get(index as usize) {
1918        Some(CpInfo::Fieldref {
1919            class_index,
1920            name_and_type_index,
1921        }) => {
1922            let owner = cp_class_name(cp, *class_index)?;
1923            let (name, desc) = cp_name_and_type(cp, *name_and_type_index)?;
1924            Ok((owner, name, desc))
1925        }
1926        _ => Err(ClassReadError::InvalidIndex(index)),
1927    }
1928}
1929
1930fn cp_method_ref(cp: &[CpInfo], index: u16) -> Result<(&str, &str, &str, bool), ClassReadError> {
1931    match cp.get(index as usize) {
1932        Some(CpInfo::Methodref {
1933            class_index,
1934            name_and_type_index,
1935        }) => {
1936            let owner = cp_class_name(cp, *class_index)?;
1937            let (name, desc) = cp_name_and_type(cp, *name_and_type_index)?;
1938            Ok((owner, name, desc, false))
1939        }
1940        Some(CpInfo::InterfaceMethodref {
1941            class_index,
1942            name_and_type_index,
1943        }) => {
1944            let owner = cp_class_name(cp, *class_index)?;
1945            let (name, desc) = cp_name_and_type(cp, *name_and_type_index)?;
1946            Ok((owner, name, desc, true))
1947        }
1948        _ => Err(ClassReadError::InvalidIndex(index)),
1949    }
1950}
1951
1952fn cp_invoke_dynamic(cp: &[CpInfo], index: u16) -> Result<(&str, &str), ClassReadError> {
1953    match cp.get(index as usize) {
1954        Some(CpInfo::InvokeDynamic {
1955            name_and_type_index,
1956            ..
1957        }) => cp_name_and_type(cp, *name_and_type_index),
1958        _ => Err(ClassReadError::InvalidIndex(index)),
1959    }
1960}
1961
1962fn cp_ldc_constant(cp: &[CpInfo], index: u16) -> Result<LdcConstant, ClassReadError> {
1963    match cp.get(index as usize) {
1964        Some(CpInfo::Integer(value)) => Ok(LdcConstant::Integer(*value)),
1965        Some(CpInfo::Float(value)) => Ok(LdcConstant::Float(*value)),
1966        Some(CpInfo::Long(value)) => Ok(LdcConstant::Long(*value)),
1967        Some(CpInfo::Double(value)) => Ok(LdcConstant::Double(*value)),
1968        Some(CpInfo::String { string_index }) => {
1969            Ok(LdcConstant::String(cp_utf8(cp, *string_index)?.to_string()))
1970        }
1971        Some(CpInfo::Class { name_index }) => {
1972            Ok(LdcConstant::Class(cp_utf8(cp, *name_index)?.to_string()))
1973        }
1974        Some(CpInfo::MethodType { descriptor_index }) => Ok(LdcConstant::MethodType(
1975            cp_utf8(cp, *descriptor_index)?.to_string(),
1976        )),
1977        Some(CpInfo::MethodHandle {
1978            reference_kind,
1979            reference_index,
1980        }) => Ok(LdcConstant::MethodHandle {
1981            reference_kind: *reference_kind,
1982            reference_index: *reference_index,
1983        }),
1984        Some(CpInfo::Dynamic { .. }) => Ok(LdcConstant::Dynamic),
1985        _ => Err(ClassReadError::InvalidIndex(index)),
1986    }
1987}
1988
1989fn decode_modified_utf8(bytes: &[u8]) -> Result<String, ClassReadError> {
1990    let mut code_units = Vec::with_capacity(bytes.len());
1991    let mut i = 0;
1992    while i < bytes.len() {
1993        let byte = bytes[i];
1994        if byte & 0x80 == 0 {
1995            code_units.push(byte as u16);
1996            i += 1;
1997        } else if byte & 0xE0 == 0xC0 {
1998            if i + 1 >= bytes.len() {
1999                return Err(ClassReadError::Utf8Error("truncated 2-byte".to_string()));
2000            }
2001            let byte2 = bytes[i + 1];
2002            if byte2 & 0xC0 != 0x80 {
2003                return Err(ClassReadError::Utf8Error("invalid 2-byte".to_string()));
2004            }
2005            let value = (((byte & 0x1F) as u16) << 6) | ((byte2 & 0x3F) as u16);
2006            code_units.push(value);
2007            i += 2;
2008        } else if byte & 0xF0 == 0xE0 {
2009            if i + 2 >= bytes.len() {
2010                return Err(ClassReadError::Utf8Error("truncated 3-byte".to_string()));
2011            }
2012            let byte2 = bytes[i + 1];
2013            let byte3 = bytes[i + 2];
2014            if byte2 & 0xC0 != 0x80 || byte3 & 0xC0 != 0x80 {
2015                return Err(ClassReadError::Utf8Error("invalid 3-byte".to_string()));
2016            }
2017            let value = (((byte & 0x0F) as u16) << 12)
2018                | (((byte2 & 0x3F) as u16) << 6)
2019                | ((byte3 & 0x3F) as u16);
2020            code_units.push(value);
2021            i += 3;
2022        } else {
2023            return Err(ClassReadError::Utf8Error(
2024                "invalid leading byte".to_string(),
2025            ));
2026        }
2027    }
2028
2029    String::from_utf16(&code_units)
2030        .map_err(|_| ClassReadError::Utf8Error("invalid utf16".to_string()))
2031}
2032
2033fn parse_code_instructions(code: &[u8]) -> Result<Vec<Insn>, ClassReadError> {
2034    let mut reader = ByteReader::new(code);
2035    let mut insns = Vec::new();
2036
2037    while reader.remaining() > 0 {
2038        let opcode_offset = reader.pos();
2039        let opcode = reader.read_u1()?;
2040        let insn = match opcode {
2041            opcodes::NOP..=opcodes::DCONST_1 => Insn::Simple(opcode.into()),
2042            opcodes::BIPUSH => Insn::Int(IntInsnNode {
2043                insn: opcode.into(),
2044                operand: reader.read_i1()? as i32,
2045            }),
2046            opcodes::SIPUSH => Insn::Int(IntInsnNode {
2047                insn: opcode.into(),
2048                operand: reader.read_i2()? as i32,
2049            }),
2050            opcodes::LDC => Insn::Ldc(LdcInsnNode {
2051                insn: opcode.into(),
2052                value: LdcValue::Index(reader.read_u1()? as u16),
2053            }),
2054            opcodes::LDC_W | opcodes::LDC2_W => Insn::Ldc(LdcInsnNode {
2055                insn: opcode.into(),
2056                value: LdcValue::Index(reader.read_u2()?),
2057            }),
2058            opcodes::ILOAD..=opcodes::ALOAD => Insn::Var(VarInsnNode {
2059                insn: opcode.into(),
2060                var_index: reader.read_u1()? as u16,
2061            }),
2062            opcodes::ILOAD_0..=opcodes::SALOAD => Insn::Simple(opcode.into()),
2063            opcodes::ISTORE..=opcodes::ASTORE => Insn::Var(VarInsnNode {
2064                insn: opcode.into(),
2065                var_index: reader.read_u1()? as u16,
2066            }),
2067            opcodes::ISTORE_0..=opcodes::SASTORE => Insn::Simple(opcode.into()),
2068            opcodes::POP..=opcodes::LXOR => Insn::Simple(opcode.into()),
2069            opcodes::IINC => Insn::Iinc(IincInsnNode {
2070                insn: opcode.into(),
2071                var_index: reader.read_u1()? as u16,
2072                increment: reader.read_i1()? as i16,
2073            }),
2074            opcodes::I2L..=opcodes::DCMPG => Insn::Simple(opcode.into()),
2075            opcodes::IFEQ..=opcodes::JSR => Insn::Jump(JumpInsnNode {
2076                insn: opcode.into(),
2077                offset: reader.read_i2()? as i32,
2078            }),
2079            opcodes::RET => Insn::Var(VarInsnNode {
2080                insn: opcode.into(),
2081                var_index: reader.read_u1()? as u16,
2082            }),
2083            opcodes::TABLESWITCH => read_table_switch(&mut reader, opcode_offset)?,
2084            opcodes::LOOKUPSWITCH => read_lookup_switch(&mut reader, opcode_offset)?,
2085            opcodes::IRETURN..=opcodes::RETURN => Insn::Simple(InsnNode { opcode }),
2086            opcodes::GETSTATIC..=opcodes::PUTFIELD => Insn::Field(FieldInsnNode {
2087                insn: opcode.into(),
2088                field_ref: MemberRef::Index(reader.read_u2()?),
2089            }),
2090            opcodes::INVOKEVIRTUAL..=opcodes::INVOKESTATIC => Insn::Method(MethodInsnNode {
2091                insn: opcode.into(),
2092                method_ref: MemberRef::Index(reader.read_u2()?),
2093            }),
2094            opcodes::INVOKEINTERFACE => {
2095                let method_index = reader.read_u2()?;
2096                let count = reader.read_u1()?;
2097                let _ = reader.read_u1()?;
2098                Insn::InvokeInterface(InvokeInterfaceInsnNode {
2099                    insn: opcode.into(),
2100                    method_index,
2101                    count,
2102                })
2103            }
2104            opcodes::INVOKEDYNAMIC => {
2105                let method_index = reader.read_u2()?;
2106                let _ = reader.read_u2()?;
2107                Insn::InvokeDynamic(InvokeDynamicInsnNode::from_index(method_index))
2108            }
2109            opcodes::NEW => Insn::Type(TypeInsnNode {
2110                insn: opcode.into(),
2111                type_index: reader.read_u2()?,
2112            }),
2113            opcodes::NEWARRAY => Insn::Int(IntInsnNode {
2114                insn: opcode.into(),
2115                operand: reader.read_u1()? as i32,
2116            }),
2117            opcodes::ANEWARRAY => Insn::Type(TypeInsnNode {
2118                insn: opcode.into(),
2119                type_index: reader.read_u2()?,
2120            }),
2121            opcodes::ARRAYLENGTH | opcodes::ATHROW => Insn::Simple(opcode.into()),
2122            opcodes::CHECKCAST | opcodes::INSTANCEOF => Insn::Type(TypeInsnNode {
2123                insn: opcode.into(),
2124                type_index: reader.read_u2()?,
2125            }),
2126            opcodes::MONITORENTER | opcodes::MONITOREXIT => Insn::Simple(opcode.into()),
2127            opcodes::WIDE => read_wide(&mut reader)?,
2128            opcodes::MULTIANEWARRAY => Insn::MultiANewArray(MultiANewArrayInsnNode {
2129                insn: opcode.into(),
2130                type_index: reader.read_u2()?,
2131                dimensions: reader.read_u1()?,
2132            }),
2133            opcodes::IFNULL | opcodes::IFNONNULL => Insn::Jump(JumpInsnNode {
2134                insn: opcode.into(),
2135                offset: reader.read_i2()? as i32,
2136            }),
2137            opcodes::GOTO_W | opcodes::JSR_W => Insn::Jump(JumpInsnNode {
2138                insn: opcode.into(),
2139                offset: reader.read_i4()?,
2140            }),
2141            opcodes::BREAKPOINT => Insn::Simple(opcode.into()),
2142            opcodes::IMPDEP1 | opcodes::IMPDEP2 => Insn::Simple(opcode.into()),
2143            _ => {
2144                return Err(ClassReadError::InvalidOpcode {
2145                    opcode,
2146                    offset: opcode_offset,
2147                });
2148            }
2149        };
2150
2151        insns.push(insn);
2152    }
2153
2154    Ok(insns)
2155}
2156
2157pub(crate) fn parse_code_instructions_public(code: &[u8]) -> Result<Vec<Insn>, ClassReadError> {
2158    parse_code_instructions(code)
2159}
2160
2161#[derive(Debug, Clone)]
2162struct ParsedInstruction {
2163    offset: u16,
2164    insn: Insn,
2165}
2166
2167fn parse_code_instructions_with_offsets(
2168    code: &[u8],
2169) -> Result<Vec<ParsedInstruction>, ClassReadError> {
2170    let mut reader = ByteReader::new(code);
2171    let mut insns = Vec::new();
2172
2173    while reader.remaining() > 0 {
2174        let opcode_offset = reader.pos();
2175        let opcode = reader.read_u1()?;
2176        let insn = match opcode {
2177            opcodes::NOP..=opcodes::DCONST_1 => Insn::Simple(opcode.into()),
2178            opcodes::BIPUSH => Insn::Int(IntInsnNode {
2179                insn: opcode.into(),
2180                operand: reader.read_i1()? as i32,
2181            }),
2182            opcodes::SIPUSH => Insn::Int(IntInsnNode {
2183                insn: opcode.into(),
2184                operand: reader.read_i2()? as i32,
2185            }),
2186            opcodes::LDC => Insn::Ldc(LdcInsnNode {
2187                insn: opcode.into(),
2188                value: LdcValue::Index(reader.read_u1()? as u16),
2189            }),
2190            opcodes::LDC_W | opcodes::LDC2_W => Insn::Ldc(LdcInsnNode {
2191                insn: opcode.into(),
2192                value: LdcValue::Index(reader.read_u2()?),
2193            }),
2194            opcodes::ILOAD..=opcodes::ALOAD => Insn::Var(VarInsnNode {
2195                insn: opcode.into(),
2196                var_index: reader.read_u1()? as u16,
2197            }),
2198            opcodes::ILOAD_0..=opcodes::SALOAD => Insn::Simple(opcode.into()),
2199            opcodes::ISTORE..=opcodes::ASTORE => Insn::Var(VarInsnNode {
2200                insn: opcode.into(),
2201                var_index: reader.read_u1()? as u16,
2202            }),
2203            opcodes::ISTORE_0..=opcodes::SASTORE => Insn::Simple(opcode.into()),
2204            opcodes::POP..=opcodes::LXOR => Insn::Simple(opcode.into()),
2205            opcodes::IINC => Insn::Iinc(IincInsnNode {
2206                insn: opcode.into(),
2207                var_index: reader.read_u1()? as u16,
2208                increment: reader.read_i1()? as i16,
2209            }),
2210            opcodes::I2L..=opcodes::DCMPG => Insn::Simple(opcode.into()),
2211            opcodes::IFEQ..=opcodes::JSR => Insn::Jump(JumpInsnNode {
2212                insn: opcode.into(),
2213                offset: reader.read_i2()? as i32,
2214            }),
2215            opcodes::RET => Insn::Var(VarInsnNode {
2216                insn: opcode.into(),
2217                var_index: reader.read_u1()? as u16,
2218            }),
2219            opcodes::TABLESWITCH => read_table_switch(&mut reader, opcode_offset)?,
2220            opcodes::LOOKUPSWITCH => read_lookup_switch(&mut reader, opcode_offset)?,
2221            opcodes::IRETURN..=opcodes::RETURN => Insn::Simple(opcode.into()),
2222            opcodes::GETSTATIC..=opcodes::PUTFIELD => Insn::Field(FieldInsnNode {
2223                insn: opcode.into(),
2224                field_ref: MemberRef::Index(reader.read_u2()?),
2225            }),
2226            opcodes::INVOKEVIRTUAL..=opcodes::INVOKESTATIC => Insn::Method(MethodInsnNode {
2227                insn: opcode.into(),
2228                method_ref: MemberRef::Index(reader.read_u2()?),
2229            }),
2230            opcodes::INVOKEINTERFACE => {
2231                let method_index = reader.read_u2()?;
2232                let count = reader.read_u1()?;
2233                let _ = reader.read_u1()?;
2234                Insn::InvokeInterface(InvokeInterfaceInsnNode {
2235                    insn: opcode.into(),
2236                    method_index,
2237                    count,
2238                })
2239            }
2240            opcodes::INVOKEDYNAMIC => {
2241                let method_index = reader.read_u2()?;
2242                let _ = reader.read_u2()?;
2243                Insn::InvokeDynamic(InvokeDynamicInsnNode::from_index(method_index))
2244            }
2245            opcodes::NEW => Insn::Type(TypeInsnNode {
2246                insn: opcode.into(),
2247                type_index: reader.read_u2()?,
2248            }),
2249            opcodes::NEWARRAY => Insn::Int(IntInsnNode {
2250                insn: opcode.into(),
2251                operand: reader.read_u1()? as i32,
2252            }),
2253            opcodes::ANEWARRAY => Insn::Type(TypeInsnNode {
2254                insn: opcode.into(),
2255                type_index: reader.read_u2()?,
2256            }),
2257            opcodes::ARRAYLENGTH | opcodes::ATHROW => Insn::Simple(opcode.into()),
2258            opcodes::CHECKCAST | opcodes::INSTANCEOF => Insn::Type(TypeInsnNode {
2259                insn: opcode.into(),
2260                type_index: reader.read_u2()?,
2261            }),
2262            opcodes::MONITORENTER | opcodes::MONITOREXIT => Insn::Simple(opcode.into()),
2263            opcodes::WIDE => read_wide(&mut reader)?,
2264            opcodes::MULTIANEWARRAY => Insn::MultiANewArray(MultiANewArrayInsnNode {
2265                insn: opcode.into(),
2266                type_index: reader.read_u2()?,
2267                dimensions: reader.read_u1()?,
2268            }),
2269            opcodes::IFNULL | opcodes::IFNONNULL => Insn::Jump(JumpInsnNode {
2270                insn: opcode.into(),
2271                offset: reader.read_i2()? as i32,
2272            }),
2273            opcodes::GOTO_W | opcodes::JSR_W => Insn::Jump(JumpInsnNode {
2274                insn: opcode.into(),
2275                offset: reader.read_i4()?,
2276            }),
2277            opcodes::BREAKPOINT => Insn::Simple(opcode.into()),
2278            opcodes::IMPDEP1 | opcodes::IMPDEP2 => Insn::Simple(opcode.into()),
2279            _ => {
2280                return Err(ClassReadError::InvalidOpcode {
2281                    opcode,
2282                    offset: opcode_offset,
2283                });
2284            }
2285        };
2286
2287        insns.push(ParsedInstruction {
2288            offset: opcode_offset as u16,
2289            insn,
2290        });
2291    }
2292
2293    Ok(insns)
2294}
2295
2296fn build_insn_nodes(
2297    code: &[u8],
2298    exception_table: &[ExceptionTableEntry],
2299    cp: &[CpInfo],
2300) -> Result<
2301    (
2302        Vec<AbstractInsnNode>,
2303        Vec<TryCatchBlockNode>,
2304        std::collections::HashMap<u16, LabelNode>,
2305    ),
2306    ClassReadError,
2307> {
2308    let instructions = parse_code_instructions_with_offsets(code)?;
2309    let mut offsets = std::collections::HashSet::new();
2310    for instruction in &instructions {
2311        offsets.insert(instruction.offset);
2312        match &instruction.insn {
2313            Insn::Jump(node) => {
2314                offsets.insert((instruction.offset as i32 + node.offset) as u16);
2315            }
2316            Insn::TableSwitch(node) => {
2317                offsets.insert((instruction.offset as i32 + node.default_offset) as u16);
2318                for offset in &node.offsets {
2319                    offsets.insert((instruction.offset as i32 + *offset) as u16);
2320                }
2321            }
2322            Insn::LookupSwitch(node) => {
2323                offsets.insert((instruction.offset as i32 + node.default_offset) as u16);
2324                for (_, offset) in &node.pairs {
2325                    offsets.insert((instruction.offset as i32 + *offset) as u16);
2326                }
2327            }
2328            _ => {}
2329        }
2330    }
2331    for entry in exception_table {
2332        offsets.insert(entry.start_pc);
2333        offsets.insert(entry.end_pc);
2334        offsets.insert(entry.handler_pc);
2335    }
2336    offsets.insert(code.len() as u16);
2337
2338    let mut label_by_offset = std::collections::HashMap::new();
2339    for (next_id, offset) in offsets.into_iter().enumerate() {
2340        label_by_offset.insert(offset, LabelNode { id: next_id });
2341    }
2342
2343    let mut nodes = Vec::new();
2344    for instruction in instructions {
2345        if let Some(label) = label_by_offset.get(&{ instruction.offset }) {
2346            nodes.push(AbstractInsnNode::Label(*label));
2347        }
2348        nodes.push(AbstractInsnNode::Insn(instruction.insn));
2349    }
2350    if let Some(label) = label_by_offset.get(&(code.len() as u16)) {
2351        nodes.push(AbstractInsnNode::Label(*label));
2352    }
2353
2354    let mut try_catch_blocks = Vec::new();
2355    for entry in exception_table {
2356        let start = *label_by_offset
2357            .get(&entry.start_pc)
2358            .ok_or_else(|| ClassReadError::InvalidAttribute("missing start label".to_string()))?;
2359        let end = *label_by_offset
2360            .get(&entry.end_pc)
2361            .ok_or_else(|| ClassReadError::InvalidAttribute("missing end label".to_string()))?;
2362        let handler = *label_by_offset
2363            .get(&entry.handler_pc)
2364            .ok_or_else(|| ClassReadError::InvalidAttribute("missing handler label".to_string()))?;
2365        let catch_type = if entry.catch_type == 0 {
2366            None
2367        } else {
2368            Some(cp_class_name(cp, entry.catch_type)?.to_string())
2369        };
2370        try_catch_blocks.push(TryCatchBlockNode {
2371            start,
2372            end,
2373            handler,
2374            catch_type,
2375        });
2376    }
2377
2378    Ok((nodes, try_catch_blocks, label_by_offset))
2379}
2380
2381pub(crate) fn build_insn_nodes_public(
2382    code: &[u8],
2383    exception_table: &[ExceptionTableEntry],
2384    cp: &[CpInfo],
2385) -> Result<(Vec<AbstractInsnNode>, Vec<TryCatchBlockNode>), ClassReadError> {
2386    let (nodes, try_catch_blocks, _) = build_insn_nodes(code, exception_table, cp)?;
2387    Ok((nodes, try_catch_blocks))
2388}
2389
2390fn attach_line_numbers(
2391    nodes: Vec<AbstractInsnNode>,
2392    entries: &[LineNumber],
2393    label_by_offset: &std::collections::HashMap<u16, LabelNode>,
2394) -> Vec<AbstractInsnNode> {
2395    let mut lines_by_label = std::collections::HashMap::<usize, Vec<LineNumberInsnNode>>::new();
2396    for entry in entries {
2397        if let Some(label) = label_by_offset.get(&entry.start_pc) {
2398            lines_by_label
2399                .entry(label.id)
2400                .or_default()
2401                .push(LineNumberInsnNode {
2402                    line: entry.line_number,
2403                    start: *label,
2404                });
2405        }
2406    }
2407
2408    let mut merged = Vec::with_capacity(nodes.len() + entries.len());
2409    for node in nodes {
2410        let label_id = match &node {
2411            AbstractInsnNode::Label(label) => Some(label.id),
2412            _ => None,
2413        };
2414        merged.push(node);
2415        if let Some(label_id) = label_id
2416            && let Some(lines) = lines_by_label.remove(&label_id)
2417        {
2418            for line in lines {
2419                merged.push(AbstractInsnNode::LineNumber(line));
2420            }
2421        }
2422    }
2423    merged
2424}
2425
2426fn read_table_switch(
2427    reader: &mut ByteReader<'_>,
2428    opcode_offset: usize,
2429) -> Result<Insn, ClassReadError> {
2430    reader.align4(opcode_offset)?;
2431    let default_offset = reader.read_i4()?;
2432    let low = reader.read_i4()?;
2433    let high = reader.read_i4()?;
2434    let count = if high < low {
2435        0
2436    } else {
2437        (high - low + 1) as usize
2438    };
2439    let mut offsets = Vec::with_capacity(count);
2440    for _ in 0..count {
2441        offsets.push(reader.read_i4()?);
2442    }
2443    Ok(Insn::TableSwitch(TableSwitchInsnNode {
2444        insn: opcodes::TABLESWITCH.into(),
2445        default_offset,
2446        low,
2447        high,
2448        offsets,
2449    }))
2450}
2451
2452fn read_lookup_switch(
2453    reader: &mut ByteReader<'_>,
2454    opcode_offset: usize,
2455) -> Result<Insn, ClassReadError> {
2456    reader.align4(opcode_offset)?;
2457    let default_offset = reader.read_i4()?;
2458    let npairs = reader.read_i4()? as usize;
2459    let mut pairs = Vec::with_capacity(npairs);
2460    for _ in 0..npairs {
2461        let key = reader.read_i4()?;
2462        let offset = reader.read_i4()?;
2463        pairs.push((key, offset));
2464    }
2465    Ok(Insn::LookupSwitch(LookupSwitchInsnNode {
2466        insn: opcodes::LOOKUPSWITCH.into(),
2467        default_offset,
2468        pairs,
2469    }))
2470}
2471
2472fn read_wide(reader: &mut ByteReader<'_>) -> Result<Insn, ClassReadError> {
2473    let opcode = reader.read_u1()?;
2474    match opcode {
2475        opcodes::ILOAD..=opcodes::ALOAD | opcodes::ISTORE..=opcodes::ASTORE | opcodes::RET => {
2476            Ok(Insn::Var(VarInsnNode {
2477                insn: opcode.into(),
2478                var_index: reader.read_u2()?,
2479            }))
2480        }
2481        opcodes::IINC => Ok(Insn::Iinc(IincInsnNode {
2482            insn: opcode.into(),
2483            var_index: reader.read_u2()?,
2484            increment: reader.read_i2()?,
2485        })),
2486        _ => Err(ClassReadError::InvalidOpcode {
2487            opcode,
2488            offset: reader.pos().saturating_sub(1),
2489        }),
2490    }
2491}
2492
2493fn visit_instruction(
2494    cp: &[CpInfo],
2495    offset: i32,
2496    insn: Insn,
2497    mv: &mut dyn MethodVisitor,
2498) -> Result<(), ClassReadError> {
2499    match insn {
2500        Insn::Simple(node) => {
2501            mv.visit_insn(node.opcode);
2502        }
2503        Insn::Int(node) => {
2504            mv.visit_int_insn(node.insn.opcode, node.operand);
2505        }
2506        Insn::Var(node) => {
2507            mv.visit_var_insn(node.insn.opcode, node.var_index);
2508        }
2509        Insn::Type(node) => {
2510            let type_name = cp_class_name(cp, node.type_index)?;
2511            mv.visit_type_insn(node.insn.opcode, type_name);
2512        }
2513        Insn::Field(node) => {
2514            let index = match node.field_ref {
2515                MemberRef::Index(index) => index,
2516                MemberRef::Symbolic { .. } => {
2517                    return Err(ClassReadError::InvalidIndex(0));
2518                }
2519            };
2520            let (owner, name, desc) = cp_field_ref(cp, index)?;
2521            mv.visit_field_insn(node.insn.opcode, owner, name, desc);
2522        }
2523        Insn::Method(node) => {
2524            let index = match node.method_ref {
2525                MemberRef::Index(index) => index,
2526                MemberRef::Symbolic { .. } => {
2527                    return Err(ClassReadError::InvalidIndex(0));
2528                }
2529            };
2530            let (owner, name, desc, is_interface) = cp_method_ref(cp, index)?;
2531            mv.visit_method_insn(node.insn.opcode, owner, name, desc, is_interface);
2532        }
2533        Insn::InvokeInterface(node) => {
2534            let (owner, name, desc, _is_interface) = cp_method_ref(cp, node.method_index)?;
2535            mv.visit_method_insn(node.insn.opcode, owner, name, desc, true);
2536        }
2537        Insn::InvokeDynamic(node) => {
2538            let (name, desc) = cp_invoke_dynamic(cp, node.method_index)?;
2539            mv.visit_invoke_dynamic_insn(name, desc);
2540        }
2541        Insn::Jump(node) => {
2542            let target = offset + node.offset;
2543            mv.visit_jump_insn(node.insn.opcode, target);
2544        }
2545        Insn::Ldc(node) => {
2546            let index = match node.value {
2547                LdcValue::Index(index) => index,
2548                LdcValue::String(value) => {
2549                    mv.visit_ldc_insn(LdcConstant::String(value));
2550                    return Ok(());
2551                }
2552                LdcValue::Type(value) => {
2553                    match value.clone() {
2554                        Type::Method { .. } => {
2555                            mv.visit_ldc_insn(LdcConstant::MethodType(value.get_descriptor()));
2556                        }
2557                        _ => {
2558                            mv.visit_ldc_insn(LdcConstant::Class(value.get_descriptor()));
2559                        }
2560                    }
2561
2562                    return Ok(());
2563                }
2564                LdcValue::Int(value) => {
2565                    mv.visit_ldc_insn(LdcConstant::Integer(value));
2566                    return Ok(());
2567                }
2568                LdcValue::Float(value) => {
2569                    mv.visit_ldc_insn(LdcConstant::Float(value));
2570                    return Ok(());
2571                }
2572                LdcValue::Long(value) => {
2573                    mv.visit_ldc_insn(LdcConstant::Long(value));
2574                    return Ok(());
2575                }
2576                LdcValue::Double(value) => {
2577                    mv.visit_ldc_insn(LdcConstant::Double(value));
2578                    return Ok(());
2579                }
2580            };
2581            let constant = cp_ldc_constant(cp, index)?;
2582            mv.visit_ldc_insn(constant);
2583        }
2584        Insn::Iinc(node) => {
2585            mv.visit_iinc_insn(node.var_index, node.increment);
2586        }
2587        Insn::TableSwitch(node) => {
2588            let targets = node
2589                .offsets
2590                .iter()
2591                .map(|value| offset + *value)
2592                .collect::<Vec<_>>();
2593            mv.visit_table_switch(offset + node.default_offset, node.low, node.high, &targets);
2594        }
2595        Insn::LookupSwitch(node) => {
2596            let pairs = node
2597                .pairs
2598                .iter()
2599                .map(|(key, value)| (*key, offset + *value))
2600                .collect::<Vec<_>>();
2601            mv.visit_lookup_switch(offset + node.default_offset, &pairs);
2602        }
2603        Insn::MultiANewArray(node) => {
2604            let type_name = cp_class_name(cp, node.type_index)?;
2605            mv.visit_multi_anewarray_insn(type_name, node.dimensions);
2606        }
2607    }
2608    Ok(())
2609}
2610
2611pub struct ByteReader<'a> {
2612    data: &'a [u8],
2613    pos: usize,
2614}
2615
2616impl<'a> ByteReader<'a> {
2617    pub fn new(data: &'a [u8]) -> Self {
2618        Self { data, pos: 0 }
2619    }
2620
2621    pub fn remaining(&self) -> usize {
2622        self.data.len().saturating_sub(self.pos)
2623    }
2624
2625    pub fn pos(&self) -> usize {
2626        self.pos
2627    }
2628
2629    pub fn align4(&mut self, opcode_offset: usize) -> Result<(), ClassReadError> {
2630        let mut padding = (4 - ((opcode_offset + 1) % 4)) % 4;
2631        while padding > 0 {
2632            self.read_u1()?;
2633            padding -= 1;
2634        }
2635        Ok(())
2636    }
2637
2638    pub fn read_u1(&mut self) -> Result<u8, ClassReadError> {
2639        if self.pos >= self.data.len() {
2640            return Err(ClassReadError::UnexpectedEof);
2641        }
2642        let value = self.data[self.pos];
2643        self.pos += 1;
2644        Ok(value)
2645    }
2646
2647    pub fn read_i1(&mut self) -> Result<i8, ClassReadError> {
2648        Ok(self.read_u1()? as i8)
2649    }
2650
2651    pub fn read_u2(&mut self) -> Result<u16, ClassReadError> {
2652        let bytes = self.read_bytes(2)?;
2653        Ok(u16::from_be_bytes([bytes[0], bytes[1]]))
2654    }
2655
2656    pub fn read_i2(&mut self) -> Result<i16, ClassReadError> {
2657        Ok(self.read_u2()? as i16)
2658    }
2659
2660    pub fn read_u4(&mut self) -> Result<u32, ClassReadError> {
2661        let bytes = self.read_bytes(4)?;
2662        Ok(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
2663    }
2664
2665    pub fn read_i4(&mut self) -> Result<i32, ClassReadError> {
2666        let bytes = self.read_bytes(4)?;
2667        Ok(i32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
2668    }
2669
2670    pub fn read_u8(&mut self) -> Result<u64, ClassReadError> {
2671        let bytes = self.read_bytes(8)?;
2672        Ok(u64::from_be_bytes([
2673            bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
2674        ]))
2675    }
2676
2677    pub fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>, ClassReadError> {
2678        if self.pos + len > self.data.len() {
2679            return Err(ClassReadError::UnexpectedEof);
2680        }
2681        let bytes = self.data[self.pos..self.pos + len].to_vec();
2682        self.pos += len;
2683        Ok(bytes)
2684    }
2685}
2686
2687#[cfg(test)]
2688mod tests {
2689    use crate::class_writer::ClassWriter;
2690    use crate::constants::*;
2691    use crate::insn::{Label, LabelNode};
2692    use crate::opcodes;
2693
2694    use super::*;
2695    use std::cell::RefCell;
2696    use std::rc::Rc;
2697
2698    // A mock visitor to capture parsing results
2699    struct MockClassVisitor {
2700        pub visited_name: Rc<RefCell<Option<String>>>,
2701        pub visited_methods: Rc<RefCell<Vec<String>>>,
2702    }
2703
2704    impl MockClassVisitor {
2705        fn new() -> Self {
2706            Self {
2707                visited_name: Rc::new(RefCell::new(None)),
2708                visited_methods: Rc::new(RefCell::new(Vec::new())),
2709            }
2710        }
2711    }
2712
2713    impl ClassVisitor for MockClassVisitor {
2714        fn visit(
2715            &mut self,
2716            _major: u16,
2717            _minor: u16,
2718            _access_flags: u16,
2719            name: &str,
2720            _super_name: Option<&str>,
2721            _interfaces: &[String],
2722        ) {
2723            *self.visited_name.borrow_mut() = Some(name.to_string());
2724        }
2725
2726        fn visit_method(
2727            &mut self,
2728            _access_flags: u16,
2729            name: &str,
2730            _descriptor: &str,
2731        ) -> Option<Box<dyn MethodVisitor>> {
2732            self.visited_methods.borrow_mut().push(name.to_string());
2733            None
2734        }
2735    }
2736
2737    /// Helper to generate a minimal valid class file byte array (Java 8).
2738    /// Class Name: "TestClass"
2739    fn generate_minimal_class() -> Vec<u8> {
2740        let mut w = Vec::new();
2741        // Magic
2742        w.extend_from_slice(&0xCAFEBABE_u32.to_be_bytes());
2743        // Version (Java 8 = 52.0)
2744        w.extend_from_slice(&0_u16.to_be_bytes()); // minor
2745        w.extend_from_slice(&52_u16.to_be_bytes()); // major
2746
2747        // Constant Pool (Count: 5)
2748        // 1: UTF8 "TestClass"
2749        // 2: Class #1
2750        // 3: UTF8 "java/lang/Object"
2751        // 4: Class #3
2752        w.extend_from_slice(&5_u16.to_be_bytes()); // Count (N+1)
2753
2754        // #1 UTF8
2755        w.push(1);
2756        let name = "TestClass";
2757        w.extend_from_slice(&(name.len() as u16).to_be_bytes());
2758        w.extend_from_slice(name.as_bytes());
2759
2760        // #2 Class
2761        w.push(7);
2762        w.extend_from_slice(&1_u16.to_be_bytes());
2763
2764        // #3 UTF8
2765        w.push(1);
2766        let obj = "java/lang/Object";
2767        w.extend_from_slice(&(obj.len() as u16).to_be_bytes());
2768        w.extend_from_slice(obj.as_bytes());
2769
2770        // #4 Class
2771        w.push(7);
2772        w.extend_from_slice(&3_u16.to_be_bytes());
2773
2774        // Access Flags (PUBLIC)
2775        w.extend_from_slice(&0x0021_u16.to_be_bytes());
2776        // This Class (#2)
2777        w.extend_from_slice(&2_u16.to_be_bytes());
2778        // Super Class (#4)
2779        w.extend_from_slice(&4_u16.to_be_bytes());
2780
2781        // Interfaces Count
2782        w.extend_from_slice(&0_u16.to_be_bytes());
2783        // Fields Count
2784        w.extend_from_slice(&0_u16.to_be_bytes());
2785        // Methods Count
2786        w.extend_from_slice(&0_u16.to_be_bytes());
2787        // Attributes Count
2788        w.extend_from_slice(&0_u16.to_be_bytes());
2789
2790        w
2791    }
2792
2793    fn generate_module_info_class() -> Vec<u8> {
2794        let mut writer = ClassWriter::new(0);
2795        writer.visit(V9, 0, ACC_MODULE, "module-info", None, &[]);
2796
2797        let mut module = writer.visit_module("com.example.app", ACC_OPEN, Some("1.0"));
2798        module.visit_main_class("com/example/app/Main");
2799        module.visit_package("com/example/api");
2800        module.visit_package("com/example/internal");
2801        module.visit_require("java.base", ACC_MANDATED, None);
2802        module.visit_require(
2803            "com.example.lib",
2804            ACC_TRANSITIVE | ACC_STATIC_PHASE,
2805            Some("2.1"),
2806        );
2807        module.visit_export("com/example/api", 0, &["com.example.consumer"]);
2808        module.visit_open("com/example/internal", 0, &["com.example.runtime"]);
2809        module.visit_use("com/example/spi/Service");
2810        module.visit_provide("com/example/spi/Service", &["com/example/impl/ServiceImpl"]);
2811        module.visit_end(&mut writer);
2812
2813        writer.to_bytes().expect("module-info should encode")
2814    }
2815
2816    #[test]
2817    fn test_class_reader_header() {
2818        let bytes = generate_minimal_class();
2819        let reader = ClassReader::new(&bytes);
2820        let mut visitor = MockClassVisitor::new();
2821
2822        let result = reader.accept(&mut visitor, 0);
2823
2824        assert!(result.is_ok(), "Should parse valid class file");
2825        assert_eq!(
2826            *visitor.visited_name.borrow(),
2827            Some("TestClass".to_string())
2828        );
2829    }
2830
2831    #[test]
2832    fn test_invalid_magic() {
2833        // expected CA FE BA BE
2834        let bytes = vec![0x00, 0x00, 0x00, 0x00];
2835        let reader = ClassReader::new(&bytes);
2836        let mut visitor = MockClassVisitor::new();
2837
2838        let result = reader.accept(&mut visitor, 0);
2839        assert!(matches!(result, Err(ClassReadError::InvalidMagic(_))));
2840    }
2841
2842    #[test]
2843    fn test_code_reader_alignment() {
2844        // Test internal alignment logic for switch instructions
2845        let data = vec![0x00, 0x00, 0x00, 0x00]; // 4 bytes
2846        let mut reader = super::ByteReader::new(&data);
2847
2848        // If we are at pos 1, padding to 4-byte boundary
2849        reader.pos = 1;
2850        // 1 -> align 4 -> skips 3 bytes -> pos 4
2851        assert!(reader.align4(0).is_ok());
2852        assert_eq!(reader.pos(), 4);
2853    }
2854
2855    #[test]
2856    fn test_parse_runtime_visible_type_annotations_supertype() {
2857        // RuntimeVisibleTypeAnnotations:
2858        // u2 num_annotations = 1
2859        // type_annotation:
2860        //   u1 target_type = TA_TARGET_CLASS_EXTENDS
2861        //   u2 supertype_index = 5
2862        //   type_path: u1 path_len=0
2863        //   annotation:
2864        //     u2 type_descriptor_index=10
2865        //     u2 num_pairs=0
2866        let mut info = vec![];
2867        u2(1, &mut info);
2868        u1(TA_TARGET_CLASS_EXTENDS, &mut info);
2869        u2(5, &mut info);
2870        u1(0, &mut info);
2871        u2(10, &mut info);
2872        u2(0, &mut info);
2873
2874        let cp: Vec<CpInfo> = vec![];
2875        let attr = parse_attribute("RuntimeVisibleTypeAnnotations", info, &cp).unwrap();
2876
2877        match attr {
2878            AttributeInfo::RuntimeVisibleTypeAnnotations { annotations } => {
2879                assert_eq!(annotations.len(), 1);
2880                let a = &annotations[0];
2881                assert_eq!(a.target_type, TA_TARGET_CLASS_EXTENDS);
2882                assert!(matches!(
2883                    a.target_info,
2884                    TypeAnnotationTargetInfo::Supertype { supertype_index: 5 }
2885                ));
2886                assert_eq!(a.target_path.path.len(), 0);
2887                assert_eq!(a.annotation.type_descriptor_index, 10);
2888                assert_eq!(a.annotation.element_value_pairs.len(), 0);
2889            }
2890            other => panic!("unexpected attr: {:?}", other),
2891        }
2892    }
2893
2894    #[test]
2895    fn test_parse_runtime_visible_type_annotations_formal_parameter_with_path() {
2896        // target_type = TA_TARGET_METHOD_FORMAL_PARAMETER
2897        // u1 formal_parameter_index = 2
2898        // type_path len=1 entry(kind=TA_TYPE_PATH_ARRAY, arg_index=0)
2899        // annotation: type_index=9, num_pairs=0
2900        let mut info = vec![];
2901        u2(1, &mut info);
2902        u1(TA_TARGET_METHOD_FORMAL_PARAMETER, &mut info);
2903        u1(2, &mut info);
2904
2905        u1(1, &mut info); // path_length
2906        u1(TA_TYPE_PATH_ARRAY, &mut info);
2907        u1(0, &mut info);
2908
2909        u2(9, &mut info);
2910        u2(0, &mut info);
2911
2912        let cp: Vec<CpInfo> = vec![];
2913        let attr = parse_attribute("RuntimeVisibleTypeAnnotations", info, &cp).unwrap();
2914
2915        match attr {
2916            AttributeInfo::RuntimeVisibleTypeAnnotations { annotations } => {
2917                let a = &annotations[0];
2918                assert_eq!(a.target_type, TA_TARGET_METHOD_FORMAL_PARAMETER);
2919                assert!(matches!(
2920                    a.target_info,
2921                    TypeAnnotationTargetInfo::FormalParameter {
2922                        formal_parameter_index: 2
2923                    }
2924                ));
2925                assert_eq!(a.target_path.path.len(), 1);
2926                assert_eq!(a.target_path.path[0].type_path_kind, TA_TYPE_PATH_ARRAY);
2927                assert_eq!(a.target_path.path[0].type_argument_index, 0);
2928            }
2929            other => panic!("unexpected attr: {:?}", other),
2930        }
2931    }
2932
2933    #[test]
2934    fn test_parse_runtime_visible_type_annotations_localvar_table() {
2935        // target_type = TA_TARGET_LOCAL_VARIABLE
2936        // u2 table_length = 1
2937        // entry: start_pc=1 length=2 index=3
2938        // type_path len=0
2939        // annotation: type_index=8, num_pairs=0
2940        let mut info = vec![];
2941        u2(1, &mut info);
2942        u1(TA_TARGET_LOCAL_VARIABLE, &mut info);
2943
2944        u2(1, &mut info); // table_length
2945        u2(1, &mut info);
2946        u2(2, &mut info);
2947        u2(3, &mut info);
2948
2949        u1(0, &mut info); // path_length
2950        u2(8, &mut info);
2951        u2(0, &mut info);
2952
2953        let cp: Vec<CpInfo> = vec![];
2954        let attr = parse_attribute("RuntimeVisibleTypeAnnotations", info, &cp).unwrap();
2955
2956        match attr {
2957            AttributeInfo::RuntimeVisibleTypeAnnotations { annotations } => {
2958                let a = &annotations[0];
2959                assert_eq!(a.target_type, TA_TARGET_LOCAL_VARIABLE);
2960                match &a.target_info {
2961                    TypeAnnotationTargetInfo::LocalVar { table } => {
2962                        assert_eq!(table.len(), 1);
2963                        assert_eq!(table[0].start_pc, 1);
2964                        assert_eq!(table[0].length, 2);
2965                        assert_eq!(table[0].index, 3);
2966                    }
2967                    other => panic!("unexpected target_info: {:?}", other),
2968                }
2969            }
2970            other => panic!("unexpected attr: {:?}", other),
2971        }
2972    }
2973
2974    #[test]
2975    fn test_parse_module_attribute_family() {
2976        let mut module_info = vec![];
2977        u2(1, &mut module_info);
2978        u2(ACC_OPEN, &mut module_info);
2979        u2(2, &mut module_info);
2980        u2(1, &mut module_info);
2981        u2(3, &mut module_info);
2982        u2(ACC_TRANSITIVE | ACC_STATIC_PHASE, &mut module_info);
2983        u2(4, &mut module_info);
2984        u2(1, &mut module_info);
2985        u2(5, &mut module_info);
2986        u2(ACC_MANDATED, &mut module_info);
2987        u2(2, &mut module_info);
2988        u2(6, &mut module_info);
2989        u2(7, &mut module_info);
2990        u2(1, &mut module_info);
2991        u2(8, &mut module_info);
2992        u2(0, &mut module_info);
2993        u2(1, &mut module_info);
2994        u2(9, &mut module_info);
2995        u2(1, &mut module_info);
2996        u2(10, &mut module_info);
2997        u2(1, &mut module_info);
2998        u2(11, &mut module_info);
2999        u2(2, &mut module_info);
3000        u2(12, &mut module_info);
3001        u2(13, &mut module_info);
3002
3003        let attr = parse_attribute("Module", module_info, &[]).expect("module attr should parse");
3004        match attr {
3005            AttributeInfo::Module(module) => {
3006                assert_eq!(module.module_name_index, 1);
3007                assert_eq!(module.module_flags, ACC_OPEN);
3008                assert_eq!(module.module_version_index, 2);
3009                assert_eq!(
3010                    module.requires,
3011                    vec![ModuleRequire {
3012                        requires_index: 3,
3013                        requires_flags: ACC_TRANSITIVE | ACC_STATIC_PHASE,
3014                        requires_version_index: 4,
3015                    }]
3016                );
3017                assert_eq!(
3018                    module.exports,
3019                    vec![ModuleExport {
3020                        exports_index: 5,
3021                        exports_flags: ACC_MANDATED,
3022                        exports_to_index: vec![6, 7],
3023                    }]
3024                );
3025                assert_eq!(
3026                    module.opens,
3027                    vec![ModuleOpen {
3028                        opens_index: 8,
3029                        opens_flags: 0,
3030                        opens_to_index: vec![9],
3031                    }]
3032                );
3033                assert_eq!(module.uses_index, vec![10]);
3034                assert_eq!(
3035                    module.provides,
3036                    vec![ModuleProvide {
3037                        provides_index: 11,
3038                        provides_with_index: vec![12, 13],
3039                    }]
3040                );
3041            }
3042            other => panic!("unexpected attr: {:?}", other),
3043        }
3044
3045        let mut packages_info = vec![];
3046        u2(2, &mut packages_info);
3047        u2(21, &mut packages_info);
3048        u2(22, &mut packages_info);
3049        let attr = parse_attribute("ModulePackages", packages_info, &[])
3050            .expect("module packages attr should parse");
3051        match attr {
3052            AttributeInfo::ModulePackages {
3053                package_index_table,
3054            } => {
3055                assert_eq!(package_index_table, vec![21, 22]);
3056            }
3057            other => panic!("unexpected attr: {:?}", other),
3058        }
3059
3060        let mut main_class_info = vec![];
3061        u2(23, &mut main_class_info);
3062        let attr = parse_attribute("ModuleMainClass", main_class_info, &[])
3063            .expect("module main class attr should parse");
3064        match attr {
3065            AttributeInfo::ModuleMainClass { main_class_index } => {
3066                assert_eq!(main_class_index, 23);
3067            }
3068            other => panic!("unexpected attr: {:?}", other),
3069        }
3070    }
3071
3072    fn u1(v: u8, out: &mut Vec<u8>) {
3073        out.push(v);
3074    }
3075    fn u2(v: u16, out: &mut Vec<u8>) {
3076        out.extend_from_slice(&v.to_be_bytes());
3077    }
3078
3079    #[test]
3080    fn test_method_node_contains_offsets_and_line_numbers() {
3081        let mut writer = ClassWriter::new(0);
3082        writer.visit(
3083            52,
3084            0,
3085            ACC_PUBLIC,
3086            "TestNodeData",
3087            Some("java/lang/Object"),
3088            &[],
3089        );
3090
3091        let mut ctor = writer.visit_method(ACC_PUBLIC, "<init>", "()V");
3092        ctor.visit_code();
3093        ctor.visit_var_insn(opcodes::ALOAD, 0);
3094        ctor.visit_method_insn(
3095            opcodes::INVOKESPECIAL,
3096            "java/lang/Object",
3097            "<init>",
3098            "()V",
3099            false,
3100        );
3101        ctor.visit_insn(opcodes::RETURN);
3102        ctor.visit_maxs(1, 1);
3103        ctor.visit_end(&mut writer);
3104
3105        let mut method = writer.visit_method(ACC_PUBLIC | ACC_STATIC, "answer", "()I");
3106        let start = Label::new();
3107        method.visit_code();
3108        method.visit_label(start);
3109        method.visit_line_number(123, LabelNode::from_label(start));
3110        method.visit_insn(opcodes::ICONST_1);
3111        method.visit_insn(opcodes::IRETURN);
3112        method.visit_maxs(1, 0);
3113        method.visit_end(&mut writer);
3114
3115        let bytes = writer.to_bytes().expect("class should encode");
3116        let class = ClassReader::new(&bytes)
3117            .to_class_node()
3118            .expect("class should decode");
3119        let method = class
3120            .methods
3121            .iter()
3122            .find(|method| method.name == "answer")
3123            .expect("method should exist");
3124
3125        assert_eq!(method.instruction_offsets, vec![0, 1]);
3126        assert_eq!(method.line_numbers.len(), 1);
3127        assert_eq!(method.line_numbers[0].line_number, 123);
3128        assert!(
3129            method
3130                .insn_nodes
3131                .iter()
3132                .any(|node| matches!(node, AbstractInsnNode::LineNumber(_)))
3133        );
3134        assert!(
3135            method
3136                .insn_nodes
3137                .iter()
3138                .any(|node| matches!(node, AbstractInsnNode::Label(_)))
3139        );
3140        assert!(method.try_catch_blocks.is_empty());
3141    }
3142
3143    #[test]
3144    fn test_method_node_contains_try_catch_blocks() {
3145        let mut writer = ClassWriter::new(0);
3146        writer.visit(
3147            52,
3148            0,
3149            ACC_PUBLIC,
3150            "TestTryCatchNode",
3151            Some("java/lang/Object"),
3152            &[],
3153        );
3154
3155        let mut ctor = writer.visit_method(ACC_PUBLIC, "<init>", "()V");
3156        ctor.visit_code();
3157        ctor.visit_var_insn(opcodes::ALOAD, 0);
3158        ctor.visit_method_insn(
3159            opcodes::INVOKESPECIAL,
3160            "java/lang/Object",
3161            "<init>",
3162            "()V",
3163            false,
3164        );
3165        ctor.visit_insn(opcodes::RETURN);
3166        ctor.visit_maxs(1, 1);
3167        ctor.visit_end(&mut writer);
3168
3169        let start = Label::new();
3170        let end = Label::new();
3171        let handler = Label::new();
3172        let mut method =
3173            writer.visit_method(ACC_PUBLIC | ACC_STATIC, "safeLen", "(Ljava/lang/String;)I");
3174        method.visit_code();
3175        method.visit_label(start);
3176        method.visit_var_insn(opcodes::ALOAD, 0);
3177        method.visit_method_insn(
3178            opcodes::INVOKEVIRTUAL,
3179            "java/lang/String",
3180            "length",
3181            "()I",
3182            false,
3183        );
3184        method.visit_insn(opcodes::IRETURN);
3185        method.visit_label(end);
3186        method.visit_label(handler);
3187        method.visit_var_insn(opcodes::ASTORE, 1);
3188        method.visit_insn(opcodes::ICONST_M1);
3189        method.visit_insn(opcodes::IRETURN);
3190        method.visit_try_catch_block(start, end, handler, Some("java/lang/RuntimeException"));
3191        method.visit_maxs(1, 2);
3192        method.visit_end(&mut writer);
3193
3194        let bytes = writer.to_bytes().expect("class should encode");
3195        let class = ClassReader::new(&bytes)
3196            .to_class_node()
3197            .expect("class should decode");
3198        let method = class
3199            .methods
3200            .iter()
3201            .find(|method| method.name == "safeLen")
3202            .expect("method should exist");
3203
3204        assert_eq!(method.exception_table.len(), 1);
3205        assert_eq!(method.try_catch_blocks.len(), 1);
3206        assert_eq!(
3207            method.try_catch_blocks[0].catch_type.as_deref(),
3208            Some("java/lang/RuntimeException")
3209        );
3210    }
3211
3212    #[test]
3213    fn test_parse_runtime_visible_annotations_one_empty() {
3214        // u2 num_annotations=1
3215        // annotation: type=10, pairs=0
3216        let mut info = vec![];
3217        u2(1, &mut info);
3218        u2(10, &mut info);
3219        u2(0, &mut info);
3220
3221        let cp: Vec<CpInfo> = vec![];
3222        let attr = parse_attribute("RuntimeVisibleAnnotations", info, &cp).unwrap();
3223        match attr {
3224            AttributeInfo::RuntimeVisibleAnnotations { annotations } => {
3225                assert_eq!(annotations.len(), 1);
3226                assert_eq!(annotations[0].type_descriptor_index, 10);
3227                assert_eq!(annotations[0].element_value_pairs.len(), 0);
3228            }
3229            other => panic!("unexpected attr: {:?}", other),
3230        }
3231    }
3232
3233    #[test]
3234    fn test_parse_runtime_visible_parameter_annotations_two_params() {
3235        // u1 num_params=2
3236        // p0: u2 num_ann=1, annotation(type=10,pairs=0)
3237        // p1: u2 num_ann=0
3238        let mut info = vec![];
3239        u1(2, &mut info);
3240        u2(1, &mut info);
3241        u2(10, &mut info);
3242        u2(0, &mut info);
3243        u2(0, &mut info);
3244
3245        let cp: Vec<CpInfo> = vec![];
3246        let attr = parse_attribute("RuntimeVisibleParameterAnnotations", info, &cp).unwrap();
3247        match attr {
3248            AttributeInfo::RuntimeVisibleParameterAnnotations { parameters } => {
3249                assert_eq!(parameters.parameters.len(), 2);
3250                assert_eq!(parameters.parameters[0].len(), 1);
3251                assert_eq!(parameters.parameters[1].len(), 0);
3252            }
3253            other => panic!("unexpected attr: {:?}", other),
3254        }
3255    }
3256
3257    #[test]
3258    fn test_class_reader_decodes_module_info_node() {
3259        let bytes = generate_module_info_class();
3260        let class = ClassReader::new(&bytes)
3261            .to_class_node()
3262            .expect("module-info should decode");
3263
3264        assert_eq!(class.name, "module-info");
3265        assert_eq!(class.access_flags, ACC_MODULE);
3266
3267        let module = class.module.expect("module descriptor should be decoded");
3268        assert_eq!(module.name, "com.example.app");
3269        assert_eq!(module.access_flags, ACC_OPEN);
3270        assert_eq!(module.version.as_deref(), Some("1.0"));
3271        assert_eq!(module.main_class.as_deref(), Some("com/example/app/Main"));
3272        assert_eq!(
3273            module.packages,
3274            vec![
3275                "com/example/api".to_string(),
3276                "com/example/internal".to_string()
3277            ]
3278        );
3279        assert_eq!(module.requires.len(), 2);
3280        assert_eq!(module.requires[0].module, "java.base");
3281        assert_eq!(module.requires[0].access_flags, ACC_MANDATED);
3282        assert_eq!(module.requires[0].version, None);
3283        assert_eq!(module.requires[1].module, "com.example.lib");
3284        assert_eq!(
3285            module.requires[1].access_flags,
3286            ACC_TRANSITIVE | ACC_STATIC_PHASE
3287        );
3288        assert_eq!(module.requires[1].version.as_deref(), Some("2.1"));
3289        assert_eq!(module.exports.len(), 1);
3290        assert_eq!(module.exports[0].package, "com/example/api");
3291        assert_eq!(
3292            module.exports[0].modules,
3293            vec!["com.example.consumer".to_string()]
3294        );
3295        assert_eq!(module.opens.len(), 1);
3296        assert_eq!(module.opens[0].package, "com/example/internal");
3297        assert_eq!(
3298            module.opens[0].modules,
3299            vec!["com.example.runtime".to_string()]
3300        );
3301        assert_eq!(module.uses, vec!["com/example/spi/Service".to_string()]);
3302        assert_eq!(module.provides.len(), 1);
3303        assert_eq!(module.provides[0].service, "com/example/spi/Service");
3304        assert_eq!(
3305            module.provides[0].providers,
3306            vec!["com/example/impl/ServiceImpl".to_string()]
3307        );
3308    }
3309}