1use crate::stub::model::{
50 BaseType, GenericClassSignature, GenericMethodSignature, TypeArgument, TypeParameterStub,
51 TypeSignature,
52};
53use crate::{ClasspathError, ClasspathResult};
54
55pub fn parse_class_signature(input: &str) -> ClasspathResult<GenericClassSignature> {
73 let mut parser = SignatureParser::new(input);
74 let result = parser.parse_class_signature()?;
75 parser.expect_end()?;
76 Ok(result)
77}
78
79pub fn parse_method_signature(input: &str) -> ClasspathResult<GenericMethodSignature> {
91 let mut parser = SignatureParser::new(input);
92 let result = parser.parse_method_signature()?;
93 parser.expect_end()?;
94 Ok(result)
95}
96
97pub fn parse_field_signature(input: &str) -> ClasspathResult<TypeSignature> {
112 let mut parser = SignatureParser::new(input);
113 let result = parser.parse_field_type_signature()?;
114 parser.expect_end()?;
115 Ok(result)
116}
117
118struct SignatureParser<'a> {
130 input: &'a [u8],
131 pos: usize,
132}
133
134impl<'a> SignatureParser<'a> {
135 fn new(input: &'a str) -> Self {
136 Self {
137 input: input.as_bytes(),
138 pos: 0,
139 }
140 }
141
142 fn peek(&self) -> Option<u8> {
146 self.input.get(self.pos).copied()
147 }
148
149 fn advance(&mut self) {
151 self.pos += 1;
152 }
153
154 fn expect(&mut self, expected: u8) -> ClasspathResult<()> {
156 match self.peek() {
157 Some(b) if b == expected => {
158 self.advance();
159 Ok(())
160 }
161 Some(b) => Err(self.error(format!(
162 "expected '{}' but found '{}' at position {}",
163 expected as char, b as char, self.pos
164 ))),
165 None => Err(self.error(format!(
166 "expected '{}' but reached end of input at position {}",
167 expected as char, self.pos
168 ))),
169 }
170 }
171
172 fn expect_end(&self) -> ClasspathResult<()> {
174 if self.pos == self.input.len() {
175 Ok(())
176 } else {
177 let remaining = &self.input[self.pos..];
178 let remaining_str = std::str::from_utf8(remaining).unwrap_or("<invalid utf8>");
179 Err(self.error(format!(
180 "unexpected trailing input at position {}: {:?}",
181 self.pos, remaining_str
182 )))
183 }
184 }
185
186 fn read_identifier(&mut self) -> ClasspathResult<String> {
191 let start = self.pos;
192 while self.pos < self.input.len() && !is_delimiter(self.input[self.pos]) {
193 self.pos += 1;
194 }
195 if self.pos == start {
196 return Err(self.error(format!(
197 "expected identifier at position {} but found '{}'",
198 self.pos,
199 self.peek()
200 .map_or_else(|| "end of input".to_owned(), |b| (b as char).to_string())
201 )));
202 }
203 let ident = std::str::from_utf8(&self.input[start..self.pos])
205 .map_err(|e| self.error(format!("invalid UTF-8 in identifier: {e}")))?;
206 Ok(ident.to_owned())
207 }
208
209 fn error(&self, reason: String) -> ClasspathError {
212 let input_str = std::str::from_utf8(self.input).unwrap_or("<invalid utf8>");
213 ClasspathError::BytecodeParseError {
214 class_name: format!("<signature:{input_str}>"),
215 reason,
216 }
217 }
218
219 fn parse_class_signature(&mut self) -> ClasspathResult<GenericClassSignature> {
225 let type_parameters = if self.peek() == Some(b'<') {
226 self.parse_formal_type_parameters()?
227 } else {
228 Vec::new()
229 };
230
231 let superclass = self.parse_class_type_signature()?;
233
234 let mut interfaces = Vec::new();
236 while self.peek() == Some(b'L') {
237 interfaces.push(self.parse_class_type_signature()?);
238 }
239
240 Ok(GenericClassSignature {
241 type_parameters,
242 superclass,
243 interfaces,
244 })
245 }
246
247 fn parse_method_signature(&mut self) -> ClasspathResult<GenericMethodSignature> {
251 let type_parameters = if self.peek() == Some(b'<') {
252 self.parse_formal_type_parameters()?
253 } else {
254 Vec::new()
255 };
256
257 self.expect(b'(')?;
258 let mut parameter_types = Vec::new();
259 while self.peek() != Some(b')') {
260 parameter_types.push(self.parse_type_signature()?);
261 }
262 self.expect(b')')?;
263
264 let return_type = self.parse_return_type()?;
266
267 let mut exception_types = Vec::new();
269 while self.peek() == Some(b'^') {
270 self.advance(); exception_types.push(self.parse_throws_target()?);
272 }
273
274 Ok(GenericMethodSignature {
275 type_parameters,
276 parameter_types,
277 return_type,
278 exception_types,
279 })
280 }
281
282 fn parse_formal_type_parameters(&mut self) -> ClasspathResult<Vec<TypeParameterStub>> {
289 self.expect(b'<')?;
290 let mut params = Vec::new();
291 while self.peek() != Some(b'>') {
292 params.push(self.parse_formal_type_parameter()?);
293 }
294 self.expect(b'>')?;
295 if params.is_empty() {
296 return Err(self.error("formal type parameter list must not be empty".to_owned()));
297 }
298 Ok(params)
299 }
300
301 fn parse_formal_type_parameter(&mut self) -> ClasspathResult<TypeParameterStub> {
302 let name = self.read_identifier()?;
303
304 self.expect(b':')?;
306 let class_bound = if is_field_type_start(self.peek()) {
307 Some(self.parse_field_type_signature()?)
308 } else {
309 None
311 };
312
313 let mut interface_bounds = Vec::new();
315 while self.peek() == Some(b':') {
316 self.advance(); interface_bounds.push(self.parse_field_type_signature()?);
318 }
319
320 Ok(TypeParameterStub {
321 name,
322 class_bound,
323 interface_bounds,
324 })
325 }
326
327 fn parse_field_type_signature(&mut self) -> ClasspathResult<TypeSignature> {
331 match self.peek() {
332 Some(b'L') => self.parse_class_type_signature(),
333 Some(b'[') => self.parse_array_type_signature(),
334 Some(b'T') => self.parse_type_variable_signature(),
335 Some(b) => Err(self.error(format!(
336 "expected field type signature (L, [, or T) but found '{}' at position {}",
337 b as char, self.pos
338 ))),
339 None => {
340 Err(self.error("expected field type signature but reached end of input".to_owned()))
341 }
342 }
343 }
344
345 fn parse_class_type_signature(&mut self) -> ClasspathResult<TypeSignature> {
361 self.expect(b'L')?;
362
363 let mut segments: Vec<String> = Vec::new();
366 loop {
367 let ident = self.read_identifier()?;
368 segments.push(ident);
369 if self.peek() == Some(b'/') {
370 self.advance(); } else {
372 break;
373 }
374 }
375
376 let fqn = segments.join(".");
378
379 let mut type_arguments = if self.peek() == Some(b'<') {
381 self.parse_type_arguments()?
382 } else {
383 Vec::new()
384 };
385
386 let mut full_fqn = fqn;
388 while self.peek() == Some(b'.') {
389 self.advance(); let inner_name = self.read_identifier()?;
391 full_fqn = format!("{full_fqn}${inner_name}");
392 type_arguments = if self.peek() == Some(b'<') {
393 self.parse_type_arguments()?
394 } else {
395 Vec::new()
396 };
397 }
398
399 self.expect(b';')?;
400
401 Ok(TypeSignature::Class {
402 fqn: full_fqn,
403 type_arguments,
404 })
405 }
406
407 fn parse_type_arguments(&mut self) -> ClasspathResult<Vec<TypeArgument>> {
413 self.expect(b'<')?;
414 let mut args = Vec::new();
415 while self.peek() != Some(b'>') {
416 args.push(self.parse_type_argument()?);
417 }
418 self.expect(b'>')?;
419 if args.is_empty() {
420 return Err(self.error("type argument list must not be empty".to_owned()));
421 }
422 Ok(args)
423 }
424
425 fn parse_type_argument(&mut self) -> ClasspathResult<TypeArgument> {
426 match self.peek() {
427 Some(b'*') => {
428 self.advance();
429 Ok(TypeArgument::Unbounded)
430 }
431 Some(b'+') => {
432 self.advance();
433 let sig = self.parse_field_type_signature()?;
434 Ok(TypeArgument::Extends(sig))
435 }
436 Some(b'-') => {
437 self.advance();
438 let sig = self.parse_field_type_signature()?;
439 Ok(TypeArgument::Super(sig))
440 }
441 _ => {
442 let sig = self.parse_field_type_signature()?;
443 Ok(TypeArgument::Type(sig))
444 }
445 }
446 }
447
448 fn parse_type_variable_signature(&mut self) -> ClasspathResult<TypeSignature> {
452 self.expect(b'T')?;
453 let name = self.read_identifier()?;
454 self.expect(b';')?;
455 Ok(TypeSignature::TypeVariable(name))
456 }
457
458 fn parse_array_type_signature(&mut self) -> ClasspathResult<TypeSignature> {
462 self.expect(b'[')?;
463 let element = self.parse_type_signature()?;
464 Ok(TypeSignature::Array(Box::new(element)))
465 }
466
467 fn parse_type_signature(&mut self) -> ClasspathResult<TypeSignature> {
472 match self.peek() {
473 Some(b'L' | b'[' | b'T') => self.parse_field_type_signature(),
474 Some(b) if is_base_type(b) => {
475 self.advance();
476 Ok(TypeSignature::Base(byte_to_base_type(b)?))
477 }
478 Some(b) => Err(self.error(format!(
479 "expected type signature but found '{}' at position {}",
480 b as char, self.pos
481 ))),
482 None => Err(self.error("expected type signature but reached end of input".to_owned())),
483 }
484 }
485
486 fn parse_return_type(&mut self) -> ClasspathResult<TypeSignature> {
490 if self.peek() == Some(b'V') {
491 self.advance();
492 Ok(TypeSignature::Base(BaseType::Void))
493 } else {
494 self.parse_type_signature()
495 }
496 }
497
498 fn parse_throws_target(&mut self) -> ClasspathResult<TypeSignature> {
504 match self.peek() {
505 Some(b'L') => self.parse_class_type_signature(),
506 Some(b'T') => self.parse_type_variable_signature(),
507 Some(b) => Err(self.error(format!(
508 "expected class or type variable in throws signature but found '{}' at position {}",
509 b as char, self.pos
510 ))),
511 None => Err(self.error("expected throws target but reached end of input".to_owned())),
512 }
513 }
514}
515
516fn is_delimiter(b: u8) -> bool {
522 matches!(
523 b,
524 b':' | b';' | b'<' | b'>' | b'.' | b'/' | b'(' | b')' | b'[' | b'^'
525 )
526}
527
528fn is_field_type_start(b: Option<u8>) -> bool {
530 matches!(b, Some(b'L' | b'[' | b'T'))
531}
532
533fn is_base_type(b: u8) -> bool {
535 matches!(b, b'B' | b'C' | b'D' | b'F' | b'I' | b'J' | b'S' | b'Z')
536}
537
538fn byte_to_base_type(b: u8) -> ClasspathResult<BaseType> {
540 match b {
541 b'B' => Ok(BaseType::Byte),
542 b'C' => Ok(BaseType::Char),
543 b'D' => Ok(BaseType::Double),
544 b'F' => Ok(BaseType::Float),
545 b'I' => Ok(BaseType::Int),
546 b'J' => Ok(BaseType::Long),
547 b'S' => Ok(BaseType::Short),
548 b'Z' => Ok(BaseType::Boolean),
549 _ => Err(ClasspathError::BytecodeParseError {
550 class_name: "<signature>".to_owned(),
551 reason: format!("unknown base type descriptor: '{}'", b as char),
552 }),
553 }
554}
555
556#[cfg(test)]
561mod tests {
562 use super::*;
563
564 #[test]
567 fn test_hashmap_class_signature() {
568 let input = "<K:Ljava/lang/Object;V:Ljava/lang/Object;>Ljava/util/AbstractMap<TK;TV;>;Ljava/util/Map<TK;TV;>;";
570 let sig = parse_class_signature(input).unwrap();
571
572 assert_eq!(sig.type_parameters.len(), 2);
574
575 let k = &sig.type_parameters[0];
576 assert_eq!(k.name, "K");
577 match &k.class_bound {
578 Some(TypeSignature::Class {
579 fqn,
580 type_arguments,
581 }) => {
582 assert_eq!(fqn, "java.lang.Object");
583 assert!(type_arguments.is_empty());
584 }
585 other => panic!("expected Class bound, got {other:?}"),
586 }
587 assert!(k.interface_bounds.is_empty());
588
589 let v = &sig.type_parameters[1];
590 assert_eq!(v.name, "V");
591 match &v.class_bound {
592 Some(TypeSignature::Class { fqn, .. }) => {
593 assert_eq!(fqn, "java.lang.Object");
594 }
595 other => panic!("expected Class bound, got {other:?}"),
596 }
597
598 match &sig.superclass {
600 TypeSignature::Class {
601 fqn,
602 type_arguments,
603 } => {
604 assert_eq!(fqn, "java.util.AbstractMap");
605 assert_eq!(type_arguments.len(), 2);
606 match &type_arguments[0] {
607 TypeArgument::Type(TypeSignature::TypeVariable(name)) => {
608 assert_eq!(name, "K");
609 }
610 other => panic!("expected TypeVariable K, got {other:?}"),
611 }
612 }
613 other => panic!("expected Class superclass, got {other:?}"),
614 }
615
616 assert_eq!(sig.interfaces.len(), 1);
618 match &sig.interfaces[0] {
619 TypeSignature::Class {
620 fqn,
621 type_arguments,
622 } => {
623 assert_eq!(fqn, "java.util.Map");
624 assert_eq!(type_arguments.len(), 2);
625 }
626 other => panic!("expected Class interface, got {other:?}"),
627 }
628 }
629
630 #[test]
633 fn test_wildcard_extends() {
634 let input = "Ljava/util/List<+Ljava/lang/Number;>;";
636 let sig = parse_field_signature(input).unwrap();
637
638 match sig {
639 TypeSignature::Class {
640 fqn,
641 type_arguments,
642 } => {
643 assert_eq!(fqn, "java.util.List");
644 assert_eq!(type_arguments.len(), 1);
645 match &type_arguments[0] {
646 TypeArgument::Extends(TypeSignature::Class { fqn, .. }) => {
647 assert_eq!(fqn, "java.lang.Number");
648 }
649 other => panic!("expected Extends(Number), got {other:?}"),
650 }
651 }
652 other => panic!("expected Class, got {other:?}"),
653 }
654 }
655
656 #[test]
659 fn test_nested_generics() {
660 let input = "Ljava/util/Map<Ljava/lang/String;Ljava/util/List<-Ljava/lang/Integer;>;>;";
663 let sig = parse_field_signature(input).unwrap();
664
665 match sig {
666 TypeSignature::Class {
667 fqn,
668 type_arguments,
669 } => {
670 assert_eq!(fqn, "java.util.Map");
671 assert_eq!(type_arguments.len(), 2);
672
673 match &type_arguments[0] {
675 TypeArgument::Type(TypeSignature::Class { fqn, .. }) => {
676 assert_eq!(fqn, "java.lang.String");
677 }
678 other => panic!("expected String, got {other:?}"),
679 }
680
681 match &type_arguments[1] {
683 TypeArgument::Type(TypeSignature::Class {
684 fqn,
685 type_arguments: inner_args,
686 }) => {
687 assert_eq!(fqn, "java.util.List");
688 assert_eq!(inner_args.len(), 1);
689 match &inner_args[0] {
690 TypeArgument::Super(TypeSignature::Class { fqn, .. }) => {
691 assert_eq!(fqn, "java.lang.Integer");
692 }
693 other => panic!("expected Super(Integer), got {other:?}"),
694 }
695 }
696 other => panic!("expected List<? super Integer>, got {other:?}"),
697 }
698 }
699 other => panic!("expected Class, got {other:?}"),
700 }
701 }
702
703 #[test]
706 fn test_bounded_type_parameter_self_reference() {
707 let input = "<T:Ljava/lang/Comparable<TT;>;>Ljava/lang/Object;";
709 let sig = parse_class_signature(input).unwrap();
710
711 assert_eq!(sig.type_parameters.len(), 1);
712 let t = &sig.type_parameters[0];
713 assert_eq!(t.name, "T");
714
715 match &t.class_bound {
716 Some(TypeSignature::Class {
717 fqn,
718 type_arguments,
719 }) => {
720 assert_eq!(fqn, "java.lang.Comparable");
721 assert_eq!(type_arguments.len(), 1);
722 match &type_arguments[0] {
723 TypeArgument::Type(TypeSignature::TypeVariable(name)) => {
724 assert_eq!(name, "T");
725 }
726 other => panic!("expected TypeVariable(T), got {other:?}"),
727 }
728 }
729 other => panic!("expected Comparable<T> bound, got {other:?}"),
730 }
731 }
732
733 #[test]
736 fn test_method_signature_with_type_params() {
737 let input = "<T:Ljava/lang/Object;>(TT;Ljava/util/List<TT;>;)TT;";
739 let sig = parse_method_signature(input).unwrap();
740
741 assert_eq!(sig.type_parameters.len(), 1);
742 assert_eq!(sig.type_parameters[0].name, "T");
743
744 assert_eq!(sig.parameter_types.len(), 2);
745 match &sig.parameter_types[0] {
746 TypeSignature::TypeVariable(name) => assert_eq!(name, "T"),
747 other => panic!("expected TypeVariable(T), got {other:?}"),
748 }
749 match &sig.parameter_types[1] {
750 TypeSignature::Class {
751 fqn,
752 type_arguments,
753 } => {
754 assert_eq!(fqn, "java.util.List");
755 assert_eq!(type_arguments.len(), 1);
756 }
757 other => panic!("expected List<T>, got {other:?}"),
758 }
759
760 match &sig.return_type {
761 TypeSignature::TypeVariable(name) => assert_eq!(name, "T"),
762 other => panic!("expected TypeVariable(T) return, got {other:?}"),
763 }
764
765 assert!(sig.exception_types.is_empty());
766 }
767
768 #[test]
771 fn test_array_type() {
772 let input = "[Ljava/lang/String;";
774 let sig = parse_field_signature(input).unwrap();
775
776 match sig {
777 TypeSignature::Array(inner) => match *inner {
778 TypeSignature::Class { ref fqn, .. } => {
779 assert_eq!(fqn, "java.lang.String");
780 }
781 other => panic!("expected Class inside Array, got {other:?}"),
782 },
783 other => panic!("expected Array, got {other:?}"),
784 }
785 }
786
787 #[test]
788 fn test_nested_array_type() {
789 let input = "([[I)V";
792 let sig = parse_method_signature(input).unwrap();
793
794 assert_eq!(sig.parameter_types.len(), 1);
795 match &sig.parameter_types[0] {
796 TypeSignature::Array(inner) => match inner.as_ref() {
797 TypeSignature::Array(inner2) => match inner2.as_ref() {
798 TypeSignature::Base(BaseType::Int) => {}
799 other => panic!("expected Base(Int), got {other:?}"),
800 },
801 other => panic!("expected Array inside Array, got {other:?}"),
802 },
803 other => panic!("expected Array, got {other:?}"),
804 }
805 }
806
807 #[test]
810 fn test_multiple_interface_bounds() {
811 let input = "<T:Ljava/lang/Object;:Ljava/io/Serializable;:Ljava/lang/Comparable<TT;>;>Ljava/lang/Object;";
813 let sig = parse_class_signature(input).unwrap();
814
815 assert_eq!(sig.type_parameters.len(), 1);
816 let t = &sig.type_parameters[0];
817 assert_eq!(t.name, "T");
818
819 match &t.class_bound {
821 Some(TypeSignature::Class { fqn, .. }) => {
822 assert_eq!(fqn, "java.lang.Object");
823 }
824 other => panic!("expected Object class bound, got {other:?}"),
825 }
826
827 assert_eq!(t.interface_bounds.len(), 2);
829 match &t.interface_bounds[0] {
830 TypeSignature::Class { fqn, .. } => {
831 assert_eq!(fqn, "java.io.Serializable");
832 }
833 other => panic!("expected Serializable, got {other:?}"),
834 }
835 match &t.interface_bounds[1] {
836 TypeSignature::Class {
837 fqn,
838 type_arguments,
839 } => {
840 assert_eq!(fqn, "java.lang.Comparable");
841 assert_eq!(type_arguments.len(), 1);
842 }
843 other => panic!("expected Comparable<T>, got {other:?}"),
844 }
845 }
846
847 #[test]
850 fn test_inner_class_signature() {
851 let input = "Ljava/util/Map.Entry<TK;TV;>;";
853 let sig = parse_field_signature(input).unwrap();
854
855 match sig {
856 TypeSignature::Class {
857 fqn,
858 type_arguments,
859 } => {
860 assert_eq!(fqn, "java.util.Map$Entry");
862 assert_eq!(type_arguments.len(), 2);
863 match &type_arguments[0] {
864 TypeArgument::Type(TypeSignature::TypeVariable(name)) => {
865 assert_eq!(name, "K");
866 }
867 other => panic!("expected TypeVariable(K), got {other:?}"),
868 }
869 match &type_arguments[1] {
870 TypeArgument::Type(TypeSignature::TypeVariable(name)) => {
871 assert_eq!(name, "V");
872 }
873 other => panic!("expected TypeVariable(V), got {other:?}"),
874 }
875 }
876 other => panic!("expected Class, got {other:?}"),
877 }
878 }
879
880 #[test]
881 fn test_nested_inner_class() {
882 let input = "Ljava/util/Outer.Middle.Inner;";
884 let sig = parse_field_signature(input).unwrap();
885
886 match sig {
887 TypeSignature::Class {
888 fqn,
889 type_arguments,
890 } => {
891 assert_eq!(fqn, "java.util.Outer$Middle$Inner");
892 assert!(type_arguments.is_empty());
893 }
894 other => panic!("expected Class, got {other:?}"),
895 }
896 }
897
898 #[test]
901 fn test_method_with_throws() {
902 let input = "<T:Ljava/lang/Exception;>(TT;)V^TT;^Ljava/io/IOException;";
904 let sig = parse_method_signature(input).unwrap();
905
906 assert_eq!(sig.type_parameters.len(), 1);
907 assert_eq!(sig.type_parameters[0].name, "T");
908
909 assert_eq!(sig.parameter_types.len(), 1);
910 match &sig.parameter_types[0] {
911 TypeSignature::TypeVariable(name) => assert_eq!(name, "T"),
912 other => panic!("expected TypeVariable(T), got {other:?}"),
913 }
914
915 match &sig.return_type {
916 TypeSignature::Base(BaseType::Void) => {}
917 other => panic!("expected Void return, got {other:?}"),
918 }
919
920 assert_eq!(sig.exception_types.len(), 2);
921 match &sig.exception_types[0] {
922 TypeSignature::TypeVariable(name) => assert_eq!(name, "T"),
923 other => panic!("expected TypeVariable(T) exception, got {other:?}"),
924 }
925 match &sig.exception_types[1] {
926 TypeSignature::Class { fqn, .. } => {
927 assert_eq!(fqn, "java.io.IOException");
928 }
929 other => panic!("expected IOException, got {other:?}"),
930 }
931 }
932
933 #[test]
936 fn test_malformed_empty() {
937 assert!(parse_class_signature("").is_err());
938 }
939
940 #[test]
941 fn test_malformed_missing_semicolon() {
942 assert!(parse_field_signature("Ljava/lang/Object").is_err());
944 }
945
946 #[test]
947 fn test_malformed_unclosed_type_args() {
948 assert!(parse_field_signature("Ljava/util/List<Ljava/lang/String;;").is_err());
950 }
951
952 #[test]
953 fn test_malformed_missing_class_bound_colon() {
954 assert!(parse_class_signature("<T>Ljava/lang/Object;").is_err());
956 }
957
958 #[test]
959 fn test_malformed_trailing_input() {
960 assert!(parse_field_signature("Ljava/lang/Object;GARBAGE").is_err());
962 }
963
964 #[test]
965 fn test_malformed_method_missing_paren() {
966 assert!(parse_method_signature("V").is_err());
967 }
968
969 #[test]
972 fn test_unbounded_wildcard() {
973 let input = "Ljava/util/List<*>;";
975 let sig = parse_field_signature(input).unwrap();
976
977 match sig {
978 TypeSignature::Class {
979 fqn,
980 type_arguments,
981 } => {
982 assert_eq!(fqn, "java.util.List");
983 assert_eq!(type_arguments.len(), 1);
984 assert!(matches!(type_arguments[0], TypeArgument::Unbounded));
985 }
986 other => panic!("expected Class, got {other:?}"),
987 }
988 }
989
990 #[test]
991 fn test_method_void_return() {
992 let input = "()V";
994 let sig = parse_method_signature(input).unwrap();
995
996 assert!(sig.type_parameters.is_empty());
997 assert!(sig.parameter_types.is_empty());
998 assert!(matches!(
999 sig.return_type,
1000 TypeSignature::Base(BaseType::Void)
1001 ));
1002 assert!(sig.exception_types.is_empty());
1003 }
1004
1005 #[test]
1006 fn test_method_primitive_params() {
1007 let input = "(IDZ)J";
1009 let sig = parse_method_signature(input).unwrap();
1010
1011 assert_eq!(sig.parameter_types.len(), 3);
1012 assert!(matches!(
1013 sig.parameter_types[0],
1014 TypeSignature::Base(BaseType::Int)
1015 ));
1016 assert!(matches!(
1017 sig.parameter_types[1],
1018 TypeSignature::Base(BaseType::Double)
1019 ));
1020 assert!(matches!(
1021 sig.parameter_types[2],
1022 TypeSignature::Base(BaseType::Boolean)
1023 ));
1024 assert!(matches!(
1025 sig.return_type,
1026 TypeSignature::Base(BaseType::Long)
1027 ));
1028 }
1029
1030 #[test]
1031 fn test_empty_class_bound_with_interface_bound() {
1032 let input = "<T::Ljava/io/Serializable;>Ljava/lang/Object;";
1035 let sig = parse_class_signature(input).unwrap();
1036
1037 assert_eq!(sig.type_parameters.len(), 1);
1038 let t = &sig.type_parameters[0];
1039 assert_eq!(t.name, "T");
1040 assert!(t.class_bound.is_none());
1041 assert_eq!(t.interface_bounds.len(), 1);
1042 match &t.interface_bounds[0] {
1043 TypeSignature::Class { fqn, .. } => {
1044 assert_eq!(fqn, "java.io.Serializable");
1045 }
1046 other => panic!("expected Serializable, got {other:?}"),
1047 }
1048 }
1049
1050 #[test]
1051 fn test_type_variable_field_signature() {
1052 let input = "TT;";
1054 let sig = parse_field_signature(input).unwrap();
1055
1056 match sig {
1057 TypeSignature::TypeVariable(name) => assert_eq!(name, "T"),
1058 other => panic!("expected TypeVariable, got {other:?}"),
1059 }
1060 }
1061
1062 #[test]
1063 fn test_complex_real_world_class_signature() {
1064 let input =
1067 "<K:Ljava/lang/Object;V:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/Map<TK;TV;>;";
1068 let sig = parse_class_signature(input).unwrap();
1069
1070 assert_eq!(sig.type_parameters.len(), 2);
1071 match &sig.superclass {
1072 TypeSignature::Class {
1073 fqn,
1074 type_arguments,
1075 } => {
1076 assert_eq!(fqn, "java.lang.Object");
1077 assert!(type_arguments.is_empty());
1078 }
1079 other => panic!("expected Object superclass, got {other:?}"),
1080 }
1081 assert_eq!(sig.interfaces.len(), 1);
1082 }
1083
1084 #[test]
1085 fn test_array_of_generic_type() {
1086 let input = "([Ljava/util/List<Ljava/lang/String;>;)V";
1088 let sig = parse_method_signature(input).unwrap();
1089
1090 assert_eq!(sig.parameter_types.len(), 1);
1091 match &sig.parameter_types[0] {
1092 TypeSignature::Array(inner) => match inner.as_ref() {
1093 TypeSignature::Class {
1094 fqn,
1095 type_arguments,
1096 } => {
1097 assert_eq!(fqn, "java.util.List");
1098 assert_eq!(type_arguments.len(), 1);
1099 }
1100 other => panic!("expected List<String> inside array, got {other:?}"),
1101 },
1102 other => panic!("expected Array, got {other:?}"),
1103 }
1104 }
1105
1106 #[test]
1107 fn test_wildcard_super_bound() {
1108 let input = "Ljava/lang/Comparable<-TT;>;";
1110 let sig = parse_field_signature(input).unwrap();
1111
1112 match sig {
1113 TypeSignature::Class {
1114 fqn,
1115 type_arguments,
1116 } => {
1117 assert_eq!(fqn, "java.lang.Comparable");
1118 assert_eq!(type_arguments.len(), 1);
1119 match &type_arguments[0] {
1120 TypeArgument::Super(TypeSignature::TypeVariable(name)) => {
1121 assert_eq!(name, "T");
1122 }
1123 other => panic!("expected Super(T), got {other:?}"),
1124 }
1125 }
1126 other => panic!("expected Class, got {other:?}"),
1127 }
1128 }
1129
1130 #[test]
1131 fn test_inner_class_with_outer_type_args() {
1132 let input = "Ljava/util/Outer<Ljava/lang/String;>.Inner;";
1135 let sig = parse_field_signature(input).unwrap();
1136
1137 match sig {
1138 TypeSignature::Class {
1139 fqn,
1140 type_arguments,
1141 } => {
1142 assert_eq!(fqn, "java.util.Outer$Inner");
1143 assert!(type_arguments.is_empty());
1145 }
1146 other => panic!("expected Class, got {other:?}"),
1147 }
1148 }
1149
1150 #[test]
1151 fn test_multiple_type_params_method() {
1152 let input = "<K:Ljava/lang/Object;V:Ljava/lang/Object;>(TK;TV;)V";
1154 let sig = parse_method_signature(input).unwrap();
1155
1156 assert_eq!(sig.type_parameters.len(), 2);
1157 assert_eq!(sig.type_parameters[0].name, "K");
1158 assert_eq!(sig.type_parameters[1].name, "V");
1159 assert_eq!(sig.parameter_types.len(), 2);
1160 assert!(matches!(
1161 sig.return_type,
1162 TypeSignature::Base(BaseType::Void)
1163 ));
1164 }
1165}