diff --git a/.clippy.toml b/.clippy.toml index 57bffb39..a4d2aac7 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -2,6 +2,15 @@ # See full lints list at: # https://rust-lang.github.io/rust-clippy/master/index.html +absolute-paths-allowed-crates = [ + "base64", + "clap", + "gherkin", + "syn", + "tracing", + "tracing_subscriber", +] + doc-valid-idents = ["JUnit"] standard-macro-braces = [ diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index 0bc0423e..d38da72d 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -23,6 +23,7 @@ )] #![forbid(non_ascii_idents, unsafe_code)] #![warn( + clippy::absolute_paths, clippy::as_conversions, clippy::as_ptr_cast_mut, clippy::assertions_on_result_states, @@ -71,6 +72,7 @@ clippy::mutex_atomic, clippy::mutex_integer, clippy::needless_collect, + clippy::needless_pass_by_ref_mut, clippy::needless_raw_strings, clippy::nonstandard_macro_braces, clippy::option_if_let_else, @@ -83,6 +85,7 @@ clippy::pub_without_shorthand, clippy::rc_buffer, clippy::rc_mutex, + clippy::readonly_write_lock, clippy::redundant_clone, clippy::redundant_type_annotations, clippy::ref_patterns, @@ -95,6 +98,7 @@ clippy::str_to_string, clippy::string_add, clippy::string_lit_as_bytes, + clippy::string_lit_chars_any, clippy::string_slice, clippy::string_to_string, clippy::suboptimal_flops, @@ -106,7 +110,6 @@ clippy::transmute_undefined_repr, clippy::trivial_regex, clippy::try_err, - clippy::tuple_array_conversions, clippy::undocumented_unsafe_blocks, clippy::unimplemented, clippy::unnecessary_safety_comment, @@ -123,13 +126,11 @@ clippy::verbose_file_reads, clippy::wildcard_enum_match_arm, future_incompatible, - invalid_reference_casting, let_underscore_drop, meta_variable_misuse, missing_copy_implementations, missing_debug_implementations, missing_docs, - noop_method_call, semicolon_in_expressions_from_macros, unreachable_pub, unused_crate_dependencies, diff --git a/src/cucumber.rs b/src/cucumber.rs index dc821203..8c7ad842 100644 --- a/src/cucumber.rs +++ b/src/cucumber.rs @@ -14,7 +14,7 @@ use std::{ borrow::Cow, - fmt::{Debug, Formatter}, + fmt::{self, Debug}, marker::PhantomData, mem, path::Path, @@ -201,7 +201,7 @@ where /// /// /// [`Scenario`]: gherkin::Scenario - /// [`Skipped`]: crate::event::Step::Skipped + /// [`Skipped`]: event::Step::Skipped #[must_use] pub fn repeat_skipped( self, @@ -266,7 +266,7 @@ where /// async data-autoplay="true" data-rows="24"> /// /// - /// [`Failed`]: crate::event::Step::Failed + /// [`Failed`]: event::Step::Failed #[must_use] pub fn repeat_failed( self, @@ -365,7 +365,7 @@ where /// async data-autoplay="true" data-rows="24"> /// /// - /// [`Failed`]: crate::event::Step::Failed + /// [`Failed`]: event::Step::Failed #[must_use] pub fn repeat_if( self, @@ -438,9 +438,9 @@ where /// ``` /// /// [`Background`]: gherkin::Background - /// [`Failed`]: crate::event::Step::Failed + /// [`Failed`]: event::Step::Failed /// [`Scenario`]: gherkin::Scenario - /// [`Skipped`]: crate::event::Step::Skipped + /// [`Skipped`]: event::Step::Skipped /// [`Step`]: gherkin::Step #[must_use] pub fn fail_on_skipped( @@ -520,9 +520,9 @@ where /// ``` /// /// [`Background`]: gherkin::Background - /// [`Failed`]: crate::event::Step::Failed + /// [`Failed`]: event::Step::Failed /// [`Scenario`]: gherkin::Scenario - /// [`Skipped`]: crate::event::Step::Skipped + /// [`Skipped`]: event::Step::Skipped /// [`Step`]: gherkin::Step #[must_use] pub fn fail_on_skipped_with( @@ -829,7 +829,7 @@ where >::Cli: Debug, Cli: clap::Args + Debug, { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Cucumber") .field("parser", &self.parser) .field("runner", &self.runner) @@ -1193,7 +1193,7 @@ where /// If encountered errors while parsing [`Feature`]s or at least one /// [`Step`] [`Failed`]. /// - /// [`Failed`]: crate::event::Step::Failed + /// [`Failed`]: event::Step::Failed /// [`Feature`]: gherkin::Feature /// [`Step`]: gherkin::Step pub async fn run_and_exit(self, input: I) { @@ -1249,10 +1249,9 @@ where /// async data-autoplay="true" data-rows="14"> /// /// - /// [`Failed`]: crate::event::Step::Failed + /// [`Failed`]: event::Step::Failed /// [`Feature`]: gherkin::Feature /// [`Scenario`]: gherkin::Scenario - /// [`Step`]: crate::Step pub async fn filter_run_and_exit(self, input: I, filter: Filter) where Filter: Fn( diff --git a/src/lib.rs b/src/lib.rs index dbc691ac..3162ee5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ )] #![forbid(non_ascii_idents, unsafe_code)] #![warn( + clippy::absolute_paths, clippy::as_conversions, clippy::as_ptr_cast_mut, clippy::assertions_on_result_states, @@ -72,6 +73,7 @@ clippy::mutex_atomic, clippy::mutex_integer, clippy::needless_collect, + clippy::needless_pass_by_ref_mut, clippy::needless_raw_strings, clippy::nonstandard_macro_braces, clippy::option_if_let_else, @@ -84,6 +86,7 @@ clippy::pub_without_shorthand, clippy::rc_buffer, clippy::rc_mutex, + clippy::readonly_write_lock, clippy::redundant_clone, clippy::redundant_type_annotations, clippy::ref_patterns, @@ -96,6 +99,7 @@ clippy::str_to_string, clippy::string_add, clippy::string_lit_as_bytes, + clippy::string_lit_chars_any, clippy::string_slice, clippy::string_to_string, clippy::suboptimal_flops, @@ -107,7 +111,6 @@ clippy::transmute_undefined_repr, clippy::trivial_regex, clippy::try_err, - clippy::tuple_array_conversions, clippy::undocumented_unsafe_blocks, clippy::unimplemented, clippy::unnecessary_safety_comment, @@ -124,13 +127,11 @@ clippy::verbose_file_reads, clippy::wildcard_enum_match_arm, future_incompatible, - invalid_reference_casting, let_underscore_drop, meta_variable_misuse, missing_copy_implementations, missing_debug_implementations, missing_docs, - noop_method_call, semicolon_in_expressions_from_macros, unreachable_pub, unused_crate_dependencies, @@ -145,6 +146,9 @@ )] // TODO: Remove on next `derive_more` major version. #![allow(clippy::uninlined_format_args)] +// TODO: Massive false positives on `.await` points. Try remove on next Rust +// version. +#![allow(clippy::multiple_unsafe_ops_per_block)] pub mod cli; mod cucumber; diff --git a/src/parser/basic.rs b/src/parser/basic.rs index 650ae4c9..f3998cb1 100644 --- a/src/parser/basic.rs +++ b/src/parser/basic.rs @@ -118,7 +118,7 @@ impl> Parser for Basic { .case_insensitive(true) .build() .unwrap_or_else(|e| { - unreachable!("GlobWalkerBuilder panicked: {e}") + unreachable!("`GlobWalkerBuilder` panicked: {e}") }); walk(w) } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 07d414a9..68b7062b 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -53,6 +53,7 @@ pub trait Parser { /// Result of parsing [Gherkin] files. /// /// [Gherkin]: https://cucumber.io/docs/gherkin/reference +#[allow(clippy::absolute_paths)] pub type Result = std::result::Result; /// [`Parser`] error. diff --git a/src/runner/basic.rs b/src/runner/basic.rs index 073a076b..6a7cf753 100644 --- a/src/runner/basic.rs +++ b/src/runner/basic.rs @@ -11,6 +11,7 @@ //! Default [`Runner`] implementation. use std::{ + any::Any, cmp, collections::HashMap, fmt, iter, mem, @@ -2392,7 +2393,7 @@ impl Features { } /// Coerces the given `value` into a type-erased [`Info`]. -fn coerce_into_info(val: T) -> Info { +fn coerce_into_info(val: T) -> Info { Arc::new(val) } diff --git a/src/step.rs b/src/step.rs index 4d443a0a..4e4922ef 100644 --- a/src/step.rs +++ b/src/step.rs @@ -309,7 +309,7 @@ impl Eq for HashableRegex {} impl PartialOrd for HashableRegex { fn partial_cmp(&self, other: &Self) -> Option { - self.0.as_str().partial_cmp(other.0.as_str()) + Some(self.cmp(other)) } } diff --git a/src/writer/basic.rs b/src/writer/basic.rs index 570fee97..f3675d0a 100644 --- a/src/writer/basic.rs +++ b/src/writer/basic.rs @@ -1042,6 +1042,8 @@ fn format_str_with_indent(str: impl AsRef, indent: usize) -> String { /// Formats the given [`gherkin::Table`] and adds `indent`s to each line to /// prettify the output. fn format_table(table: &gherkin::Table, indent: usize) -> String { + use std::fmt::Write as _; + let max_row_len = table .rows .iter() @@ -1063,10 +1065,13 @@ fn format_table(table: &gherkin::Table, indent: usize) -> String { .rows .iter() .map(|row| { - row.iter() - .zip(&max_row_len) - .map(|(cell, len)| format!("| {cell:len$} ")) - .collect::() + row.iter().zip(&max_row_len).fold( + String::new(), + |mut out, (cell, len)| { + _ = write!(out, "| {cell:len$} "); + out + }, + ) }) .map(|row| format!("{}{row}", " ".repeat(indent + 1))) .join("|\n"); diff --git a/src/writer/discard.rs b/src/writer/discard.rs index 4908c49e..2384324c 100644 --- a/src/writer/discard.rs +++ b/src/writer/discard.rs @@ -13,7 +13,7 @@ use async_trait::async_trait; use derive_more::{Deref, DerefMut}; -use crate::{event::Cucumber, writer, Event, World, Writer}; +use crate::{event::Cucumber, parser, writer, Event, World, Writer}; /// Wrapper providing a no-op [`ArbitraryWriter`] implementation. /// @@ -31,7 +31,7 @@ impl + ?Sized> Writer for Arbitrary { async fn handle_event( &mut self, - ev: crate::parser::Result>>, + ev: parser::Result>>, cli: &Self::Cli, ) { self.0.handle_event(ev, cli).await; @@ -122,7 +122,7 @@ impl + ?Sized> Writer for Stats { async fn handle_event( &mut self, - ev: crate::parser::Result>>, + ev: parser::Result>>, cli: &Self::Cli, ) { self.0.handle_event(ev, cli).await; diff --git a/src/writer/out.rs b/src/writer/out.rs index c2fd1685..a401ecce 100644 --- a/src/writer/out.rs +++ b/src/writer/out.rs @@ -220,7 +220,7 @@ pub trait WriteStrExt: io::Write { /// If this writer fails to write the given `string`. fn write_line(&mut self, string: impl AsRef) -> io::Result<()> { self.write_str(string.as_ref()) - .and_then(|_| self.write_str("\n")) + .and_then(|()| self.write_str("\n")) .map(drop) }