Skip to main content

sqry_classpath/bytecode/
generics.rs

1//! Recursive descent parser for JVM generic signatures (JVMS 4.7.9.1).
2//!
3//! The JVM stores generic type information in `Signature` attributes as compact
4//! strings following a specific grammar. This module parses those strings into
5//! the structured types defined in [`crate::stub::model`].
6//!
7//! # Grammar (JVMS 4.7.9.1)
8//!
9//! ```text
10//! ClassSignature     = FormalTypeParameters? SuperclassSignature SuperinterfaceSignature*
11//! MethodSignature    = FormalTypeParameters? '(' TypeSignature* ')' ReturnType ThrowsSignature*
12//! FormalTypeParameters = '<' FormalTypeParameter+ '>'
13//! FormalTypeParameter = Identifier ClassBound InterfaceBound*
14//! ClassBound         = ':' FieldTypeSignature?
15//! InterfaceBound     = ':' FieldTypeSignature
16//! FieldTypeSignature = ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature
17//! ClassTypeSignature = 'L' (Identifier '/')* Identifier TypeArguments? ('.' Identifier TypeArguments?)* ';'
18//! TypeArguments      = '<' TypeArgument+ '>'
19//! TypeArgument       = WildcardIndicator? FieldTypeSignature | '*'
20//! WildcardIndicator  = '+' | '-'
21//! TypeVariableSignature = 'T' Identifier ';'
22//! ArrayTypeSignature = '[' TypeSignature
23//! TypeSignature      = FieldTypeSignature | BaseType
24//! ReturnType         = TypeSignature | 'V'
25//! ThrowsSignature    = '^' ClassTypeSignature | '^' TypeVariableSignature
26//! BaseType           = 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z'
27//! ```
28//!
29//! # Examples
30//!
31//! ```
32//! use sqry_classpath::bytecode::generics::{parse_class_signature, parse_method_signature, parse_field_signature};
33//!
34//! // HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>
35//! let sig = "<K:Ljava/lang/Object;V:Ljava/lang/Object;>Ljava/util/AbstractMap<TK;TV;>;Ljava/util/Map<TK;TV;>;";
36//! let parsed = parse_class_signature(sig).unwrap();
37//! assert_eq!(parsed.type_parameters.len(), 2);
38//!
39//! // <T:Object>(T)T
40//! let method_sig = "<T:Ljava/lang/Object;>(TT;)TT;";
41//! let parsed = parse_method_signature(method_sig).unwrap();
42//! assert_eq!(parsed.type_parameters.len(), 1);
43//!
44//! // List<String>
45//! let field_sig = "Ljava/util/List<Ljava/lang/String;>;";
46//! let parsed = parse_field_signature(field_sig).unwrap();
47//! ```
48
49use crate::stub::model::{
50    BaseType, GenericClassSignature, GenericMethodSignature, TypeArgument, TypeParameterStub,
51    TypeSignature,
52};
53use crate::{ClasspathError, ClasspathResult};
54
55// ---------------------------------------------------------------------------
56// Public API
57// ---------------------------------------------------------------------------
58
59/// Parse a class-level generic signature (JVMS 4.7.9.1 `ClassSignature`).
60///
61/// The input is the raw string from the `Signature` attribute of a class file.
62///
63/// # Example
64///
65/// ```text
66/// <K:Ljava/lang/Object;V:Ljava/lang/Object;>Ljava/util/AbstractMap<TK;TV;>;Ljava/util/Map<TK;TV;>;
67/// ```
68///
69/// # Errors
70///
71/// Returns `ClasspathError::BytecodeParseError` if the signature is malformed.
72pub 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
79/// Parse a method-level generic signature (JVMS 4.7.9.1 `MethodSignature`).
80///
81/// # Example
82///
83/// ```text
84/// <T:Ljava/lang/Object;>(TT;)TT;
85/// ```
86///
87/// # Errors
88///
89/// Returns `ClasspathError::BytecodeParseError` if the signature is malformed.
90pub 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
97/// Parse a field-level type signature (JVMS 4.7.9.1 `FieldTypeSignature`).
98///
99/// This handles class type signatures, array type signatures, and type variable
100/// signatures. It does **not** accept bare base types.
101///
102/// # Example
103///
104/// ```text
105/// Ljava/util/List<Ljava/lang/String;>;
106/// ```
107///
108/// # Errors
109///
110/// Returns `ClasspathError::BytecodeParseError` if the signature is malformed.
111pub 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
118// ---------------------------------------------------------------------------
119// Parser internals
120// ---------------------------------------------------------------------------
121
122/// Byte-level cursor over a JVM generic signature string.
123///
124/// All positions and reads operate on the raw UTF-8 bytes. JVM signatures are
125/// specified as Modified UTF-8 in the constant pool, but the signature grammar
126/// itself only uses ASCII characters for delimiters. Identifiers (class names,
127/// type parameter names) may theoretically contain non-ASCII characters, but in
128/// practice they are ASCII.
129struct 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    // -- Primitives ----------------------------------------------------------
143
144    /// Peek at the current byte without advancing.
145    fn peek(&self) -> Option<u8> {
146        self.input.get(self.pos).copied()
147    }
148
149    /// Advance the cursor by one byte.
150    fn advance(&mut self) {
151        self.pos += 1;
152    }
153
154    /// Consume the expected byte or return an error.
155    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    /// Assert that the entire input has been consumed.
173    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    /// Read an identifier — a sequence of bytes terminated by one of the
187    /// delimiter characters used in the signature grammar.
188    ///
189    /// Delimiters: `:`, `;`, `<`, `>`, `.`, `/`, `(`, `)`, `[`, `^`
190    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        // Safety: JVM identifiers are valid UTF-8 (Modified UTF-8 subset).
204        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    /// Build a `ClasspathError::BytecodeParseError` with the full input as
210    /// context.
211    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    // -- Grammar productions -------------------------------------------------
220
221    /// ```text
222    /// ClassSignature = FormalTypeParameters? SuperclassSignature SuperinterfaceSignature*
223    /// ```
224    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        // SuperclassSignature = ClassTypeSignature
232        let superclass = self.parse_class_type_signature()?;
233
234        // SuperinterfaceSignature* = ClassTypeSignature*
235        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    /// ```text
248    /// MethodSignature = FormalTypeParameters? '(' TypeSignature* ')' ReturnType ThrowsSignature*
249    /// ```
250    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        // ReturnType = TypeSignature | 'V'
265        let return_type = self.parse_return_type()?;
266
267        // ThrowsSignature*
268        let mut exception_types = Vec::new();
269        while self.peek() == Some(b'^') {
270            self.advance(); // consume '^'
271            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    /// ```text
283    /// FormalTypeParameters = '<' FormalTypeParameter+ '>'
284    /// FormalTypeParameter  = Identifier ClassBound InterfaceBound*
285    /// ClassBound           = ':' FieldTypeSignature?
286    /// InterfaceBound       = ':' FieldTypeSignature
287    /// ```
288    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        // ClassBound = ':' FieldTypeSignature?
305        self.expect(b':')?;
306        let class_bound = if is_field_type_start(self.peek()) {
307            Some(self.parse_field_type_signature()?)
308        } else {
309            // Empty class bound — implicit Object bound.
310            None
311        };
312
313        // InterfaceBound* = (':' FieldTypeSignature)*
314        let mut interface_bounds = Vec::new();
315        while self.peek() == Some(b':') {
316            self.advance(); // consume ':'
317            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    /// ```text
328    /// FieldTypeSignature = ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature
329    /// ```
330    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    /// ```text
346    /// ClassTypeSignature = 'L' PackageSpecifier* SimpleClassTypeSignature
347    ///                      ClassTypeSignatureSuffix* ';'
348    /// PackageSpecifier   = Identifier '/'
349    /// SimpleClassTypeSignature = Identifier TypeArguments?
350    /// ClassTypeSignatureSuffix = '.' SimpleClassTypeSignature
351    /// ```
352    ///
353    /// We read `L`, then accumulate `Identifier/` segments for the package,
354    /// then the final `Identifier` (class name), optional type arguments,
355    /// then `ClassTypeSignatureSuffix*`, then `;`.
356    ///
357    /// Inner class suffixes (`.InnerName<Args>`) are appended to the FQN
358    /// with `$` separators (matching JVM internal convention) and the
359    /// outermost type arguments are replaced by the inner class's arguments.
360    fn parse_class_type_signature(&mut self) -> ClasspathResult<TypeSignature> {
361        self.expect(b'L')?;
362
363        // Read package/class segments separated by '/'.
364        // The last segment before a non-'/' delimiter is the class name.
365        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(); // consume '/'
371            } else {
372                break;
373            }
374        }
375
376        // Build FQN: replace '/' separators with '.' for the package.
377        let fqn = segments.join(".");
378
379        // TypeArguments?
380        let mut type_arguments = if self.peek() == Some(b'<') {
381            self.parse_type_arguments()?
382        } else {
383            Vec::new()
384        };
385
386        // ClassTypeSignatureSuffix* = ('.' SimpleClassTypeSignature)*
387        let mut full_fqn = fqn;
388        while self.peek() == Some(b'.') {
389            self.advance(); // consume '.'
390            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    /// ```text
408    /// TypeArguments = '<' TypeArgument+ '>'
409    /// TypeArgument  = WildcardIndicator? FieldTypeSignature | '*'
410    /// WildcardIndicator = '+' | '-'
411    /// ```
412    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    /// ```text
449    /// TypeVariableSignature = 'T' Identifier ';'
450    /// ```
451    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    /// ```text
459    /// ArrayTypeSignature = '[' TypeSignature
460    /// ```
461    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    /// ```text
468    /// TypeSignature = FieldTypeSignature | BaseType
469    /// BaseType = 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z'
470    /// ```
471    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    /// ```text
487    /// ReturnType = TypeSignature | 'V'
488    /// ```
489    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    /// Parse the target of a throws signature (after the `^` has been consumed).
499    ///
500    /// ```text
501    /// ThrowsSignature = '^' ClassTypeSignature | '^' TypeVariableSignature
502    /// ```
503    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
516// ---------------------------------------------------------------------------
517// Helpers
518// ---------------------------------------------------------------------------
519
520/// Returns `true` if the byte is a delimiter in the signature grammar.
521fn is_delimiter(b: u8) -> bool {
522    matches!(
523        b,
524        b':' | b';' | b'<' | b'>' | b'.' | b'/' | b'(' | b')' | b'[' | b'^'
525    )
526}
527
528/// Returns `true` if the byte can start a `FieldTypeSignature`.
529fn is_field_type_start(b: Option<u8>) -> bool {
530    matches!(b, Some(b'L' | b'[' | b'T'))
531}
532
533/// Returns `true` if the byte is a JVM `BaseType` descriptor character.
534fn 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
538/// Convert a base type descriptor byte to the corresponding `BaseType`.
539fn 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// ---------------------------------------------------------------------------
557// Tests
558// ---------------------------------------------------------------------------
559
560#[cfg(test)]
561mod tests {
562    use super::*;
563
564    // -- Test 1: HashMap<K,V> class signature --------------------------------
565
566    #[test]
567    fn test_hashmap_class_signature() {
568        // <K:Ljava/lang/Object;V:Ljava/lang/Object;>Ljava/util/AbstractMap<TK;TV;>;Ljava/util/Map<TK;TV;>;
569        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        // Type parameters K, V
573        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        // Superclass: AbstractMap<K, V>
599        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        // Interfaces: Map<K, V>
617        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 2: Wildcard with upper bound -----------------------------------
631
632    #[test]
633    fn test_wildcard_extends() {
634        // List<? extends Number> => Ljava/util/List<+Ljava/lang/Number;>;
635        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 3: Nested generics — Map<String, List<? super Integer>> --------
657
658    #[test]
659    fn test_nested_generics() {
660        // Map<String, List<? super Integer>>
661        // => Ljava/util/Map<Ljava/lang/String;Ljava/util/List<-Ljava/lang/Integer;>;>;
662        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                // First arg: String
674                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                // Second arg: List<? super Integer>
682                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 4: Bounded type parameter with self-reference ------------------
704
705    #[test]
706    fn test_bounded_type_parameter_self_reference() {
707        // <T:Ljava/lang/Comparable<TT;>;>Ljava/lang/Object;
708        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 5: Method signature with type params and return type ------------
734
735    #[test]
736    fn test_method_signature_with_type_params() {
737        // <T:Ljava/lang/Object;>(TT;Ljava/util/List<TT;>;)TT;
738        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 6: Array type in signature -------------------------------------
769
770    #[test]
771    fn test_array_type() {
772        // String[] => [Ljava/lang/String;
773        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        // int[][] => [[I
790        // This is a TypeSignature, not a FieldTypeSignature, so we test via method sig
791        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 7: Multiple interface bounds ------------------------------------
808
809    #[test]
810    fn test_multiple_interface_bounds() {
811        // <T:Ljava/lang/Object;:Ljava/io/Serializable;:Ljava/lang/Comparable<TT;>;>Ljava/lang/Object;
812        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        // Class bound: Object
820        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        // Interface bounds: Serializable, Comparable<T>
828        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 8: Inner class signatures (ClassTypeSignatureSuffix) ------------
848
849    #[test]
850    fn test_inner_class_signature() {
851        // Map.Entry<K, V> => Ljava/util/Map.Entry<TK;TV;>;
852        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                // Inner class FQN uses $ separator
861                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        // Outer.Middle.Inner => Ljava/util/Outer.Middle.Inner;
883        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 9: Throws signatures in method signature -----------------------
899
900    #[test]
901    fn test_method_with_throws() {
902        // <T:Ljava/lang/Exception;>(TT;)V^TT;^Ljava/io/IOException;
903        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 10: Malformed signatures return Err ----------------------------
934
935    #[test]
936    fn test_malformed_empty() {
937        assert!(parse_class_signature("").is_err());
938    }
939
940    #[test]
941    fn test_malformed_missing_semicolon() {
942        // Missing trailing ';'
943        assert!(parse_field_signature("Ljava/lang/Object").is_err());
944    }
945
946    #[test]
947    fn test_malformed_unclosed_type_args() {
948        // Missing '>'
949        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        // Type parameter without ':'
955        assert!(parse_class_signature("<T>Ljava/lang/Object;").is_err());
956    }
957
958    #[test]
959    fn test_malformed_trailing_input() {
960        // Valid signature followed by garbage
961        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    // -- Additional edge cases -----------------------------------------------
970
971    #[test]
972    fn test_unbounded_wildcard() {
973        // List<?> => Ljava/util/List<*>;
974        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        // ()V — no params, void return
993        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        // (IDZ)J — int, double, boolean -> long
1008        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        // <T::Ljava/io/Serializable;>Ljava/lang/Object;
1033        // Empty class bound (implicit Object), one interface bound
1034        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        // TT; — bare type variable reference
1053        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        // AbstractMap<K,V> — class that implements multiple parameterized interfaces
1065        // Signature: <K:Ljava/lang/Object;V:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/Map<TK;TV;>;
1066        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        // List<String>[] in method param => ([Ljava/util/List<Ljava/lang/String;>;)V
1087        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        // Comparable<? super T> => Ljava/lang/Comparable<-TT;>;
1109        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        // Outer<String>.Inner => Ljava/util/Outer<Ljava/lang/String;>.Inner;
1133        // The outer type args are present but inner has none, so final type_arguments is empty
1134        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                // Inner class has no type args of its own, so empty
1144                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        // <K:Ljava/lang/Object;V:Ljava/lang/Object;>(TK;TV;)V
1153        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}