Skip to main content

ferro_babe/
diagnostic.rs

1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2/// Indicates whether a recoverable parse finding is informational or erroneous.
3pub enum DiagnosticSeverity {
4    /// A non-fatal finding that does not invalidate the returned information.
5    Warning,
6    /// A decoding failure represented in a best-effort partial result.
7    Error,
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11/// Identifies the class-file area associated with a [`Diagnostic`].
12pub enum DiagnosticStage {
13    /// The class-file header.
14    Header,
15    /// The constant-pool table or an index into it.
16    ConstantPool,
17    /// A field, method, or another member structure.
18    Member,
19    /// A class, member, or code attribute.
20    Attribute,
21    /// A method's bytecode instruction stream.
22    Code,
23}
24
25#[derive(Debug, Clone, PartialEq, Eq)]
26/// A recoverable parsing finding returned with a partial [`crate::Disassembly`].
27pub struct Diagnostic {
28    severity: DiagnosticSeverity,
29    stage: DiagnosticStage,
30    offset: Option<usize>,
31    message: String,
32}
33
34impl Diagnostic {
35    pub(crate) fn from_decode_error(error: &FerroBabeError) -> Self {
36        let (stage, offset, message) = match error {
37            FerroBabeError::Decode { source } => match source {
38                ClassReadError::UnexpectedEof => {
39                    (DiagnosticStage::Member, None, source.to_string())
40                }
41                ClassReadError::InvalidConstantPoolTag(_) | ClassReadError::InvalidIndex(_) => {
42                    (DiagnosticStage::ConstantPool, None, source.to_string())
43                }
44                ClassReadError::InvalidAttribute(_) => {
45                    (DiagnosticStage::Attribute, None, source.to_string())
46                }
47                ClassReadError::InvalidOpcode { offset, .. } => {
48                    (DiagnosticStage::Code, Some(*offset), source.to_string())
49                }
50                ClassReadError::InvalidMagic(_) | ClassReadError::InvalidClassVersion(_) => {
51                    (DiagnosticStage::Header, None, source.to_string())
52                }
53                ClassReadError::Utf8Error(_) => {
54                    (DiagnosticStage::ConstantPool, None, source.to_string())
55                }
56            },
57            _ => (DiagnosticStage::Header, None, error.to_string()),
58        };
59
60        Self {
61            severity: DiagnosticSeverity::Error,
62            stage,
63            offset,
64            message,
65        }
66    }
67
68    /// Returns the severity assigned to this finding.
69    #[must_use]
70    pub fn severity(&self) -> DiagnosticSeverity {
71        self.severity
72    }
73
74    /// Returns the class-file area where this finding occurred.
75    #[must_use]
76    pub fn stage(&self) -> DiagnosticStage {
77        self.stage
78    }
79
80    /// Returns the reported byte offset when the decoder supplied one.
81    ///
82    /// Offsets for bytecode findings are relative to the method's code array.
83    #[must_use]
84    pub fn offset(&self) -> Option<usize> {
85        self.offset
86    }
87
88    /// Returns the human-readable decoder message.
89    #[must_use]
90    pub fn message(&self) -> &str {
91        &self.message
92    }
93}
94use rust_asm::error::ClassReadError;
95
96use crate::FerroBabeError;