-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add coding style tool #681
base: main
Are you sure you want to change the base?
Conversation
for sorting granularity of regarding order of
for blank lines between items: https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#blank_lines_lower_bound |
We talked about this in the devmeeting and decided we don't want to maintain another tool since rustfmt can take care of the things you listed. If you want, you can create a correct rustfmt.toml file that enforces these behaviors. |
You are proposing to use rustfmt instead. These features are not available in stable rustfmt.
This feature is sadly unstable. It also does not implement "all use items of the same category must be ordered: pub, crate, pub(...), ...".
We can change that to comply with the style guide, that is no problem. For me consistency is the important thing. This style guide seems to be Beta, so not official?
This feature is sadly also unstable. Hopefully we don't get the empty lines in the beginning of functions?
Oh, that was a fast decision. I hoped to argue for my solution but I was late to the meeting due to work as I mentioned earlier. So do I conclude correctly that we would be fine to require our developers to use an unstable toolchain to use the unstable features? Until now, this was a no-go? 🤔 |
After todays discussion I'm more open to this PR, since I thought previously this PR would introduce another external tool which I'd not have been a fan of. Since @h3ndrk understandably wants formatting rules for this use cases which are not covered by rustfmt yet, I think we can use this tool until the respective checks are stable in rustfmt. Despite that I would like to hear the opinion @schmidma, since he originally also was not a fan of this extra tool. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left many ideas for improvement. Feel free to discuss ;)
This branch has conflicts ;) |
12bfb08
to
7fda14a
Compare
@schmidma Please have a look again. The tool is largely rewritten to comply with our coding standards. It also features much better error reports thanks to a third-party crate. The |
This branch has conflicts and is also not passing the CI 😉 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some remarks and suggestions
tools/checky/src/main.rs
Outdated
#[derive(Parser, Debug)] | ||
struct Arguments { | ||
paths: Vec<PathBuf>, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please provide docstrings (///
) such that clap
automatically generates proper help pages
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
#[derive(Parser, Debug)] | ||
struct Arguments { | ||
paths: Vec<PathBuf>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you somehow tell clap
that the user should provide at least one path? currently, the tool also successfully completes when no paths are given
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
if !entry | ||
.path() | ||
.extension() | ||
.map(|extension| extension == "rs") | ||
.unwrap_or_default() | ||
{ | ||
continue; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I provide a single non-rust file, I'd expect this tool to fail. Currently it silently runs to completion.
e.g.
cargo run --manifest-path tools/checky/Cargo.toml -- Cargo.toml
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a suggestion how to implement that without adding a lot of complexity in this file?
tools/checky/src/main.rs
Outdated
let file = RustFile::try_parse(entry.path()) | ||
.wrap_err_with(|| format!("failed to parse {}", entry.path().display()))?; | ||
|
||
for report in check(&file) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for report in check(&file) { | |
let reports = check(&file); | |
for report in reports { |
Just because this is where the magic happens...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
pub fn check(file: &RustFile) -> Vec<Report> { | ||
let mut reports = Vec::new(); | ||
reports.extend(empty_lines::check(file)); | ||
// reports.extend(mod_use_order::check(file)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it disabled? If it is dead code, we should remove it for now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to first decide on the way how we want to order that. I forgot what we decided in some Dev-Meeting. So maybe you need to decide it again. Then we can enable the check and fix all wrong mod-use-orders.
|
||
pub fn check(file: &RustFile) -> Vec<Report> { | ||
let mut reports = Vec::new(); | ||
reports.extend(empty_lines::check(file)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion for the check API, as some check may want to have configuration parameters:
pub trait Check {
fn check(&self) -> impl IntoIterator<Item = Report>;
}
// [...]
let empty_lines = EmptyLines::new(/*possible setup here, read from toml etc./*);
reports.extend(empty_lines.check(file));
or maybe even additionally
pub trait Check {
fn check(&self, context: &mut ReportContext) -> impl IntoIterator<Item = Report>;
}
which hides the allocation in Vec<Report>
or even directly prints them. This way the check only calls something like context.report(...)
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried quickly but this requires to think a bit about lifetimes etc. which is too much for me in this PR. Either someone takes this over or we could do this in a next iteration.
tools/checky/src/rust_file.rs
Outdated
file.read_to_string(&mut buffer).wrap_err_with(|| { | ||
format!("failed to read file {} to string", path.as_ref().display()) | ||
})?; | ||
let path = path.as_ref().to_path_buf(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd expect this to be cloned at the end of the function and not here, and then reborrowed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved the .to_path_buf()
at the end. Did you mean this? 🤔
) -> Option<Report<'a>> { | ||
let line_before = before.span().end().line; | ||
let line_after = after.span().start().line; | ||
if line_before + 1 == line_after { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if line_before + 1 == line_after { | |
let something_with_subsequent = line_before + 1 == line_after; | |
if something_with_subsequent { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Named the documentation variable is_subsequent
.
let Some(line_before) = file.source.line(line_before - 1) else { | ||
panic!("line {line_before} does not exist"); | ||
}; | ||
let Some(line_after) = file.source.line(line_after - 1) else { | ||
panic!("line {line_after} does not exist"); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are .expect()
calls, are they?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now the format string is created regardless if there was a None
but maybe that is fine. .expect()
only takes &str
.
} else { | ||
None | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
refactor for early returns
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored
Do we want to revive this? Or do you want to pass this to someone else @h3ndrk ? |
Feel free to take this over. I fixed some things but the mod-use-order check still needs some work. |
Introduced Changes
This PR adds the "checky" tool that iterates over all Rust files in our repository and checks them for the following coding style rules:
ToDo / Known Issues
/dev/null
Ideas for Next Iterations (Not This PR)
How to Test
Run cargo run --manifest-path=tools/checky/Cargo.toml from the root directory of the repository.