1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2025-06-15 13:50:27 +02:00

Introduce a cargo clippy run

Personally, I don’t always agree with Clippy, but it a very widely
recommended tool for writing idiomatic Rust. So on balance, I think
it’s overall a good idea to enable it for both our exercises and our
tooling.
This commit is contained in:
Martin Geisler
2024-04-24 11:39:40 +02:00
parent 1c964f6fe3
commit 618d8fe4e9
15 changed files with 80 additions and 59 deletions

View File

@ -10,36 +10,6 @@ env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
jobs: jobs:
format:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install formatting dependencies
run: |
sudo apt update
sudo apt install gettext yapf3
- name: Install nightly rustfmt
run: |
rustup default nightly
rustup component add rustfmt
- name: Check formatting
uses: dprint/check@v2.2
typos:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Check for typos
uses: crate-ci/typos@v1.23.2
with:
config: ./.github/typos.toml
cargo: cargo:
strategy: strategy:
matrix: matrix:

53
.github/workflows/lint.yml vendored Normal file
View File

@ -0,0 +1,53 @@
name: Lint
on:
pull_request:
push:
branches:
- main
env:
CARGO_TERM_COLOR: always
jobs:
format:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install formatting dependencies
run: |
sudo apt update
sudo apt install gettext yapf3
- name: Install nightly rustfmt
run: |
rustup default nightly
rustup component add rustfmt
- name: Check formatting
uses: dprint/check@v2.2
typos:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Check for typos
uses: crate-ci/typos@v1.23.2
with:
config: ./.github/typos.toml
clippy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Rust cache
uses: ./.github/workflows/setup-rust-cache
- name: Clippy
run: cargo clippy

View File

@ -48,7 +48,7 @@ fn timediff(actual: u64, target: u64, slop: u64) -> String {
} else if actual + slop < target { } else if actual + slop < target {
format!("{}: ({} short)", duration(actual), duration(target - actual),) format!("{}: ({} short)", duration(actual), duration(target - actual),)
} else { } else {
format!("{}", duration(actual)) duration(actual).to_string()
} }
} }

View File

@ -29,7 +29,7 @@ fn main() {
); );
let matches = app.get_matches(); let matches = app.get_matches();
if let Some(_) = matches.subcommand_matches("supports") { if matches.subcommand_matches("supports").is_some() {
// Support all renderers. // Support all renderers.
process::exit(0); process::exit(0);
} }

View File

@ -156,7 +156,7 @@ impl Courses {
fn course_mut(&mut self, name: impl AsRef<str>) -> &mut Course { fn course_mut(&mut self, name: impl AsRef<str>) -> &mut Course {
let name = name.as_ref(); let name = name.as_ref();
if let Some(found_idx) = if let Some(found_idx) =
self.courses.iter().position(|course| &course.name == name) self.courses.iter().position(|course| course.name == name)
{ {
return &mut self.courses[found_idx]; return &mut self.courses[found_idx];
} }
@ -177,9 +177,7 @@ impl Courses {
&self, &self,
chapter: &Chapter, chapter: &Chapter,
) -> Option<(&Course, &Session, &Segment, &Slide)> { ) -> Option<(&Course, &Session, &Segment, &Slide)> {
let Some(ref source_path) = chapter.source_path else { let source_path = chapter.source_path.as_ref()?;
return None;
};
for course in self { for course in self {
for session in course { for session in course {
@ -193,7 +191,7 @@ impl Courses {
} }
} }
return None; None
} }
} }
@ -202,7 +200,7 @@ impl<'a> IntoIterator for &'a Courses {
type IntoIter = std::slice::Iter<'a, Course>; type IntoIter = std::slice::Iter<'a, Course>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
(&self.courses).into_iter() self.courses.iter()
} }
} }
@ -216,7 +214,7 @@ impl Course {
fn session_mut(&mut self, name: impl AsRef<str>) -> &mut Session { fn session_mut(&mut self, name: impl AsRef<str>) -> &mut Session {
let name = name.as_ref(); let name = name.as_ref();
if let Some(found_idx) = if let Some(found_idx) =
self.sessions.iter().position(|session| &session.name == name) self.sessions.iter().position(|session| session.name == name)
{ {
return &mut self.sessions[found_idx]; return &mut self.sessions[found_idx];
} }
@ -275,7 +273,7 @@ impl<'a> IntoIterator for &'a Course {
type IntoIter = std::slice::Iter<'a, Session>; type IntoIter = std::slice::Iter<'a, Session>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
(&self.sessions).into_iter() self.sessions.iter()
} }
} }
@ -350,7 +348,7 @@ impl<'a> IntoIterator for &'a Session {
type IntoIter = std::slice::Iter<'a, Segment>; type IntoIter = std::slice::Iter<'a, Segment>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
(&self.segments).into_iter() self.segments.iter()
} }
} }
@ -403,7 +401,7 @@ impl<'a> IntoIterator for &'a Segment {
type IntoIter = std::slice::Iter<'a, Slide>; type IntoIter = std::slice::Iter<'a, Slide>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
(&self.slides).into_iter() self.slides.iter()
} }
} }
@ -451,7 +449,7 @@ impl Slide {
pub fn is_sub_chapter(&self, chapter: &Chapter) -> bool { pub fn is_sub_chapter(&self, chapter: &Chapter) -> bool {
// The first `source_path` in the slide is the "parent" chapter, so anything // The first `source_path` in the slide is the "parent" chapter, so anything
// else is a sub-chapter. // else is a sub-chapter.
chapter.source_path.as_ref() != self.source_paths.get(0) chapter.source_path.as_ref() != self.source_paths.first()
} }
/// Return the total duration of this slide. /// Return the total duration of this slide.

View File

@ -83,7 +83,7 @@ impl<const N: usize> Table<N> {
for cell in iter { for cell in iter {
write!(f, " {} |", cell)?; write!(f, " {} |", cell)?;
} }
write!(f, "\n") writeln!(f)
} }
} }

View File

@ -50,7 +50,7 @@ pub fn replace(
} }
["course", "outline", course_name] => { ["course", "outline", course_name] => {
let Some(course) = courses.find_course(course_name) else { let Some(course) = courses.find_course(course_name) else {
return format!("not found - {}", captures[0].to_string()); return format!("not found - {}", &captures[0]);
}; };
course.schedule() course.schedule()
} }

View File

@ -58,7 +58,7 @@ pub fn process(output_directory: &Path, input_contents: &str) -> anyhow::Result<
Event::Text(text) => { Event::Text(text) => {
info!("Text: {:?}", text); info!("Text: {:?}", text);
if let Some(output_file) = &mut current_file { if let Some(output_file) = &mut current_file {
output_file.write(text.as_bytes())?; output_file.write_all(text.as_bytes())?;
} }
} }
Event::End(TagEnd::CodeBlock) => { Event::End(TagEnd::CodeBlock) => {

View File

@ -41,7 +41,7 @@ async fn main() -> Result<(), tokio_websockets::Error> {
println!("From server: {}", text); println!("From server: {}", text);
} }
}, },
Some(Err(err)) => return Err(err.into()), Some(Err(err)) => return Err(err),
None => return Ok(()), None => return Ok(()),
} }
} }

View File

@ -107,9 +107,7 @@ enum ParserError {
fn parse(input: &str) -> Result<Expression, ParserError> { fn parse(input: &str) -> Result<Expression, ParserError> {
let mut tokens = tokenize(input); let mut tokens = tokenize(input);
fn parse_expr<'a>( fn parse_expr(tokens: &mut Tokenizer<'_>) -> Result<Expression, ParserError> {
tokens: &mut Tokenizer<'a>,
) -> Result<Expression, ParserError> {
let tok = tokens.next().ok_or(ParserError::UnexpectedEOF)??; let tok = tokens.next().ok_or(ParserError::UnexpectedEOF)??;
let expr = match tok { let expr = match tok {
Token::Number(num) => { Token::Number(num) => {

View File

@ -25,8 +25,8 @@ where
N: Copy + std::ops::Sub<Output = N>, N: Copy + std::ops::Sub<Output = N>,
{ {
// ANCHOR_END: offset_differences // ANCHOR_END: offset_differences
let a = (&values).into_iter(); let a = values.iter();
let b = (&values).into_iter().cycle().skip(offset); let b = values.iter().cycle().skip(offset);
a.zip(b).map(|(a, b)| *b - *a).collect() a.zip(b).map(|(a, b)| *b - *a).collect()
} }

View File

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// Iterators are covered later.
#[allow(clippy::needless_range_loop)]
// ANCHOR: solution // ANCHOR: solution
// ANCHOR: transpose // ANCHOR: transpose
fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] { fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {

View File

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// Omitting `return` is covered later.
#[allow(clippy::needless_return)]
// ANCHOR: solution // ANCHOR: solution
// ANCHOR: fib // ANCHOR: fib
fn fib(n: u32) -> u32 { fn fib(n: u32) -> u32 {

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#[allow(clippy::upper_case_acronyms)]
// ANCHOR: solution // ANCHOR: solution
// ANCHOR: ffi // ANCHOR: ffi
mod ffi { mod ffi {
@ -40,7 +41,7 @@ mod ffi {
} }
// Layout according to the macOS man page for dir(5). // Layout according to the macOS man page for dir(5).
#[cfg(all(target_os = "macos"))] #[cfg(target_os = "macos")]
#[repr(C)] #[repr(C)]
pub struct dirent { pub struct dirent {
pub d_fileno: u64, pub d_fileno: u64,

View File

@ -37,12 +37,9 @@ impl User {
patient_name: &self.name, patient_name: &self.name,
visit_count: self.visit_count as u32, visit_count: self.visit_count as u32,
height_change: measurements.height - self.height, height_change: measurements.height - self.height,
blood_pressure_change: match self.last_blood_pressure { blood_pressure_change: self
Some(lbp) => { .last_blood_pressure
Some((bp.0 as i32 - lbp.0 as i32, bp.1 as i32 - lbp.1 as i32)) .map(|lbp| (bp.0 as i32 - lbp.0 as i32, bp.1 as i32 - lbp.1 as i32)),
}
None => None,
},
}; };
self.height = measurements.height; self.height = measurements.height;
self.last_blood_pressure = Some(bp); self.last_blood_pressure = Some(bp);