2021-04-08 17:50:13 +02:00
|
|
|
use rustc_hir as hir;
|
2021-08-12 11:16:25 +02:00
|
|
|
use rustc_hir::intravisit::FnKind;
|
2021-04-08 17:50:13 +02:00
|
|
|
use rustc_lint::{LateContext, LintContext};
|
|
|
|
use rustc_middle::lint::in_external_macro;
|
|
|
|
use rustc_span::Span;
|
|
|
|
|
|
|
|
use clippy_utils::diagnostics::span_lint;
|
2021-06-03 08:41:37 +02:00
|
|
|
use clippy_utils::source::snippet_opt;
|
2021-04-08 17:50:13 +02:00
|
|
|
|
|
|
|
use super::TOO_MANY_LINES;
|
|
|
|
|
2021-08-12 11:16:25 +02:00
|
|
|
pub(super) fn check_fn(
|
|
|
|
cx: &LateContext<'_>,
|
2022-01-13 13:18:19 +01:00
|
|
|
kind: FnKind<'_>,
|
2021-08-12 11:16:25 +02:00
|
|
|
span: Span,
|
2022-01-13 13:18:19 +01:00
|
|
|
body: &hir::Body<'_>,
|
2021-08-12 11:16:25 +02:00
|
|
|
too_many_lines_threshold: u64,
|
|
|
|
) {
|
|
|
|
// Closures must be contained in a parent body, which will be checked for `too_many_lines`.
|
|
|
|
// Don't check closures for `too_many_lines` to avoid duplicated lints.
|
|
|
|
if matches!(kind, FnKind::Closure) || in_external_macro(cx.sess(), span) {
|
2021-04-08 17:50:13 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-06-03 08:41:37 +02:00
|
|
|
let code_snippet = match snippet_opt(cx, body.value.span) {
|
|
|
|
Some(s) => s,
|
|
|
|
_ => return,
|
|
|
|
};
|
2021-04-08 17:50:13 +02:00
|
|
|
let mut line_count: u64 = 0;
|
|
|
|
let mut in_comment = false;
|
|
|
|
let mut code_in_line;
|
|
|
|
|
2021-06-03 08:41:37 +02:00
|
|
|
let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..))
|
|
|
|
&& code_snippet.as_bytes().first().copied() == Some(b'{')
|
|
|
|
&& code_snippet.as_bytes().last().copied() == Some(b'}')
|
|
|
|
{
|
|
|
|
// Removing the braces from the enclosing block
|
|
|
|
&code_snippet[1..code_snippet.len() - 1]
|
|
|
|
} else {
|
|
|
|
&code_snippet
|
|
|
|
}
|
|
|
|
.trim() // Remove leading and trailing blank lines
|
|
|
|
.lines();
|
2021-04-08 17:50:13 +02:00
|
|
|
|
|
|
|
for mut line in function_lines {
|
|
|
|
code_in_line = false;
|
|
|
|
loop {
|
|
|
|
line = line.trim_start();
|
|
|
|
if line.is_empty() {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if in_comment {
|
|
|
|
if let Some(i) = line.find("*/") {
|
|
|
|
line = &line[i + 2..];
|
|
|
|
in_comment = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
2021-12-06 12:33:31 +01:00
|
|
|
let multi_idx = line.find("/*").unwrap_or(line.len());
|
|
|
|
let single_idx = line.find("//").unwrap_or(line.len());
|
2021-04-08 17:50:13 +02:00
|
|
|
code_in_line |= multi_idx > 0 && single_idx > 0;
|
|
|
|
// Implies multi_idx is below line.len()
|
|
|
|
if multi_idx < single_idx {
|
|
|
|
line = &line[multi_idx + 2..];
|
|
|
|
in_comment = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if code_in_line {
|
|
|
|
line_count += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if line_count > too_many_lines_threshold {
|
|
|
|
span_lint(
|
|
|
|
cx,
|
|
|
|
TOO_MANY_LINES,
|
|
|
|
span,
|
|
|
|
&format!(
|
|
|
|
"this function has too many lines ({}/{})",
|
|
|
|
line_count, too_many_lines_threshold
|
|
|
|
),
|
2021-06-03 08:41:37 +02:00
|
|
|
);
|
2021-04-08 17:50:13 +02:00
|
|
|
}
|
|
|
|
}
|