Skip to main content

java_bin_name/
method.rs

1use core::fmt::{Debug, Display};
2
3use alloc::{boxed::Box, vec::Vec};
4use smallvec::SmallVec;
5
6use crate::{Cursor, Parse, TypeParameter, TypeSignature, UnknownTypeTag, ty::FieldType};
7
8/// Error thrown when parsing a method descriptor.
9#[derive(Debug, Clone)]
10#[non_exhaustive]
11pub enum InvalidMethodDescriptor {
12    /// Brackets not exist or not enclosed.
13    BrokenBrackets,
14    /// Error when parsing field type.
15    UnknownFieldTy(UnknownTypeTag),
16}
17
18impl core::error::Error for InvalidMethodDescriptor {}
19
20impl From<UnknownTypeTag> for InvalidMethodDescriptor {
21    fn from(value: UnknownTypeTag) -> Self {
22        Self::UnknownFieldTy(value)
23    }
24}
25
26impl Display for InvalidMethodDescriptor {
27    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
28        match self {
29            Self::BrokenBrackets => write!(f, "broken brackets"),
30            Self::UnknownFieldTy(unknown_field_ty) => {
31                write!(f, "{unknown_field_ty}")
32            }
33        }
34    }
35}
36
37/// Descriptor of a method despite of its signature.
38///
39/// See [JVMS 4.3.3](https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.3.3).
40#[derive(Clone, PartialEq, Eq, Hash)]
41pub struct MethodDescriptor<'a> {
42    /// Zero or more parameter descriptors, representing the types of parameters that the method takes.
43    pub params: SmallVec<[FieldType<'a>; 4]>,
44    /// The return descriptor.
45    pub ret: MethodReturnDescriptor<'a>,
46}
47
48impl Display for MethodDescriptor<'_> {
49    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
50        write!(f, "(")?;
51        for param in &self.params {
52            write!(f, "{param}")?;
53        }
54        write!(f, "){}", self.ret)
55    }
56}
57
58impl<'a> Parse<'a> for MethodDescriptor<'a> {
59    type Error = InvalidMethodDescriptor;
60
61    fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
62        if cursor.get_char() != '(' {
63            return Err(InvalidMethodDescriptor::BrokenBrackets);
64        }
65        let mut params_raw = Cursor::new(cursor.try_advance(|s| {
66            s.split_once(')')
67                .ok_or(InvalidMethodDescriptor::BrokenBrackets)
68        })?);
69        let mut params = SmallVec::new();
70        while !params_raw.get().is_empty() {
71            params.push(FieldType::parse_from(&mut params_raw)?);
72        }
73        Ok(Self {
74            params,
75            ret: MethodReturnDescriptor::parse_from(cursor)?,
76        })
77    }
78}
79
80/// Method return type.
81#[derive(Clone, PartialEq, Eq, Hash)]
82pub enum MethodReturnDescriptor<'a> {
83    /// Represents to `VoidDescriptor` in JVMS.
84    Void,
85    /// Valid return type.
86    Type(FieldType<'a>),
87}
88
89impl Display for MethodReturnDescriptor<'_> {
90    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
91        match self {
92            MethodReturnDescriptor::Void => write!(f, "V"),
93            MethodReturnDescriptor::Type(field_ty) => write!(f, "{field_ty}"),
94        }
95    }
96}
97
98impl<'a> Parse<'a> for MethodReturnDescriptor<'a> {
99    type Error = UnknownTypeTag;
100
101    fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
102        if cursor.get().chars().next().is_some_and(|c| c == 'V') {
103            cursor.advance_by('V'.len_utf8());
104            Ok(Self::Void)
105        } else {
106            FieldType::parse_from(cursor).map(Self::Type)
107        }
108    }
109}
110
111impl Debug for MethodReturnDescriptor<'_> {
112    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
113        match self {
114            Self::Void => write!(f, "void"),
115            Self::Type(ty) => Debug::fmt(ty, f),
116        }
117    }
118}
119
120impl Debug for MethodDescriptor<'_> {
121    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
122        write!(f, "method(")?;
123        let mut it = self.params.iter();
124        if let Some(first) = it.next() {
125            Debug::fmt(first, f)?;
126        }
127        for param in it {
128            write!(f, ", ")?;
129            Debug::fmt(param, f)?;
130        }
131        write!(f, ") -> ")?;
132        Debug::fmt(&self.ret, f)
133    }
134}
135
136/// Signature of a method declaration.
137#[derive(PartialEq, Eq, Clone)]
138pub struct MethodSignature<'a> {
139    /// Generic parameters.
140    pub params: SmallVec<[TypeParameter<'a>; 1]>,
141    /// Method arguments.
142    pub args: SmallVec<[TypeSignature<'a>; 2]>,
143    /// Return type of the method.
144    pub result: MethodReturnSignature<'a>,
145    /// Exceptions to be thrown.
146    pub throws: Box<[TypeSignature<'a>]>,
147}
148
149/// Result section in a method signature.
150#[derive(PartialEq, Eq, Clone)]
151pub enum MethodReturnSignature<'a> {
152    /// No return value.
153    Void,
154    /// Returns something.
155    Type(TypeSignature<'a>),
156}
157
158/// Errors encountered while parsing a method signature.
159#[derive(Debug, Clone)]
160#[non_exhaustive]
161pub enum InvalidMethodSignature {
162    /// Unclosed angles.
163    UnclosedAngles,
164    /// Unclosed brackets.
165    UnclosedBrackets,
166    /// Unknown type signature tag.
167    UnknownTypeTag(UnknownTypeTag),
168    /// Expected `ReferenceTypeSignature`.
169    ExpectedReference,
170    /// Expected left bracket.
171    ExpectedBracket,
172    /// Expected `ClassTypeSignature` or `TypeVariableSignature`.
173    ExpectedClassOrTypeVar,
174}
175
176impl<'a> Parse<'a> for MethodSignature<'a> {
177    type Error = InvalidMethodSignature;
178
179    fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
180        let mut params = SmallVec::new();
181        if cursor.0.starts_with('<') {
182            cursor.get_char();
183            let contents = cursor.try_advance(|s| {
184                crate::angle_safe_split(s, &['>']).ok_or(InvalidMethodSignature::UnclosedAngles)
185            })?;
186            cursor.get_char();
187            let mut contents = Cursor(contents);
188            crate::parse_type_params(&mut contents, |param| params.push(param))?;
189        }
190
191        let mut args = SmallVec::new();
192        if cursor.get_char() != '(' {
193            return Err(InvalidMethodSignature::ExpectedBracket);
194        }
195        let contents = cursor.try_advance(|s| {
196            // this is safe since there won't be any other right bracket.
197            s.split_once(')')
198                .ok_or(InvalidMethodSignature::UnclosedBrackets)
199        })?;
200        let mut contents = Cursor(contents);
201        while !contents.0.is_empty() {
202            args.push(TypeSignature::parse_from(&mut contents)?);
203        }
204
205        let result = MethodReturnSignature::parse_from(cursor)?;
206
207        let mut throws = Vec::new();
208        while !cursor.0.is_empty() && cursor.get_char() == '^' {
209            let exception = TypeSignature::parse_from(cursor)?;
210            if !matches!(
211                exception,
212                TypeSignature::Class { .. } | TypeSignature::Type(_)
213            ) {
214                return Err(InvalidMethodSignature::ExpectedClassOrTypeVar);
215            }
216            throws.push(exception);
217        }
218
219        Ok(Self {
220            params,
221            args,
222            result,
223            throws: throws.into(),
224        })
225    }
226}
227
228impl Display for MethodSignature<'_> {
229    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
230        if !self.params.is_empty() {
231            crate::display_type_params(&self.params, f)?;
232        }
233        write!(f, "(")?;
234        for arg in &self.args {
235            write!(f, "{arg}")?;
236        }
237        write!(f, "){}", self.result)?;
238        for thrown in &self.throws {
239            write!(f, "^{}", thrown)?;
240        }
241        Ok(())
242    }
243}
244
245impl<'a> Parse<'a> for MethodReturnSignature<'a> {
246    type Error = UnknownTypeTag;
247
248    fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
249        if cursor.0.starts_with('V') {
250            cursor.advance_by(1);
251            Ok(Self::Void)
252        } else {
253            TypeSignature::parse_from(cursor).map(Self::Type)
254        }
255    }
256}
257
258impl Display for MethodReturnSignature<'_> {
259    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
260        match self {
261            MethodReturnSignature::Void => write!(f, "V"),
262            MethodReturnSignature::Type(sig) => write!(f, "{sig}"),
263        }
264    }
265}
266
267impl Display for InvalidMethodSignature {
268    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
269        match self {
270            Self::UnclosedAngles => write!(f, "unclosed angles"),
271            Self::UnclosedBrackets => write!(f, "unclosed brackets"),
272            Self::UnknownTypeTag(err) => write!(f, "{err}"),
273            Self::ExpectedReference => {
274                write!(f, "expected type signature to be `ReferenceTypeSignature`")
275            }
276            Self::ExpectedBracket => write!(f, "expected left bracket"),
277            Self::ExpectedClassOrTypeVar => write!(
278                f,
279                "expected exception signature to be either `ClassTypeSignature` or `TypeVariableSignature`"
280            ),
281        }
282    }
283}
284
285impl core::error::Error for InvalidMethodSignature {
286    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
287        match self {
288            Self::UnknownTypeTag(err) => Some(err),
289            _ => None,
290        }
291    }
292}
293
294impl From<UnknownTypeTag> for InvalidMethodSignature {
295    fn from(value: UnknownTypeTag) -> Self {
296        Self::UnknownTypeTag(value)
297    }
298}
299
300impl From<crate::ParseTypeParamsError> for InvalidMethodSignature {
301    fn from(value: crate::ParseTypeParamsError) -> Self {
302        match value {
303            crate::ParseTypeParamsError::UnknownTypeTag(err) => Self::UnknownTypeTag(err),
304            crate::ParseTypeParamsError::ExpectedReference => Self::ExpectedReference,
305        }
306    }
307}
308
309impl Debug for MethodSignature<'_> {
310    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
311        if !self.params.is_empty() {
312            write!(f, "<")?;
313            let mut it = self.params.iter().peekable();
314            while let Some(param) = it.next() {
315                write!(f, "{param:?}")?;
316                if it.peek().is_some() {
317                    write!(f, ", ")?;
318                }
319            }
320            write!(f, ">::")?;
321        }
322        write!(f, "(")?;
323        let mut it = self.args.iter().peekable();
324        while let Some(arg) = it.next() {
325            write!(f, "{arg:?}")?;
326            if it.peek().is_some() {
327                write!(f, ", ")?;
328            }
329        }
330        write!(f, ") -> {:?}", self.result)?;
331        if !self.throws.is_empty() {
332            write!(f, " throws ")?;
333            let mut it = self.throws.iter().peekable();
334            while let Some(exception) = it.next() {
335                write!(f, "{exception:?}")?;
336                if it.peek().is_some() {
337                    write!(f, ", ")?;
338                }
339            }
340        }
341        Ok(())
342    }
343}
344
345impl Debug for MethodReturnSignature<'_> {
346    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
347        match self {
348            MethodReturnSignature::Void => write!(f, "void"),
349            MethodReturnSignature::Type(ty) => write!(f, "{ty:?}"),
350        }
351    }
352}
353
354#[cfg(test)]
355mod tests {
356    use alloc::boxed::Box;
357    use smallvec::SmallVec;
358
359    use crate::{
360        FieldType, MethodDescriptor, MethodReturnDescriptor, MethodReturnSignature,
361        MethodSignature, PrimitiveType, TypeParameter, TypeSignature, parse, validate_rw,
362    };
363
364    #[test]
365    fn return_desc_void() {
366        assert_eq!(
367            parse::<'_, MethodReturnDescriptor<'_>>("V").unwrap(),
368            MethodReturnDescriptor::Void
369        );
370        validate_rw::<'_, MethodReturnDescriptor<'_>>("V");
371    }
372
373    #[test]
374    fn return_desc_primitive() {
375        assert_eq!(
376            parse::<'_, MethodReturnDescriptor<'_>>("I").unwrap(),
377            MethodReturnDescriptor::Type(FieldType::Primitive(PrimitiveType::Int))
378        );
379        validate_rw::<'_, MethodReturnDescriptor<'_>>("I");
380    }
381
382    #[test]
383    fn empty_to_void() {
384        assert_eq!(
385            parse::<'_, MethodDescriptor<'_>>("()V").unwrap(),
386            MethodDescriptor {
387                params: SmallVec::new(),
388                ret: MethodReturnDescriptor::Void
389            }
390        );
391        validate_rw::<'_, MethodDescriptor<'_>>("()V");
392    }
393
394    #[test]
395    fn mixed() {
396        assert_eq!(
397            parse::<'_, MethodDescriptor<'_>>(
398                "(I[BLjava/lang/String;Ljava/lang/Object;Z)[Ljava/lang/String;"
399            )
400            .unwrap(),
401            MethodDescriptor {
402                params: smallvec::smallvec![
403                    FieldType::Primitive(PrimitiveType::Int),
404                    FieldType::Array(Box::new(FieldType::Primitive(PrimitiveType::Byte))),
405                    FieldType::Class("java/lang/String"),
406                    FieldType::Class("java/lang/Object"),
407                    FieldType::Primitive(PrimitiveType::Boolean),
408                ],
409                ret: MethodReturnDescriptor::Type(FieldType::Array(Box::new(FieldType::Class(
410                    "java/lang/String"
411                ))))
412            }
413        );
414        validate_rw::<'_, MethodDescriptor<'_>>(
415            "(I[BLjava/lang/String;Ljava/lang/Object;Z)[Ljava/lang/String;",
416        );
417    }
418
419    #[test]
420    fn method_sig() {
421        assert_eq!(
422            parse::<'_, MethodSignature<'_>>(
423                "(Ljava/lang/String;I)V^Ljava/io/IOException;^Ljava/lang/SecurityException;"
424            )
425            .unwrap(),
426            MethodSignature {
427                params: SmallVec::new(),
428                args: smallvec::smallvec![
429                    TypeSignature::Class {
430                        sig: crate::ReducedClassTypeSignature {
431                            name: "java/lang/String",
432                            args: SmallVec::new()
433                        },
434                        suffix: None
435                    },
436                    TypeSignature::Primitive(PrimitiveType::Int)
437                ],
438                result: MethodReturnSignature::Void,
439                throws: Box::new([
440                    TypeSignature::Class {
441                        sig: crate::ReducedClassTypeSignature {
442                            name: "java/io/IOException",
443                            args: SmallVec::new()
444                        },
445                        suffix: None
446                    },
447                    TypeSignature::Class {
448                        sig: crate::ReducedClassTypeSignature {
449                            name: "java/lang/SecurityException",
450                            args: SmallVec::new()
451                        },
452                        suffix: None
453                    },
454                ])
455            }
456        );
457        validate_rw::<'_, MethodSignature<'_>>(
458            "(Ljava/lang/String;I)V^Ljava/io/IOException;^Ljava/lang/SecurityException;",
459        );
460
461        assert_eq!(
462            parse::<'_, MethodSignature<'_>>("<T:Ljava/lang/Exception;>(TT;)TT;^TT;").unwrap(),
463            MethodSignature {
464                params: smallvec::smallvec![TypeParameter {
465                    name: "T",
466                    bound_class: Some(TypeSignature::Class {
467                        sig: crate::ReducedClassTypeSignature {
468                            name: "java/lang/Exception",
469                            args: SmallVec::new()
470                        },
471                        suffix: None
472                    }),
473                    bound_interface: Box::new([])
474                }],
475                args: smallvec::smallvec![TypeSignature::Type("T")],
476                result: MethodReturnSignature::Type(TypeSignature::Type("T")),
477                throws: Box::new([TypeSignature::Type("T")])
478            }
479        );
480        validate_rw::<'_, MethodSignature<'_>>("<T:Ljava/lang/Exception;>(TT;)TT;^TT;");
481    }
482}