1use cafebabe::attributes::{AttributeData, AttributeInfo};
7use cafebabe::constant_pool::LiteralConstant;
8use cafebabe::descriptors::{FieldDescriptor, FieldType, MethodDescriptor, ReturnDescriptor};
9
10use crate::stub::model::{BaseType, ConstantValue, OrderedFloat, TypeSignature};
11
12pub(crate) fn field_descriptor_to_type(desc: &FieldDescriptor<'_>) -> TypeSignature {
21 let base = field_type_to_signature(&desc.field_type);
22 wrap_in_arrays(base, desc.dimensions)
23}
24
25pub(crate) fn return_descriptor_to_type(desc: &ReturnDescriptor<'_>) -> TypeSignature {
30 match desc {
31 ReturnDescriptor::Void => TypeSignature::Base(BaseType::Void),
32 ReturnDescriptor::Return(fd) => field_descriptor_to_type(fd),
33 }
34}
35
36pub(crate) fn method_descriptor_to_types(
38 desc: &MethodDescriptor<'_>,
39) -> (Vec<TypeSignature>, TypeSignature) {
40 let param_types = desc
41 .parameters
42 .iter()
43 .map(field_descriptor_to_type)
44 .collect();
45 let return_type = return_descriptor_to_type(&desc.return_type);
46 (param_types, return_type)
47}
48
49fn field_type_to_signature(ft: &FieldType<'_>) -> TypeSignature {
52 match ft {
53 FieldType::Byte => TypeSignature::Base(BaseType::Byte),
54 FieldType::Char => TypeSignature::Base(BaseType::Char),
55 FieldType::Double => TypeSignature::Base(BaseType::Double),
56 FieldType::Float => TypeSignature::Base(BaseType::Float),
57 FieldType::Integer => TypeSignature::Base(BaseType::Int),
58 FieldType::Long => TypeSignature::Base(BaseType::Long),
59 FieldType::Short => TypeSignature::Base(BaseType::Short),
60 FieldType::Boolean => TypeSignature::Base(BaseType::Boolean),
61 FieldType::Object(class_name) => TypeSignature::Class {
62 fqn: class_name_to_fqn(class_name),
63 type_arguments: vec![],
64 },
65 }
66}
67
68fn wrap_in_arrays(inner: TypeSignature, dimensions: u8) -> TypeSignature {
70 let mut sig = inner;
71 for _ in 0..dimensions {
72 sig = TypeSignature::Array(Box::new(sig));
73 }
74 sig
75}
76
77pub(crate) fn class_name_to_fqn(name: &str) -> String {
86 name.replace('/', ".")
87}
88
89pub(crate) fn literal_to_constant_value(lit: &LiteralConstant<'_>) -> ConstantValue {
95 match lit {
96 LiteralConstant::Integer(v) => ConstantValue::Int(*v),
97 LiteralConstant::Long(v) => ConstantValue::Long(*v),
98 LiteralConstant::Float(v) => ConstantValue::Float(OrderedFloat(*v)),
99 LiteralConstant::Double(v) => ConstantValue::Double(OrderedFloat(*v)),
100 LiteralConstant::String(s) => ConstantValue::String(s.to_string()),
101 LiteralConstant::StringBytes(bytes) => {
102 ConstantValue::String(String::from_utf8_lossy(bytes).into_owned())
104 }
105 }
106}
107
108#[allow(dead_code)]
114pub(crate) fn find_attribute<'a, 'b>(
115 attrs: &'a [AttributeInfo<'b>],
116 name: &str,
117) -> Option<&'a AttributeInfo<'b>> {
118 attrs.iter().find(|a| a.name == name)
119}
120
121pub(crate) fn extract_source_file(attrs: &[AttributeInfo<'_>]) -> Option<String> {
123 attrs.iter().find_map(|a| match &a.data {
124 AttributeData::SourceFile(s) => Some(s.to_string()),
125 _ => None,
126 })
127}
128
129pub(crate) fn extract_method_parameter_names(attrs: &[AttributeInfo<'_>]) -> Vec<String> {
131 for attr in attrs {
132 if let AttributeData::MethodParameters(params) = &attr.data {
133 return params
134 .iter()
135 .filter_map(|p| p.name.as_ref().map(std::string::ToString::to_string))
136 .collect();
137 }
138 }
139 vec![]
140}
141
142pub(crate) fn extract_constant_value(attrs: &[AttributeInfo<'_>]) -> Option<ConstantValue> {
144 attrs.iter().find_map(|a| match &a.data {
145 AttributeData::ConstantValue(lit) => Some(literal_to_constant_value(lit)),
146 _ => None,
147 })
148}
149
150#[allow(dead_code)]
165pub(crate) fn parse_field_descriptor_str(desc: &str) -> Option<TypeSignature> {
166 let (sig, rest) = parse_field_type_from_str(desc)?;
167 if rest.is_empty() { Some(sig) } else { None }
168}
169
170#[allow(dead_code)]
177pub(crate) fn parse_method_descriptor_str(
178 desc: &str,
179) -> Option<(Vec<TypeSignature>, TypeSignature)> {
180 let bytes = desc.as_bytes();
181 if bytes.is_empty() || bytes[0] != b'(' {
182 return None;
183 }
184 let mut pos = 1;
185 let mut params = Vec::new();
186 while pos < bytes.len() && bytes[pos] != b')' {
187 let (sig, rest) = parse_field_type_from_str(&desc[pos..])?;
188 let consumed = desc[pos..].len() - rest.len();
189 pos += consumed;
190 params.push(sig);
191 }
192 if pos >= bytes.len() || bytes[pos] != b')' {
193 return None;
194 }
195 pos += 1;
196 let ret_str = &desc[pos..];
197 let return_type = if ret_str == "V" {
198 TypeSignature::Base(BaseType::Void)
199 } else {
200 let (sig, rest) = parse_field_type_from_str(ret_str)?;
201 if !rest.is_empty() {
202 return None;
203 }
204 sig
205 };
206 Some((params, return_type))
207}
208
209fn parse_field_type_from_str(desc: &str) -> Option<(TypeSignature, &str)> {
212 let bytes = desc.as_bytes();
213 if bytes.is_empty() {
214 return None;
215 }
216 match bytes[0] {
217 b'B' => Some((TypeSignature::Base(BaseType::Byte), &desc[1..])),
218 b'C' => Some((TypeSignature::Base(BaseType::Char), &desc[1..])),
219 b'D' => Some((TypeSignature::Base(BaseType::Double), &desc[1..])),
220 b'F' => Some((TypeSignature::Base(BaseType::Float), &desc[1..])),
221 b'I' => Some((TypeSignature::Base(BaseType::Int), &desc[1..])),
222 b'J' => Some((TypeSignature::Base(BaseType::Long), &desc[1..])),
223 b'S' => Some((TypeSignature::Base(BaseType::Short), &desc[1..])),
224 b'Z' => Some((TypeSignature::Base(BaseType::Boolean), &desc[1..])),
225 b'V' => Some((TypeSignature::Base(BaseType::Void), &desc[1..])),
226 b'L' => {
227 let semi_pos = desc[1..].find(';')?;
229 let class_name = &desc[1..=semi_pos];
230 let fqn = class_name.replace('/', ".");
231 let sig = TypeSignature::Class {
232 fqn,
233 type_arguments: vec![],
234 };
235 Some((sig, &desc[2 + semi_pos..]))
236 }
237 b'[' => {
238 let (inner, rest) = parse_field_type_from_str(&desc[1..])?;
239 Some((TypeSignature::Array(Box::new(inner)), rest))
240 }
241 _ => None,
242 }
243}
244
245#[cfg(test)]
250mod tests {
251 use super::*;
252
253 #[test]
254 fn test_class_name_to_fqn() {
255 assert_eq!(class_name_to_fqn("java/lang/String"), "java.lang.String");
256 assert_eq!(class_name_to_fqn("com/example/Foo"), "com.example.Foo");
257 assert_eq!(class_name_to_fqn("SimpleClass"), "SimpleClass");
258 }
259
260 #[test]
261 fn test_parse_primitive_descriptors() {
262 assert!(matches!(
263 parse_field_descriptor_str("B"),
264 Some(TypeSignature::Base(BaseType::Byte))
265 ));
266 assert!(matches!(
267 parse_field_descriptor_str("C"),
268 Some(TypeSignature::Base(BaseType::Char))
269 ));
270 assert!(matches!(
271 parse_field_descriptor_str("D"),
272 Some(TypeSignature::Base(BaseType::Double))
273 ));
274 assert!(matches!(
275 parse_field_descriptor_str("F"),
276 Some(TypeSignature::Base(BaseType::Float))
277 ));
278 assert!(matches!(
279 parse_field_descriptor_str("I"),
280 Some(TypeSignature::Base(BaseType::Int))
281 ));
282 assert!(matches!(
283 parse_field_descriptor_str("J"),
284 Some(TypeSignature::Base(BaseType::Long))
285 ));
286 assert!(matches!(
287 parse_field_descriptor_str("S"),
288 Some(TypeSignature::Base(BaseType::Short))
289 ));
290 assert!(matches!(
291 parse_field_descriptor_str("Z"),
292 Some(TypeSignature::Base(BaseType::Boolean))
293 ));
294 assert!(matches!(
295 parse_field_descriptor_str("V"),
296 Some(TypeSignature::Base(BaseType::Void))
297 ));
298 }
299
300 #[test]
301 fn test_parse_class_descriptor() {
302 let sig = parse_field_descriptor_str("Ljava/lang/String;").unwrap();
303 match sig {
304 TypeSignature::Class {
305 fqn,
306 type_arguments,
307 } => {
308 assert_eq!(fqn, "java.lang.String");
309 assert!(type_arguments.is_empty());
310 }
311 other => panic!("Expected Class, got {other:?}"),
312 }
313 }
314
315 #[test]
316 fn test_parse_array_descriptor() {
317 let sig = parse_field_descriptor_str("[I").unwrap();
318 match sig {
319 TypeSignature::Array(inner) => {
320 assert!(matches!(*inner, TypeSignature::Base(BaseType::Int)));
321 }
322 other => panic!("Expected Array, got {other:?}"),
323 }
324 }
325
326 #[test]
327 fn test_parse_nested_array_descriptor() {
328 let sig = parse_field_descriptor_str("[[Ljava/lang/String;").unwrap();
329 match sig {
330 TypeSignature::Array(outer) => match *outer {
331 TypeSignature::Array(inner) => match *inner {
332 TypeSignature::Class { ref fqn, .. } => {
333 assert_eq!(fqn, "java.lang.String");
334 }
335 other => panic!("Expected Class, got {other:?}"),
336 },
337 other => panic!("Expected Array, got {other:?}"),
338 },
339 other => panic!("Expected Array, got {other:?}"),
340 }
341 }
342
343 #[test]
344 fn test_parse_method_descriptor_void_void() {
345 let (params, ret) = parse_method_descriptor_str("()V").unwrap();
346 assert!(params.is_empty());
347 assert!(matches!(ret, TypeSignature::Base(BaseType::Void)));
348 }
349
350 #[test]
351 fn test_parse_method_descriptor_with_params() {
352 let (params, ret) = parse_method_descriptor_str("(ILjava/lang/String;)V").unwrap();
353 assert_eq!(params.len(), 2);
354 assert!(matches!(params[0], TypeSignature::Base(BaseType::Int)));
355 match ¶ms[1] {
356 TypeSignature::Class { fqn, .. } => assert_eq!(fqn, "java.lang.String"),
357 other => panic!("Expected Class, got {other:?}"),
358 }
359 assert!(matches!(ret, TypeSignature::Base(BaseType::Void)));
360 }
361
362 #[test]
363 fn test_parse_method_descriptor_with_return() {
364 let (params, ret) = parse_method_descriptor_str("()Ljava/lang/String;").unwrap();
365 assert!(params.is_empty());
366 match &ret {
367 TypeSignature::Class { fqn, .. } => assert_eq!(fqn, "java.lang.String"),
368 other => panic!("Expected Class, got {other:?}"),
369 }
370 }
371
372 #[test]
373 fn test_parse_method_descriptor_complex() {
374 let (params, ret) =
375 parse_method_descriptor_str("(BJ[Ljava/lang/Object;D)Ljava/util/List;").unwrap();
376 assert_eq!(params.len(), 4);
377 assert!(matches!(params[0], TypeSignature::Base(BaseType::Byte)));
378 assert!(matches!(params[1], TypeSignature::Base(BaseType::Long)));
379 match ¶ms[2] {
380 TypeSignature::Array(inner) => match inner.as_ref() {
381 TypeSignature::Class { fqn, .. } => assert_eq!(fqn, "java.lang.Object"),
382 other => panic!("Expected Class, got {other:?}"),
383 },
384 other => panic!("Expected Array, got {other:?}"),
385 }
386 assert!(matches!(params[3], TypeSignature::Base(BaseType::Double)));
387 match &ret {
388 TypeSignature::Class { fqn, .. } => assert_eq!(fqn, "java.util.List"),
389 other => panic!("Expected Class, got {other:?}"),
390 }
391 }
392
393 #[test]
394 fn test_parse_invalid_descriptor() {
395 assert!(parse_field_descriptor_str("").is_none());
396 assert!(parse_field_descriptor_str("X").is_none());
397 assert!(parse_field_descriptor_str("Ljava/lang/String").is_none()); assert!(parse_field_descriptor_str("II").is_none()); }
400
401 #[test]
402 fn test_parse_invalid_method_descriptor() {
403 assert!(parse_method_descriptor_str("").is_none());
404 assert!(parse_method_descriptor_str("V").is_none()); assert!(parse_method_descriptor_str("(").is_none()); assert!(parse_method_descriptor_str("()").is_none()); }
408
409 #[test]
410 fn test_literal_to_constant_value() {
411 assert_eq!(
412 literal_to_constant_value(&LiteralConstant::Integer(42)),
413 ConstantValue::Int(42)
414 );
415 assert_eq!(
416 literal_to_constant_value(&LiteralConstant::Long(123_456_789)),
417 ConstantValue::Long(123_456_789)
418 );
419 assert_eq!(
420 literal_to_constant_value(&LiteralConstant::Float(std::f32::consts::PI)),
421 ConstantValue::Float(OrderedFloat(std::f32::consts::PI))
422 );
423 assert_eq!(
424 literal_to_constant_value(&LiteralConstant::Double(std::f64::consts::E)),
425 ConstantValue::Double(OrderedFloat(std::f64::consts::E))
426 );
427 assert_eq!(
428 literal_to_constant_value(&LiteralConstant::String("hello".into())),
429 ConstantValue::String("hello".to_owned())
430 );
431 }
432}