Add tidy directoy tidy-alphabetical
It can be used to ensure that a list of things is sorted alphabetically. It goes off lines, but contains several heuristics to work with normal Rust code (looking at indentation, ignoring comments and attributes).
This commit is contained in:
parent
e6ce5627a9
commit
0e3867338d
98
src/tools/tidy/src/alphabetical.rs
Normal file
98
src/tools/tidy/src/alphabetical.rs
Normal file
@ -0,0 +1,98 @@
|
||||
//! Checks that a list of items is in alphabetical order
|
||||
//!
|
||||
//! To use, use the following annotation in the code:
|
||||
//! ```rust
|
||||
//! // tidy-alphabetical-start
|
||||
//! fn aaa() {}
|
||||
//! fn eee() {}
|
||||
//! fn z() {}
|
||||
//! // tidy-alphabetical-end
|
||||
//! ```
|
||||
//!
|
||||
//! The following lines are ignored:
|
||||
//! - Lines that are indented with more or less spaces than the first line
|
||||
//! - Lines starting with `//`, `#[`, `)`, `]`, `}` if the comment has the same indentation as
|
||||
//! the first line
|
||||
//!
|
||||
//! If a line ends with an opening bracket, the line is ignored and the next line will have
|
||||
//! its extra indentation ignored.
|
||||
|
||||
use std::{fmt::Display, path::Path};
|
||||
|
||||
use crate::walk::{filter_dirs, walk};
|
||||
|
||||
fn indentation(line: &str) -> usize {
|
||||
line.find(|c| c != ' ').unwrap_or(0)
|
||||
}
|
||||
|
||||
fn is_close_bracket(c: char) -> bool {
|
||||
matches!(c, ')' | ']' | '}')
|
||||
}
|
||||
|
||||
fn check_section<'a>(
|
||||
file: impl Display,
|
||||
lines: impl Iterator<Item = (usize, &'a str)>,
|
||||
bad: &mut bool,
|
||||
) {
|
||||
let content_lines = lines.take_while(|(_, line)| !line.contains("// tidy-alphabetical-end"));
|
||||
|
||||
let mut prev_line = String::new();
|
||||
let mut first_indent = None;
|
||||
let mut in_split_line = None;
|
||||
|
||||
for (line_idx, line) in content_lines {
|
||||
let indent = first_indent.unwrap_or_else(|| {
|
||||
let indent = indentation(line);
|
||||
first_indent = Some(indent);
|
||||
indent
|
||||
});
|
||||
|
||||
let line = if let Some(prev_split_line) = in_split_line {
|
||||
in_split_line = None;
|
||||
format!("{prev_split_line}{}", line.trim_start())
|
||||
} else {
|
||||
line.to_string()
|
||||
};
|
||||
|
||||
if indentation(&line) != indent {
|
||||
continue;
|
||||
}
|
||||
|
||||
let trimmed_line = line.trim_start_matches(' ');
|
||||
|
||||
if trimmed_line.starts_with("//")
|
||||
|| trimmed_line.starts_with("#[")
|
||||
|| trimmed_line.starts_with(is_close_bracket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if line.trim_end().ends_with('(') {
|
||||
in_split_line = Some(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
let prev_line_trimmed_lowercase = prev_line.trim_start_matches(' ').to_lowercase();
|
||||
|
||||
if trimmed_line.to_lowercase() < prev_line_trimmed_lowercase {
|
||||
tidy_error!(bad, "{file}:{}: line not in alphabetical order", line_idx + 1,);
|
||||
}
|
||||
|
||||
prev_line = line;
|
||||
}
|
||||
}
|
||||
|
||||
const START_COMMENT: &str = "// tidy-alphabetical-start";
|
||||
|
||||
pub fn check(path: &Path, bad: &mut bool) {
|
||||
walk(path, &mut filter_dirs, &mut |entry, contents| {
|
||||
let file = &entry.path().display();
|
||||
|
||||
let mut lines = contents.lines().enumerate();
|
||||
while let Some((_, line)) = lines.next() {
|
||||
if line.contains(START_COMMENT) {
|
||||
check_section(file, &mut lines, bad);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
@ -38,6 +38,7 @@ macro_rules! tidy_error {
|
||||
});
|
||||
}
|
||||
|
||||
pub mod alphabetical;
|
||||
pub mod bins;
|
||||
pub mod debug_artifacts;
|
||||
pub mod deps;
|
||||
|
@ -90,6 +90,8 @@ macro_rules! check {
|
||||
check!(edition, &compiler_path);
|
||||
check!(edition, &library_path);
|
||||
|
||||
check!(alphabetical, &compiler_path);
|
||||
|
||||
let collected = {
|
||||
while handles.len() >= concurrency.get() {
|
||||
handles.pop_front().unwrap().join().unwrap();
|
||||
|
Loading…
Reference in New Issue
Block a user