1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
use runestick::Span;

/// Compilation warning.
#[derive(Debug, Clone, Copy)]
pub struct Warning {
    /// The id of the source where the id happened.
    pub source_id: usize,
    /// The kind of the warning.
    pub kind: WarningKind,
}

/// Compilation warning kind.
#[derive(Debug, Clone, Copy)]
pub enum WarningKind {
    /// Item identified by the span is not used.
    NotUsed {
        /// The span that is not used.
        span: Span,
        /// The context in which the value was not used.
        context: Option<Span>,
    },
    /// Warning that an unconditional let pattern will panic if it doesn't
    /// match.
    LetPatternMightPanic {
        /// The span of the pattern.
        span: Span,
        /// The context in which it is used.
        context: Option<Span>,
    },
    /// Encountered a template string without an expansion.
    TemplateWithoutExpansions {
        /// Span that caused the error.
        span: Span,
        /// The context in which it is used.
        context: Option<Span>,
    },
    /// Suggestion that call parameters could be removed.
    RemoveTupleCallParams {
        /// The span of the call.
        span: Span,
        /// The span of the variant being built.
        variant: Span,
        /// The context in which it is used.
        context: Option<Span>,
    },
    /// An unecessary semi-colon is used.
    UnecessarySemiColon {
        /// Span where the semi-colon is.
        span: Span,
    },
}
/// Compilation warnings.
#[derive(Debug, Clone, Default)]
pub struct Warnings {
    warnings: Option<Vec<Warning>>,
}

impl Warnings {
    /// Construct a new, empty collection of compilation warnings that is
    /// disabled, i.e. any warnings added to it will be ignored.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use rune::Warnings;
    /// use runestick::Span;
    ///
    /// let mut warnings = Warnings::disabled();
    /// assert!(warnings.is_empty());
    /// warnings.not_used(0, Span::empty(), None);
    /// ```
    pub fn disabled() -> Self {
        Self { warnings: None }
    }

    /// Construct a new, empty collection of compilation warnings.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use rune::{Warnings, Warning, WarningKind};
    /// use runestick::Span;
    ///
    /// let mut warnings = Warnings::new();
    /// assert!(warnings.is_empty());
    /// warnings.not_used(0, Span::empty(), None);
    /// assert!(!warnings.is_empty());
    ///
    /// assert!(matches!(warnings.iter().next(), Some(Warning { source_id: 0, kind: WarningKind::NotUsed { .. } })));
    /// ```
    pub fn new() -> Self {
        Self {
            warnings: Some(Vec::new()),
        }
    }

    /// Indicate if there are warnings or not.
    pub fn is_empty(&self) -> bool {
        self.warnings.as_ref().map(Vec::is_empty).unwrap_or(true)
    }

    /// Get an iterator over all the warnings.
    pub fn iter(&self) -> impl Iterator<Item = &'_ Warning> {
        self.into_iter()
    }

    /// Indicate that a value is produced but never used.
    pub fn not_used(&mut self, source_id: usize, span: Span, context: Option<Span>) {
        if let Some(w) = &mut self.warnings {
            w.push(Warning {
                source_id,
                kind: WarningKind::NotUsed { span, context },
            });
        }
    }

    /// Indicate that a binding pattern might panic.
    ///
    /// Like `let (a, b) = value`.
    pub fn let_pattern_might_panic(&mut self, source_id: usize, span: Span, context: Option<Span>) {
        if let Some(w) = &mut self.warnings {
            w.push(Warning {
                source_id,
                kind: WarningKind::LetPatternMightPanic { span, context },
            });
        }
    }

    /// Indicate that we encountered a template string without any expansion
    /// groups.
    ///
    /// Like `` `Hello` ``.
    pub fn template_without_expansions(
        &mut self,
        source_id: usize,
        span: Span,
        context: Option<Span>,
    ) {
        if let Some(w) = &mut self.warnings {
            w.push(Warning {
                source_id,
                kind: WarningKind::TemplateWithoutExpansions { span, context },
            });
        }
    }

    /// Add a warning indicating that the parameters of an empty tuple can be
    /// removed when creating it.
    ///
    /// Like `None()`.
    pub fn remove_tuple_call_parens(
        &mut self,
        source_id: usize,
        span: Span,
        variant: Span,
        context: Option<Span>,
    ) {
        if let Some(w) = &mut self.warnings {
            w.push(Warning {
                source_id,
                kind: WarningKind::RemoveTupleCallParams {
                    span,
                    variant,
                    context,
                },
            });
        }
    }

    /// Add a warning about an unecessary semi-colon.
    pub fn uneccessary_semi_colon(&mut self, source_id: usize, span: Span) {
        if let Some(w) = &mut self.warnings {
            w.push(Warning {
                source_id,
                kind: WarningKind::UnecessarySemiColon { span },
            });
        }
    }
}

impl<'a> IntoIterator for &'a Warnings {
    type IntoIter = std::slice::Iter<'a, Warning>;
    type Item = &'a Warning;

    fn into_iter(self) -> Self::IntoIter {
        if let Some(w) = &self.warnings {
            w.iter()
        } else {
            (&[]).iter()
        }
    }
}