Skip to content

Commit 52f7ad0

Browse files
committed
excessive line count
1 parent 1ecb18a commit 52f7ad0

File tree

10 files changed

+138
-0
lines changed

10 files changed

+138
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6266,6 +6266,7 @@ Released 2018-09-13
62666266
[`err_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#err_expect
62676267
[`error_impl_error`]: https://rust-lang.github.io/rust-clippy/master/index.html#error_impl_error
62686268
[`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
6269+
[`excessive_file_length`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_file_length
62696270
[`excessive_nesting`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_nesting
62706271
[`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision
62716272
[`exhaustive_enums`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_enums

clippy_config/src/conf.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,9 @@ define_Conf! {
657657
/// The maximum amount of nesting a block can reside in
658658
#[lints(excessive_nesting)]
659659
excessive_nesting_threshold: u64 = 0,
660+
/// The maximum number of lines a file can have
661+
#[lints(excessive_file_length)]
662+
excessive_file_length_threshold: u64 = 500,
660663
/// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint
661664
#[lints(large_futures)]
662665
future_size_threshold: u64 = 16 * 1024,

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
152152
crate::eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS_INFO,
153153
crate::excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS_INFO,
154154
crate::excessive_bools::STRUCT_EXCESSIVE_BOOLS_INFO,
155+
crate::excessive_file_length::EXCESSIVE_FILE_LENGTH_INFO,
155156
crate::excessive_nesting::EXCESSIVE_NESTING_INFO,
156157
crate::exhaustive_items::EXHAUSTIVE_ENUMS_INFO,
157158
crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
use clippy_config::Conf;
2+
use clippy_utils::diagnostics::span_lint_and_help;
3+
use rustc_ast::Crate;
4+
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
5+
use rustc_session::impl_lint_pass;
6+
use rustc_span::def_id::LOCAL_CRATE;
7+
use rustc_span::{FileName, Span, SyntaxContext};
8+
9+
declare_clippy_lint! {
10+
/// ### What it does
11+
/// Checks for files that exceed a configurable line count threshold.
12+
///
13+
/// Note: This is a restriction lint that is allow-by-default. You need to enable it
14+
/// explicitly in your configuration and set the threshold in clippy.toml.
15+
///
16+
/// ### Why restrict this?
17+
/// Large files can be harder to navigate and understand. They often indicate that
18+
/// the code could benefit from being split into multiple smaller, more focused modules.
19+
/// This improves maintainability and makes the codebase easier to understand.
20+
///
21+
/// ### Example
22+
/// An example clippy.toml configuration:
23+
/// ```toml
24+
/// # clippy.toml
25+
/// excessive-file-length-threshold = 500
26+
/// ```
27+
///
28+
/// If a file exceeds this threshold, the lint will suggest splitting it into
29+
/// smaller modules.
30+
#[clippy::version = "1.84.0"]
31+
pub EXCESSIVE_FILE_LENGTH,
32+
restriction,
33+
"checks for files that exceed a configurable line count threshold"
34+
}
35+
36+
impl_lint_pass!(ExcessiveFileLength => [EXCESSIVE_FILE_LENGTH]);
37+
38+
pub struct ExcessiveFileLength {
39+
pub excessive_file_length_threshold: u64,
40+
}
41+
42+
impl ExcessiveFileLength {
43+
pub fn new(conf: &'static Conf) -> Self {
44+
Self {
45+
excessive_file_length_threshold: conf.excessive_file_length_threshold,
46+
}
47+
}
48+
}
49+
50+
impl EarlyLintPass for ExcessiveFileLength {
51+
fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
52+
// Only check if threshold is set (non-zero)
53+
if self.excessive_file_length_threshold == 0 {
54+
return;
55+
}
56+
57+
// Get all source files for the local crate
58+
let source_map = cx.sess().source_map();
59+
60+
// We want to check each file in the current crate
61+
for file in source_map.files().iter() {
62+
// Only check files from the local crate, not external dependencies
63+
if file.cnum != LOCAL_CRATE {
64+
continue;
65+
}
66+
67+
// Skip non-real files (generated code, etc.)
68+
if !matches!(&file.name, FileName::Real(_)) {
69+
continue;
70+
}
71+
72+
// Count total lines in the file
73+
let line_count = file.count_lines() as u64;
74+
75+
// Check if file exceeds threshold
76+
if line_count > self.excessive_file_length_threshold {
77+
// Create a span at the start of the file for the lint
78+
let span = Span::new(
79+
file.start_pos,
80+
file.start_pos,
81+
SyntaxContext::root(),
82+
None,
83+
);
84+
85+
span_lint_and_help(
86+
cx,
87+
EXCESSIVE_FILE_LENGTH,
88+
span,
89+
format!(
90+
"this file has too many lines ({}/{})",
91+
line_count, self.excessive_file_length_threshold
92+
),
93+
None,
94+
"consider splitting this file into smaller modules to improve maintainability",
95+
);
96+
}
97+
}
98+
}
99+
}

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ mod error_impl_error;
128128
mod escape;
129129
mod eta_reduction;
130130
mod excessive_bools;
131+
mod excessive_file_length;
131132
mod excessive_nesting;
132133
mod exhaustive_items;
133134
mod exit;
@@ -747,6 +748,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
747748
store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule));
748749
store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation::new(conf)));
749750
store.register_early_pass(move || Box::new(excessive_nesting::ExcessiveNesting::new(conf)));
751+
store.register_early_pass(move || Box::new(excessive_file_length::ExcessiveFileLength::new(conf)));
750752
store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
751753
store.register_early_pass(|| Box::new(ref_patterns::RefPatterns));
752754
store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs));
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
excessive-file-length-threshold = 10
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![warn(clippy::excessive_file_length)]
2+
//~^ ERROR: this file has too many lines
3+
4+
// This file should trigger the lint because it has more than 10 lines
5+
// (configured in clippy.toml)
6+
7+
fn main() {
8+
println!("Line 1");
9+
println!("Line 2");
10+
println!("Line 3");
11+
println!("Line 4");
12+
println!("Line 5");
13+
println!("Line 6");
14+
println!("Line 7");
15+
// This file now has more than 10 lines and should trigger the lint
16+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error: this file has too many lines (16/10)
2+
--> tests/ui-toml/excessive_file_length/excessive_file_length.rs:1:1
3+
|
4+
LL | #![warn(clippy::excessive_file_length)]
5+
| ^
6+
|
7+
= help: consider splitting this file into smaller modules to improve maintainability
8+
= note: `-D clippy::excessive-file-length` implied by `-D warnings`
9+
= help: to override `-D warnings` add `#[allow(clippy::excessive_file_length)]`
10+
11+
error: aborting due to 1 previous error
12+

tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
4646
enforced-import-renames
4747
enum-variant-name-threshold
4848
enum-variant-size-threshold
49+
excessive-file-length-threshold
4950
excessive-nesting-threshold
5051
future-size-threshold
5152
ignore-interior-mutability
@@ -143,6 +144,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
143144
enforced-import-renames
144145
enum-variant-name-threshold
145146
enum-variant-size-threshold
147+
excessive-file-length-threshold
146148
excessive-nesting-threshold
147149
future-size-threshold
148150
ignore-interior-mutability
@@ -240,6 +242,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
240242
enforced-import-renames
241243
enum-variant-name-threshold
242244
enum-variant-size-threshold
245+
excessive-file-length-threshold
243246
excessive-nesting-threshold
244247
future-size-threshold
245248
ignore-interior-mutability

tests/ui/explicit_write_in_test.stderr

Whitespace-only changes.

0 commit comments

Comments
 (0)