rune/diagnostics/
warning.rs

1use core::fmt;
2
3use crate::alloc::String;
4use crate::ast::Span;
5use crate::ast::Spanned;
6use crate::SourceId;
7
8/// Warning diagnostic emitted during compilation. Warning diagnostics indicates
9/// an recoverable issues.
10#[derive(Debug)]
11pub struct WarningDiagnostic {
12    /// The id of the source where the warning happened.
13    pub(crate) source_id: SourceId,
14    /// The kind of the warning.
15    pub(crate) kind: WarningDiagnosticKind,
16}
17
18impl WarningDiagnostic {
19    /// The source id where the warning originates from.
20    pub fn source_id(&self) -> SourceId {
21        self.source_id
22    }
23
24    /// The kind of the warning.
25    #[cfg(feature = "emit")]
26    pub(crate) fn kind(&self) -> &WarningDiagnosticKind {
27        &self.kind
28    }
29
30    #[cfg(test)]
31    pub(crate) fn into_kind(self) -> WarningDiagnosticKind {
32        self.kind
33    }
34
35    /// Access context of warning, if any is available.
36    #[cfg(feature = "emit")]
37    pub(crate) fn context(&self) -> Option<Span> {
38        match &self.kind {
39            WarningDiagnosticKind::LetPatternMightPanic { context, .. }
40            | WarningDiagnosticKind::RemoveTupleCallParams { context, .. }
41            | WarningDiagnosticKind::NotUsed { context, .. }
42            | WarningDiagnosticKind::UsedDeprecated { context, .. }
43            | WarningDiagnosticKind::TemplateWithoutExpansions { context, .. } => *context,
44            _ => None,
45        }
46    }
47}
48
49impl Spanned for WarningDiagnostic {
50    /// Get the span of the warning.
51    fn span(&self) -> Span {
52        match &self.kind {
53            WarningDiagnosticKind::NotUsed { span, .. } => *span,
54            WarningDiagnosticKind::Unreachable { span, .. } => *span,
55            WarningDiagnosticKind::LetPatternMightPanic { span, .. } => *span,
56            WarningDiagnosticKind::TemplateWithoutExpansions { span, .. } => *span,
57            WarningDiagnosticKind::RemoveTupleCallParams { span, .. } => *span,
58            WarningDiagnosticKind::UnnecessarySemiColon { span, .. } => *span,
59            WarningDiagnosticKind::UsedDeprecated { span, .. } => *span,
60        }
61    }
62}
63
64impl fmt::Display for WarningDiagnostic {
65    #[inline]
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        fmt::Display::fmt(&self.kind, f)
68    }
69}
70
71impl core::error::Error for WarningDiagnostic {
72    #[inline]
73    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
74        None
75    }
76}
77
78/// The kind of a [WarningDiagnostic].
79#[derive(Debug)]
80#[allow(missing_docs)]
81#[non_exhaustive]
82pub(crate) enum WarningDiagnosticKind {
83    /// Item identified by the span is not used.
84    NotUsed {
85        /// The span that is not used.
86        span: Span,
87        /// The context in which the value was not used.
88        #[cfg_attr(not(feature = "emit"), allow(dead_code))]
89        context: Option<Span>,
90    },
91    /// Unreachable code.
92    Unreachable {
93        /// The span that is not used.
94        span: Span,
95        /// The span which caused the code to be unreachable.
96        #[cfg_attr(not(feature = "emit"), allow(dead_code))]
97        cause: Span,
98    },
99    /// Warning that an unconditional let pattern will panic if it doesn't
100    /// match.
101    LetPatternMightPanic {
102        /// The span of the pattern.
103        span: Span,
104        /// The context in which it is used.
105        #[cfg_attr(not(feature = "emit"), allow(dead_code))]
106        context: Option<Span>,
107    },
108    /// Encountered a template string without an expansion.
109    TemplateWithoutExpansions {
110        /// Span that caused the error.
111        span: Span,
112        /// The context in which it is used.
113        #[cfg_attr(not(feature = "emit"), allow(dead_code))]
114        context: Option<Span>,
115    },
116    /// Suggestion that call parameters could be removed.
117    RemoveTupleCallParams {
118        /// The span of the call.
119        span: Span,
120        /// The span of the variant being built.
121        #[cfg_attr(not(feature = "emit"), allow(dead_code))]
122        variant: Span,
123        /// The context in which it is used.
124        #[cfg_attr(not(feature = "emit"), allow(dead_code))]
125        context: Option<Span>,
126    },
127    /// An unecessary semi-colon is used.
128    UnnecessarySemiColon {
129        /// Span where the semi-colon is.
130        span: Span,
131    },
132    UsedDeprecated {
133        /// The span which is deprecated
134        span: Span,
135        /// The context in which it is used.
136        #[cfg_attr(not(feature = "emit"), allow(dead_code))]
137        context: Option<Span>,
138        /// Deprecated message.
139        message: String,
140    },
141}
142
143impl fmt::Display for WarningDiagnosticKind {
144    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145        match self {
146            WarningDiagnosticKind::NotUsed { .. } => write!(f, "Not used"),
147            WarningDiagnosticKind::Unreachable { .. } => write!(f, "Unreachable code"),
148            WarningDiagnosticKind::LetPatternMightPanic { .. } => {
149                write!(f, "Pattern might panic")
150            }
151            WarningDiagnosticKind::TemplateWithoutExpansions { .. } => write!(
152                f,
153                "Using a template string without expansions, like `Hello World`"
154            ),
155            WarningDiagnosticKind::RemoveTupleCallParams { .. } => {
156                write!(f, "Call paramters are not needed here")
157            }
158            WarningDiagnosticKind::UnnecessarySemiColon { .. } => {
159                write!(f, "Unnecessary semicolon")
160            }
161            WarningDiagnosticKind::UsedDeprecated { message, .. } => {
162                write!(f, "Used deprecated function: {message}")
163            }
164        }
165    }
166}