Skip to main content

wowlab_tidy/languages/rust/rules/complexity/
max_fn_lines.rs

1#[cfg(test)]
2use googletest::prelude::*;
3use ra_ap_syntax::{
4    AstNode,
5    ast::{self, HasName},
6};
7
8use crate::{AstCtx, Example, Violation};
9
10#[rustfmt::skip]
11const EXAMPLES: &[Example] = &[
12    Example {
13        label: "short function",
14        code: "fn f() { let x = 1; }",
15        pass: true,
16    },
17];
18
19crate::ast_rule!(
20    max_fn_lines,
21    "Flag functions longer than threshold lines.",
22    "Functions over 150 lines are hard to understand, test, and review. Break them into smaller focused functions.",
23    Medium,
24    params {
25        threshold: i64 = 150
26    },
27);
28
29fn check_max_fn_lines(ctx: &AstCtx<'_>) -> Vec<Violation> {
30    let max_fn_lines = ctx.file.config.get_usize("rust_max_fn_lines", &PARAMS[0]);
31
32    ctx.nodes::<ast::Fn>()
33        .filter(|function| !ctx.is_in_test(function))
34        .filter_map(|function| {
35            let body = function.body()?;
36            let range = body.syntax().text_range();
37            let start = ctx.line_index.line_col(range.start()).line as usize;
38            let end = ctx.line_index.line_col(range.end()).line as usize;
39            let lines = end.saturating_sub(start);
40
41            (lines > max_fn_lines).then(|| {
42                let name = function.name()?;
43
44                Some(ctx.violation(
45                    &name,
46                    format!("function `{name}` is {lines} lines long (max {max_fn_lines})"),
47                ))
48            })?
49        })
50        .collect()
51}
52
53crate::tidy_ast_test!(check_max_fn_lines, {
54    use std::fmt::Write as _;
55
56    crate::example_tests!(EXAMPLES, check_max_fn_lines);
57
58    #[gtest]
59    fn long_fn_fails() -> Result<()> {
60        let mut src = String::from("fn long() {\n");
61        for i in 0..155 {
62            let _ = writeln!(src, "    let _x{i} = {i};");
63        }
64        src.push_str("}\n");
65        let v = run(&src);
66        verify_eq!(v.len(), 1)?;
67        verify_true!(v[0].message.contains("long"))?;
68        verify_true!(v[0].message.contains("lines long"))?;
69
70        Ok(())
71    }
72});