selene_lib/lints/
must_use.rs

1use crate::standard_library::{Field, FieldKind};
2
3use super::*;
4use std::convert::Infallible;
5
6pub struct MustUseLint;
7
8impl Lint for MustUseLint {
9    type Config = ();
10    type Error = Infallible;
11
12    const SEVERITY: Severity = Severity::Warning;
13    const LINT_TYPE: LintType = LintType::Correctness;
14
15    fn new(_: Self::Config) -> Result<Self, Self::Error> {
16        Ok(MustUseLint)
17    }
18
19    fn pass(
20        &self,
21        _: &Ast,
22        Context {
23            standard_library, ..
24        }: &Context,
25        AstContext { scope_manager, .. }: &AstContext,
26    ) -> Vec<Diagnostic> {
27        let mut diagnostics = Vec::new();
28
29        for (_, function_call_stmt) in scope_manager.function_calls.iter() {
30            let function_behavior =
31                match standard_library.find_global(&function_call_stmt.call_name_path) {
32                    Some(Field {
33                        field_kind: FieldKind::Function(function_behavior),
34                        ..
35                    }) => function_behavior,
36                    _ => continue,
37                };
38
39            if !function_behavior.must_use {
40                continue;
41            }
42
43            diagnostics.push(Diagnostic::new(
44                "must_use",
45                format!(
46                    "unused return value of `{}` must be used",
47                    // TODO: This is wrong for methods
48                    function_call_stmt.call_name_path.join(".")
49                ),
50                Label::new(function_call_stmt.call_prefix_range),
51            ));
52        }
53
54        diagnostics
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::{super::test_util::test_lint, *};
61
62    #[test]
63    fn test_must_use() {
64        test_lint(MustUseLint::new(()).unwrap(), "must_use", "must_use");
65    }
66}