]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
Rollup merge of #104903 - spastorino:consolidate-normalize-in-report_projection_error...
[rust.git] / src / tools / clippy / clippy_lints / src / functions / too_many_lines.rs
1 use rustc_hir as hir;
2 use rustc_hir::intravisit::FnKind;
3 use rustc_lint::{LateContext, LintContext};
4 use rustc_middle::lint::in_external_macro;
5 use rustc_span::Span;
6
7 use clippy_utils::diagnostics::span_lint;
8 use clippy_utils::source::snippet_opt;
9
10 use super::TOO_MANY_LINES;
11
12 pub(super) fn check_fn(
13     cx: &LateContext<'_>,
14     kind: FnKind<'_>,
15     span: Span,
16     body: &hir::Body<'_>,
17     too_many_lines_threshold: u64,
18 ) {
19     // Closures must be contained in a parent body, which will be checked for `too_many_lines`.
20     // Don't check closures for `too_many_lines` to avoid duplicated lints.
21     if matches!(kind, FnKind::Closure) || in_external_macro(cx.sess(), span) {
22         return;
23     }
24
25     let Some(code_snippet) = snippet_opt(cx, body.value.span) else {
26         return
27     };
28     let mut line_count: u64 = 0;
29     let mut in_comment = false;
30     let mut code_in_line;
31
32     let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..))
33         && code_snippet.as_bytes().first().copied() == Some(b'{')
34         && code_snippet.as_bytes().last().copied() == Some(b'}')
35     {
36         // Removing the braces from the enclosing block
37         &code_snippet[1..code_snippet.len() - 1]
38     } else {
39         &code_snippet
40     }
41     .trim() // Remove leading and trailing blank lines
42     .lines();
43
44     for mut line in function_lines {
45         code_in_line = false;
46         loop {
47             line = line.trim_start();
48             if line.is_empty() {
49                 break;
50             }
51             if in_comment {
52                 if let Some(i) = line.find("*/") {
53                     line = &line[i + 2..];
54                     in_comment = false;
55                     continue;
56                 }
57             } else {
58                 let multi_idx = line.find("/*").unwrap_or(line.len());
59                 let single_idx = line.find("//").unwrap_or(line.len());
60                 code_in_line |= multi_idx > 0 && single_idx > 0;
61                 // Implies multi_idx is below line.len()
62                 if multi_idx < single_idx {
63                     line = &line[multi_idx + 2..];
64                     in_comment = true;
65                     continue;
66                 }
67             }
68             break;
69         }
70         if code_in_line {
71             line_count += 1;
72         }
73     }
74
75     if line_count > too_many_lines_threshold {
76         span_lint(
77             cx,
78             TOO_MANY_LINES,
79             span,
80             &format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"),
81         );
82     }
83 }