Skip to main content

grip/
function_purity.rs

1// Copyright 2026 Umberto Gotti <umberto.gotti@umbertogotti.dev>
2// Licensed under the MIT License
3// SPDX-License-Identifier: MIT
4
5use syn::visit::Visit;
6use syn::{Block, FnArg, ReturnType, Signature, Type};
7
8use crate::io_call_finder::IoCallFinder;
9use crate::unsafe_finder::UnsafeFinder;
10
11pub struct FunctionPurity;
12
13impl FunctionPurity {
14    pub fn has_mut_param(sig: &Signature) -> bool {
15        sig.inputs.iter().any(|arg| match arg {
16            FnArg::Receiver(recv) => recv.reference.is_some() && recv.mutability.is_some(),
17            FnArg::Typed(pat_type) => Self::has_mut_in_type(&pat_type.ty),
18        })
19    }
20
21    #[allow(clippy::only_used_in_recursion)]
22    fn has_mut_in_type(ty: &Type) -> bool {
23        match ty {
24            Type::Reference(reference) => reference.mutability.is_some(),
25            Type::Paren(inner) => Self::has_mut_in_type(&inner.elem),
26            _ => false,
27        }
28    }
29
30    pub fn is_unit_return(sig: &Signature) -> bool {
31        match &sig.output {
32            ReturnType::Default => true,
33            ReturnType::Type(_, ty) => {
34                if let Type::Tuple(tuple) = ty.as_ref() {
35                    tuple.elems.is_empty()
36                } else {
37                    false
38                }
39            }
40        }
41    }
42
43    pub fn has_unsafe_block(block: &Block) -> bool {
44        let mut finder = UnsafeFinder::new();
45        finder.visit_block(block);
46        finder.found
47    }
48
49    pub fn has_io_call(block: &Block) -> bool {
50        let mut finder = IoCallFinder::new();
51        finder.visit_block(block);
52        finder.found
53    }
54}