Refactored Attributes to be a struct

because why not
This commit is contained in:
nora 2021-08-20 16:14:26 +02:00
parent 5dcee9db57
commit 3546a5b268
2 changed files with 178 additions and 170 deletions

View file

@ -245,10 +245,12 @@ impl Parse for MethodInfo {
impl Parse for AttributeInfo {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self::Unknown {
Ok(Self {
attribute_name_index: data.u2()?,
attribute_length: data.u4()?,
attribute_content: parse_vec(data, data.last_u4()? as usize)?,
inner: AttributeInfoInner::Unknown {
attribute_content: parse_vec(data, data.last_u4()? as usize)?,
},
})
}
}
@ -456,13 +458,20 @@ fn resolve_attributes(class: &mut ClassFile) -> Result<()> {
impl AttributeInfo {
fn resolve_attribute(&mut self, pool: &[CpInfo]) -> Result<()> {
// this is a borrow checker hack, but it works :(
let attr = std::mem::replace(self, AttributeInfo::__Empty);
let attr = std::mem::replace(
self,
AttributeInfo {
attribute_name_index: 0,
attribute_length: 0,
inner: AttributeInfoInner::__Empty,
},
);
let (&index, &len, content) = match &attr {
AttributeInfo::Unknown {
AttributeInfo {
attribute_name_index,
attribute_length,
attribute_content,
inner: AttributeInfoInner::Unknown { attribute_content },
} => (attribute_name_index, attribute_length, attribute_content),
_ => unreachable!("Attribute already resolved"),
};
@ -486,127 +495,163 @@ impl AttributeInfo {
let _ = std::mem::replace(
self,
match name {
"ConstantValue" => Self::ConstantValue {
"ConstantValue" => Self {
attribute_name_index,
attribute_length,
constantvalue_index: data.u2()?,
},
"Code" => Self::Code {
attribute_name_index,
attribute_length,
max_stack: data.u2()?,
max_locals: data.u2()?,
code_length: data.u4()?,
code: parse_vec(data, data.last_u4()? as usize)?,
exception_table_length: data.u2()?,
exception_table: parse_vec(data, data.last_u2()?)?,
attributes_count: data.u2()?,
attributes: parse_vec(data, data.last_u2()?)?,
},
"StackMapTable" => Self::StackMapTable {
attribute_name_index,
attribute_length,
number_of_entries: data.u2()?,
entries: parse_vec(data, data.last_u2()?)?,
},
"Exceptions" => Self::Exceptions {
attribute_name_index,
attribute_length,
number_of_exceptions: data.u2()?,
exception_index_table: parse_vec(data, data.last_u2()?)?,
},
"InnerClasses" => Self::InnerClasses {
attribute_name_index,
attribute_length,
number_of_classes: data.u2()?,
classes: parse_vec(data, data.last_u2()?)?,
},
"EnclosingMethod" => Self::EnclosingMethod {
attribute_name_index,
attribute_length,
class_index: data.u2()?,
method_index: data.u2()?,
},
"Synthetic" => Self::Synthetic {
attribute_name_index,
attribute_length,
},
"Signature" => Self::Signature {
attribute_name_index,
attribute_length,
signature_index: data.u2()?,
},
"SourceFile" => Self::SourceFile {
attribute_name_index,
attribute_length,
sourcefile_index: data.u2()?,
},
"SourceDebugExtension" => Self::SourceDebugExtension {
attribute_name_index,
attribute_length,
debug_extension: parse_vec(data, data.last_u2()?)?,
},
"LineNumberTable" => Self::LineNumberTable {
attribute_name_index,
attribute_length,
line_number_table_length: data.u2()?,
line_number_table: parse_vec(data, data.last_u2()?)?,
},
"LocalVariableTable" => Self::LocalVariableTable {
attribute_name_index,
attribute_length,
local_variable_table_length: data.u2()?,
local_variable_table: parse_vec(data, data.last_u2()?)?,
},
"LocalVariableTypeTable" => Self::LocalVariableTypeTable {
attribute_name_index,
attribute_length,
local_variable_table_length: data.u2()?,
local_variable_table: parse_vec(data, data.last_u2()?)?,
},
"Deprecated" => Self::Deprecated {
attribute_name_index,
attribute_length,
},
"RuntimeVisibleAnnotations" => Self::RuntimeVisibleAnnotations {
attribute_name_index,
attribute_length,
num_annotations: data.u2()?,
annotations: parse_vec(data, data.last_u2()?)?,
},
"RuntimeInvisibleAnnotations" => Self::RuntimeInvisibleAnnotations {
attribute_name_index,
attribute_length,
num_annotations: data.u2()?,
annotations: parse_vec(data, data.last_u2()?)?,
},
"RuntimeVisibleParameterAnnotations" => Self::RuntimeVisibleParameterAnnotations {
attribute_name_index,
attribute_length,
num_parameters: data.u1()?,
parameter_annotations: parse_vec(data, data.last_u1()?)?,
},
"RuntimeInvisibleParameterAnnotations" => {
Self::RuntimeInvisibleParameterAnnotations {
attribute_name_index,
attribute_length,
num_parameters: data.u1()?,
parameter_annotations: parse_vec(data, data.last_u1()?)?,
}
}
"AnnotationDefault" => Self::AnnotationDefault {
attribute_name_index,
attribute_length,
default_value: AnnotationElementValue {
tag: data.u1()?,
value: AnnotationElementValueValue::parse(data)?,
inner: AttributeInfoInner::ConstantValue {
constantvalue_index: data.u2()?,
},
},
"BootstrapMethods" => Self::BootstrapMethods {
"Code" => Self {
attribute_name_index,
attribute_length,
num_bootstrap_methods: data.u2()?,
bootstrap_methods: parse_vec(data, data.last_u2()?)?,
inner: AttributeInfoInner::Code {
max_stack: data.u2()?,
max_locals: data.u2()?,
code_length: data.u4()?,
code: parse_vec(data, data.last_u4()? as usize)?,
exception_table_length: data.u2()?,
exception_table: parse_vec(data, data.last_u2()?)?,
attributes_count: data.u2()?,
attributes: parse_vec(data, data.last_u2()?)?,
},
},
"StackMapTable" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::StackMapTable {
number_of_entries: data.u2()?,
entries: parse_vec(data, data.last_u2()?)?,
},
},
"Exceptions" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::Exceptions {
number_of_exceptions: data.u2()?,
exception_index_table: parse_vec(data, data.last_u2()?)?,
},
},
"InnerClasses" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::InnerClasses {
number_of_classes: data.u2()?,
classes: parse_vec(data, data.last_u2()?)?,
},
},
"EnclosingMethod" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::EnclosingMethod {
class_index: data.u2()?,
method_index: data.u2()?,
},
},
"Synthetic" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::Synthetic,
},
"Signature" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::Signature {
signature_index: data.u2()?,
},
},
"SourceFile" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::SourceFile {
sourcefile_index: data.u2()?,
},
},
"SourceDebugExtension" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::SourceDebugExtension {
debug_extension: parse_vec(data, data.last_u2()?)?,
},
},
"LineNumberTable" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::LineNumberTable {
line_number_table_length: data.u2()?,
line_number_table: parse_vec(data, data.last_u2()?)?,
},
},
"LocalVariableTable" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::LocalVariableTable {
local_variable_table_length: data.u2()?,
local_variable_table: parse_vec(data, data.last_u2()?)?,
},
},
"LocalVariableTypeTable" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::LocalVariableTypeTable {
local_variable_table_length: data.u2()?,
local_variable_table: parse_vec(data, data.last_u2()?)?,
},
},
"Deprecated" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::Deprecated,
},
"RuntimeVisibleAnnotations" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::RuntimeVisibleAnnotations {
num_annotations: data.u2()?,
annotations: parse_vec(data, data.last_u2()?)?,
},
},
"RuntimeInvisibleAnnotations" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::RuntimeInvisibleAnnotations {
num_annotations: data.u2()?,
annotations: parse_vec(data, data.last_u2()?)?,
},
},
"RuntimeVisibleParameterAnnotations" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::RuntimeVisibleParameterAnnotations {
num_parameters: data.u1()?,
parameter_annotations: parse_vec(data, data.last_u1()?)?,
},
},
"RuntimeInvisibleParameterAnnotations" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::RuntimeInvisibleParameterAnnotations {
num_parameters: data.u1()?,
parameter_annotations: parse_vec(data, data.last_u1()?)?,
},
},
"AnnotationDefault" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::AnnotationDefault {
default_value: AnnotationElementValue {
tag: data.u1()?,
value: AnnotationElementValueValue::parse(data)?,
},
},
},
"BootstrapMethods" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::BootstrapMethods {
num_bootstrap_methods: data.u2()?,
bootstrap_methods: parse_vec(data, data.last_u2()?)?,
},
},
name => return Err(ParseErr(format!("Invalid Attribute name: {}", name))),
},

View file

@ -182,26 +182,28 @@ pub struct MethodInfo {
///
/// _index: Index to the `constant_pool` table of any type
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
// todo refactor this into a struct + enum
pub enum AttributeInfo {
pub struct AttributeInfo {
pub attribute_name_index: u2,
pub attribute_length: u4,
/// The attribute value
pub inner: AttributeInfoInner,
}
/// The Attributes, without the two common fields
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum AttributeInfoInner {
__Empty,
/// The exact kind of attribute is not known yet and will be resolved later in the process
Unknown {
attribute_name_index: u2,
attribute_length: u4,
attribute_content: Vec<u1>,
},
/// Only on fields, the constant value of that field
ConstantValue {
attribute_name_index: u2, // "ConstantValue"
attribute_length: u4,
/// Must be of type `Long`/`Float`/`Double`/`Integer`/`String`
constantvalue_index: u2,
},
/// Only on methods, contains JVM instructions and auxiliary information for a single method
Code {
attribute_name_index: u2,
attribute_length: u4,
/// The maximum depth of the operand stack for this method
max_stack: u2,
/// The number of the local variables array, including the parameters
@ -221,31 +223,22 @@ pub enum AttributeInfo {
/// Only on the `Code` attribute, used for verification
/// May be implicit on version >= 50.0, with no entries
StackMapTable {
/// Must be `Utf8`
attribute_name_index: u2,
attribute_length: u4,
number_of_entries: u2,
entries: Vec<StackMapFrame>,
},
/// Only on `MethodInfo`, indicates which checked exceptions might be thrown
Exceptions {
attribute_name_index: u2,
attribute_length: u4,
number_of_exceptions: u2,
/// Must be a `Class` constant
exception_index_table: Vec<u2>,
},
/// Only on a `ClassFile`. Specifies the inner classes of a class
InnerClasses {
attribute_name_index: u2,
attribute_length: u4,
number_of_classes: u2,
classes: Vec<AttributeInnerClass>,
},
/// Only on a `ClassFile`, required if it is local or anonymous
EnclosingMethod {
attribute_name_index: u2,
attribute_length: u4, // 4
/// Must be a `Class` constant, the innermost enclosing class
class_index: u2,
/// Must be zero or `NameAndType`
@ -253,97 +246,67 @@ pub enum AttributeInfo {
},
/// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`.
/// Every generated class has to have this attribute or the `Synthetic` Accessor modifier
Synthetic {
attribute_name_index: u2,
attribute_length: u4, // 0
},
Synthetic,
/// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Records generic signature information
Signature {
attribute_name_index: u2,
attribute_length: u4, // 2
/// Must be `Utf8`, and a Class/Method/Field signature
signature_index: u2,
},
/// Only on a `ClassFile`
SourceFile {
attribute_name_index: u2,
attribute_length: u4, // 2
/// Must be `Utf8`, the name of the source filed
sourcefile_index: u2,
},
/// Only on a `ClassFile`
SourceDebugExtension {
attribute_name_index: u2,
attribute_length: u4, // number of items in `debug_extension`
/// A modified UTF-8 of additional debugging information
/// A modified UTF-8 of additional debugging information, `attribute_length`: number of items in `debug_extension`
debug_extension: Vec<u1>,
},
/// Only on the `Code` attribute. It includes line number information used by debuggers
LineNumberTable {
attribute_name_index: u2,
attribute_length: u4,
line_number_table_length: u2,
line_number_table: Vec<AttributeLineNumber>,
},
/// Only on the `Code` attribute. It may be used to determine the value of local variables by debuggers
LocalVariableTable {
attribute_name_index: u2,
attribute_length: u4,
local_variable_table_length: u2,
/// Note: the 3rd field is called `descriptor_index` and represents an field descriptor
local_variable_table: Vec<AttributeLocalVariableTable>,
},
/// Only on the `Code` attribute. It provides signature information instead of descriptor information
LocalVariableTypeTable {
attribute_name_index: u2,
attribute_length: u4,
local_variable_table_length: u2,
/// Note: the 3rd field is called `signature_index` and represents a field type signature
local_variable_table: Vec<AttributeLocalVariableTable>,
},
/// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Marks a class/field/method as deprecated
Deprecated {
attribute_name_index: u2,
attribute_length: u4, // 0
},
Deprecated,
/// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Contains all Runtime visible annotations
RuntimeVisibleAnnotations {
attribute_name_index: u2,
attribute_length: u4,
num_annotations: u2,
annotations: Vec<Annotation>,
},
/// Same as `RuntimeVisibleAnnotations`, but invisible to reflection
RuntimeInvisibleAnnotations {
attribute_name_index: u2,
attribute_length: u4,
num_annotations: u2,
annotations: Vec<Annotation>,
},
/// Only on `MethodInfo`, parameter annotations visible during runtime
RuntimeVisibleParameterAnnotations {
attribute_name_index: u2,
attribute_length: u4,
num_parameters: u1,
parameter_annotations: Vec<ParameterAnnotation>,
},
/// Same as `RuntimeVisibleParameterAnnotations`, but invisible to reflection
RuntimeInvisibleParameterAnnotations {
attribute_name_index: u2,
attribute_length: u4,
num_parameters: u1,
parameter_annotations: Vec<ParameterAnnotation>,
},
/// Only on `MethodInfo`, on those representing elements of annotation types, the default value of the element
AnnotationDefault {
attribute_name_index: u2,
attribute_length: u4,
default_value: AnnotationElementValue,
},
/// Only on `ClassFile`. Records bootstrap method specifiers for `invokedynamic`
BootstrapMethods {
attribute_name_index: u2,
attribute_length: u4,
num_bootstrap_methods: u2,
bootstrap_methods: Vec<BootstrapMethod>,
},