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 { impl Parse for AttributeInfo {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data) -> Result<Self> {
Ok(Self::Unknown { Ok(Self {
attribute_name_index: data.u2()?, attribute_name_index: data.u2()?,
attribute_length: data.u4()?, attribute_length: data.u4()?,
inner: AttributeInfoInner::Unknown {
attribute_content: parse_vec(data, data.last_u4()? as usize)?, attribute_content: parse_vec(data, data.last_u4()? as usize)?,
},
}) })
} }
} }
@ -456,13 +458,20 @@ fn resolve_attributes(class: &mut ClassFile) -> Result<()> {
impl AttributeInfo { impl AttributeInfo {
fn resolve_attribute(&mut self, pool: &[CpInfo]) -> Result<()> { fn resolve_attribute(&mut self, pool: &[CpInfo]) -> Result<()> {
// this is a borrow checker hack, but it works :( // 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 { let (&index, &len, content) = match &attr {
AttributeInfo::Unknown { AttributeInfo {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
attribute_content, inner: AttributeInfoInner::Unknown { attribute_content },
} => (attribute_name_index, attribute_length, attribute_content), } => (attribute_name_index, attribute_length, attribute_content),
_ => unreachable!("Attribute already resolved"), _ => unreachable!("Attribute already resolved"),
}; };
@ -486,14 +495,17 @@ impl AttributeInfo {
let _ = std::mem::replace( let _ = std::mem::replace(
self, self,
match name { match name {
"ConstantValue" => Self::ConstantValue { "ConstantValue" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::ConstantValue {
constantvalue_index: data.u2()?, constantvalue_index: data.u2()?,
}, },
"Code" => Self::Code { },
"Code" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::Code {
max_stack: data.u2()?, max_stack: data.u2()?,
max_locals: data.u2()?, max_locals: data.u2()?,
code_length: data.u4()?, code_length: data.u4()?,
@ -503,111 +515,144 @@ impl AttributeInfo {
attributes_count: data.u2()?, attributes_count: data.u2()?,
attributes: parse_vec(data, data.last_u2()?)?, attributes: parse_vec(data, data.last_u2()?)?,
}, },
"StackMapTable" => Self::StackMapTable { },
"StackMapTable" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::StackMapTable {
number_of_entries: data.u2()?, number_of_entries: data.u2()?,
entries: parse_vec(data, data.last_u2()?)?, entries: parse_vec(data, data.last_u2()?)?,
}, },
"Exceptions" => Self::Exceptions { },
"Exceptions" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::Exceptions {
number_of_exceptions: data.u2()?, number_of_exceptions: data.u2()?,
exception_index_table: parse_vec(data, data.last_u2()?)?, exception_index_table: parse_vec(data, data.last_u2()?)?,
}, },
"InnerClasses" => Self::InnerClasses { },
"InnerClasses" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::InnerClasses {
number_of_classes: data.u2()?, number_of_classes: data.u2()?,
classes: parse_vec(data, data.last_u2()?)?, classes: parse_vec(data, data.last_u2()?)?,
}, },
"EnclosingMethod" => Self::EnclosingMethod { },
"EnclosingMethod" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::EnclosingMethod {
class_index: data.u2()?, class_index: data.u2()?,
method_index: data.u2()?, method_index: data.u2()?,
}, },
"Synthetic" => Self::Synthetic {
attribute_name_index,
attribute_length,
}, },
"Signature" => Self::Signature { "Synthetic" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::Synthetic,
},
"Signature" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::Signature {
signature_index: data.u2()?, signature_index: data.u2()?,
}, },
"SourceFile" => Self::SourceFile { },
"SourceFile" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::SourceFile {
sourcefile_index: data.u2()?, sourcefile_index: data.u2()?,
}, },
"SourceDebugExtension" => Self::SourceDebugExtension { },
"SourceDebugExtension" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::SourceDebugExtension {
debug_extension: parse_vec(data, data.last_u2()?)?, debug_extension: parse_vec(data, data.last_u2()?)?,
}, },
"LineNumberTable" => Self::LineNumberTable { },
"LineNumberTable" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::LineNumberTable {
line_number_table_length: data.u2()?, line_number_table_length: data.u2()?,
line_number_table: parse_vec(data, data.last_u2()?)?, line_number_table: parse_vec(data, data.last_u2()?)?,
}, },
"LocalVariableTable" => Self::LocalVariableTable { },
"LocalVariableTable" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::LocalVariableTable {
local_variable_table_length: data.u2()?, local_variable_table_length: data.u2()?,
local_variable_table: parse_vec(data, data.last_u2()?)?, local_variable_table: parse_vec(data, data.last_u2()?)?,
}, },
"LocalVariableTypeTable" => Self::LocalVariableTypeTable { },
"LocalVariableTypeTable" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::LocalVariableTypeTable {
local_variable_table_length: data.u2()?, local_variable_table_length: data.u2()?,
local_variable_table: parse_vec(data, data.last_u2()?)?, local_variable_table: parse_vec(data, data.last_u2()?)?,
}, },
"Deprecated" => Self::Deprecated {
attribute_name_index,
attribute_length,
}, },
"RuntimeVisibleAnnotations" => Self::RuntimeVisibleAnnotations { "Deprecated" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::Deprecated,
},
"RuntimeVisibleAnnotations" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::RuntimeVisibleAnnotations {
num_annotations: data.u2()?, num_annotations: data.u2()?,
annotations: parse_vec(data, data.last_u2()?)?, annotations: parse_vec(data, data.last_u2()?)?,
}, },
"RuntimeInvisibleAnnotations" => Self::RuntimeInvisibleAnnotations { },
"RuntimeInvisibleAnnotations" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::RuntimeInvisibleAnnotations {
num_annotations: data.u2()?, num_annotations: data.u2()?,
annotations: parse_vec(data, data.last_u2()?)?, annotations: parse_vec(data, data.last_u2()?)?,
}, },
"RuntimeVisibleParameterAnnotations" => Self::RuntimeVisibleParameterAnnotations { },
"RuntimeVisibleParameterAnnotations" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::RuntimeVisibleParameterAnnotations {
num_parameters: data.u1()?, num_parameters: data.u1()?,
parameter_annotations: parse_vec(data, data.last_u1()?)?, parameter_annotations: parse_vec(data, data.last_u1()?)?,
}, },
"RuntimeInvisibleParameterAnnotations" => { },
Self::RuntimeInvisibleParameterAnnotations { "RuntimeInvisibleParameterAnnotations" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::RuntimeInvisibleParameterAnnotations {
num_parameters: data.u1()?, num_parameters: data.u1()?,
parameter_annotations: parse_vec(data, data.last_u1()?)?, parameter_annotations: parse_vec(data, data.last_u1()?)?,
} },
} },
"AnnotationDefault" => Self::AnnotationDefault { "AnnotationDefault" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::AnnotationDefault {
default_value: AnnotationElementValue { default_value: AnnotationElementValue {
tag: data.u1()?, tag: data.u1()?,
value: AnnotationElementValueValue::parse(data)?, value: AnnotationElementValueValue::parse(data)?,
}, },
}, },
"BootstrapMethods" => Self::BootstrapMethods { },
"BootstrapMethods" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::BootstrapMethods {
num_bootstrap_methods: data.u2()?, num_bootstrap_methods: data.u2()?,
bootstrap_methods: parse_vec(data, data.last_u2()?)?, bootstrap_methods: parse_vec(data, data.last_u2()?)?,
}, },
},
name => return Err(ParseErr(format!("Invalid Attribute name: {}", name))), 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 /// _index: Index to the `constant_pool` table of any type
#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[derive(Debug, Clone, Hash, PartialEq, Eq)]
// todo refactor this into a struct + enum pub struct AttributeInfo {
pub enum 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, __Empty,
/// The exact kind of attribute is not known yet and will be resolved later in the process /// The exact kind of attribute is not known yet and will be resolved later in the process
Unknown { Unknown {
attribute_name_index: u2,
attribute_length: u4,
attribute_content: Vec<u1>, attribute_content: Vec<u1>,
}, },
/// Only on fields, the constant value of that field /// Only on fields, the constant value of that field
ConstantValue { ConstantValue {
attribute_name_index: u2, // "ConstantValue"
attribute_length: u4,
/// Must be of type `Long`/`Float`/`Double`/`Integer`/`String` /// Must be of type `Long`/`Float`/`Double`/`Integer`/`String`
constantvalue_index: u2, constantvalue_index: u2,
}, },
/// Only on methods, contains JVM instructions and auxiliary information for a single method /// Only on methods, contains JVM instructions and auxiliary information for a single method
Code { Code {
attribute_name_index: u2,
attribute_length: u4,
/// The maximum depth of the operand stack for this method /// The maximum depth of the operand stack for this method
max_stack: u2, max_stack: u2,
/// The number of the local variables array, including the parameters /// 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 /// Only on the `Code` attribute, used for verification
/// May be implicit on version >= 50.0, with no entries /// May be implicit on version >= 50.0, with no entries
StackMapTable { StackMapTable {
/// Must be `Utf8`
attribute_name_index: u2,
attribute_length: u4,
number_of_entries: u2, number_of_entries: u2,
entries: Vec<StackMapFrame>, entries: Vec<StackMapFrame>,
}, },
/// Only on `MethodInfo`, indicates which checked exceptions might be thrown /// Only on `MethodInfo`, indicates which checked exceptions might be thrown
Exceptions { Exceptions {
attribute_name_index: u2,
attribute_length: u4,
number_of_exceptions: u2, number_of_exceptions: u2,
/// Must be a `Class` constant /// Must be a `Class` constant
exception_index_table: Vec<u2>, exception_index_table: Vec<u2>,
}, },
/// Only on a `ClassFile`. Specifies the inner classes of a class /// Only on a `ClassFile`. Specifies the inner classes of a class
InnerClasses { InnerClasses {
attribute_name_index: u2,
attribute_length: u4,
number_of_classes: u2, number_of_classes: u2,
classes: Vec<AttributeInnerClass>, classes: Vec<AttributeInnerClass>,
}, },
/// Only on a `ClassFile`, required if it is local or anonymous /// Only on a `ClassFile`, required if it is local or anonymous
EnclosingMethod { EnclosingMethod {
attribute_name_index: u2,
attribute_length: u4, // 4
/// Must be a `Class` constant, the innermost enclosing class /// Must be a `Class` constant, the innermost enclosing class
class_index: u2, class_index: u2,
/// Must be zero or `NameAndType` /// Must be zero or `NameAndType`
@ -253,97 +246,67 @@ pub enum AttributeInfo {
}, },
/// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. /// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`.
/// Every generated class has to have this attribute or the `Synthetic` Accessor modifier /// Every generated class has to have this attribute or the `Synthetic` Accessor modifier
Synthetic { Synthetic,
attribute_name_index: u2,
attribute_length: u4, // 0
},
/// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Records generic signature information /// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Records generic signature information
Signature { Signature {
attribute_name_index: u2,
attribute_length: u4, // 2
/// Must be `Utf8`, and a Class/Method/Field signature /// Must be `Utf8`, and a Class/Method/Field signature
signature_index: u2, signature_index: u2,
}, },
/// Only on a `ClassFile` /// Only on a `ClassFile`
SourceFile { SourceFile {
attribute_name_index: u2,
attribute_length: u4, // 2
/// Must be `Utf8`, the name of the source filed /// Must be `Utf8`, the name of the source filed
sourcefile_index: u2, sourcefile_index: u2,
}, },
/// Only on a `ClassFile` /// Only on a `ClassFile`
SourceDebugExtension { SourceDebugExtension {
attribute_name_index: u2, /// A modified UTF-8 of additional debugging information, `attribute_length`: number of items in `debug_extension`
attribute_length: u4, // number of items in `debug_extension`
/// A modified UTF-8 of additional debugging information
debug_extension: Vec<u1>, debug_extension: Vec<u1>,
}, },
/// Only on the `Code` attribute. It includes line number information used by debuggers /// Only on the `Code` attribute. It includes line number information used by debuggers
LineNumberTable { LineNumberTable {
attribute_name_index: u2,
attribute_length: u4,
line_number_table_length: u2, line_number_table_length: u2,
line_number_table: Vec<AttributeLineNumber>, line_number_table: Vec<AttributeLineNumber>,
}, },
/// Only on the `Code` attribute. It may be used to determine the value of local variables by debuggers /// Only on the `Code` attribute. It may be used to determine the value of local variables by debuggers
LocalVariableTable { LocalVariableTable {
attribute_name_index: u2,
attribute_length: u4,
local_variable_table_length: u2, local_variable_table_length: u2,
/// Note: the 3rd field is called `descriptor_index` and represents an field descriptor /// Note: the 3rd field is called `descriptor_index` and represents an field descriptor
local_variable_table: Vec<AttributeLocalVariableTable>, local_variable_table: Vec<AttributeLocalVariableTable>,
}, },
/// Only on the `Code` attribute. It provides signature information instead of descriptor information /// Only on the `Code` attribute. It provides signature information instead of descriptor information
LocalVariableTypeTable { LocalVariableTypeTable {
attribute_name_index: u2,
attribute_length: u4,
local_variable_table_length: u2, local_variable_table_length: u2,
/// Note: the 3rd field is called `signature_index` and represents a field type signature /// Note: the 3rd field is called `signature_index` and represents a field type signature
local_variable_table: Vec<AttributeLocalVariableTable>, local_variable_table: Vec<AttributeLocalVariableTable>,
}, },
/// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Marks a class/field/method as deprecated /// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Marks a class/field/method as deprecated
Deprecated { Deprecated,
attribute_name_index: u2,
attribute_length: u4, // 0
},
/// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Contains all Runtime visible annotations /// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Contains all Runtime visible annotations
RuntimeVisibleAnnotations { RuntimeVisibleAnnotations {
attribute_name_index: u2,
attribute_length: u4,
num_annotations: u2, num_annotations: u2,
annotations: Vec<Annotation>, annotations: Vec<Annotation>,
}, },
/// Same as `RuntimeVisibleAnnotations`, but invisible to reflection /// Same as `RuntimeVisibleAnnotations`, but invisible to reflection
RuntimeInvisibleAnnotations { RuntimeInvisibleAnnotations {
attribute_name_index: u2,
attribute_length: u4,
num_annotations: u2, num_annotations: u2,
annotations: Vec<Annotation>, annotations: Vec<Annotation>,
}, },
/// Only on `MethodInfo`, parameter annotations visible during runtime /// Only on `MethodInfo`, parameter annotations visible during runtime
RuntimeVisibleParameterAnnotations { RuntimeVisibleParameterAnnotations {
attribute_name_index: u2,
attribute_length: u4,
num_parameters: u1, num_parameters: u1,
parameter_annotations: Vec<ParameterAnnotation>, parameter_annotations: Vec<ParameterAnnotation>,
}, },
/// Same as `RuntimeVisibleParameterAnnotations`, but invisible to reflection /// Same as `RuntimeVisibleParameterAnnotations`, but invisible to reflection
RuntimeInvisibleParameterAnnotations { RuntimeInvisibleParameterAnnotations {
attribute_name_index: u2,
attribute_length: u4,
num_parameters: u1, num_parameters: u1,
parameter_annotations: Vec<ParameterAnnotation>, parameter_annotations: Vec<ParameterAnnotation>,
}, },
/// Only on `MethodInfo`, on those representing elements of annotation types, the default value of the element /// Only on `MethodInfo`, on those representing elements of annotation types, the default value of the element
AnnotationDefault { AnnotationDefault {
attribute_name_index: u2,
attribute_length: u4,
default_value: AnnotationElementValue, default_value: AnnotationElementValue,
}, },
/// Only on `ClassFile`. Records bootstrap method specifiers for `invokedynamic` /// Only on `ClassFile`. Records bootstrap method specifiers for `invokedynamic`
BootstrapMethods { BootstrapMethods {
attribute_name_index: u2,
attribute_length: u4,
num_bootstrap_methods: u2, num_bootstrap_methods: u2,
bootstrap_methods: Vec<BootstrapMethod>, bootstrap_methods: Vec<BootstrapMethod>,
}, },