diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index 05e1b3b92..348d52020 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -24,7 +24,7 @@ jobs: node-version: '18.x' - name: Install remark - run: npm install remark-cli remark-lint remark-lint-maximum-line-length remark-preset-lint-recommended remark-gfm + run: npm install remark-cli remark-lint remark-lint-maximum-line-length@^3.1.3 remark-preset-lint-recommended remark-gfm - name: Install mdbook run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index f7e7ed86e..bd3a04e34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5894,6 +5894,7 @@ Released 2018-09-13 [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles [`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates [`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars +[`allowed-prefixes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-prefixes [`allowed-scripts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-scripts [`allowed-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-wildcard-imports [`arithmetic-side-effects-allowed`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed diff --git a/book/src/README.md b/book/src/README.md index e7972b0db..7bdfb97c3 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -18,17 +18,27 @@ category. | `clippy::all` | all lints that are on by default (correctness, suspicious, style, complexity, perf) | **warn/deny** | | `clippy::correctness` | code that is outright wrong or useless | **deny** | | `clippy::suspicious` | code that is most likely wrong or useless | **warn** | +| `clippy::style` | code that should be written in a more idiomatic way | **warn** | | `clippy::complexity` | code that does something simple but in a complex way | **warn** | | `clippy::perf` | code that can be written to run faster | **warn** | -| `clippy::style` | code that should be written in a more idiomatic way | **warn** | -| `clippy::pedantic` | lints which are rather strict or might have false positives | allow | +| `clippy::pedantic` | lints which are rather strict or have occasional false positives | allow | +| `clippy::restriction` | lints which prevent the use of language and library features[^restrict] | allow | | `clippy::nursery` | new lints that are still under development | allow | -| `clippy::cargo` | lints for the cargo manifest | allow | | allow | +| `clippy::cargo` | lints for the cargo manifest | allow | -More to come, please [file an -issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas! +More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas! -The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also -contains "restriction lints", which are for things which are usually not -considered "bad", but may be useful to turn on in specific cases. These should -be used very selectively, if at all. +The `restriction` category should, *emphatically*, not be enabled as a whole. The contained +lints may lint against perfectly reasonable code, may not have an alternative suggestion, +and may contradict any other lints (including other categories). Lints should be considered +on a case-by-case basis before enabling. + +[^restrict]: Some use cases for `restriction` lints include: + - Strict coding styles (e.g. [`clippy::else_if_without_else`]). + - Additional restrictions on CI (e.g. [`clippy::todo`]). + - Preventing panicking in certain functions (e.g. [`clippy::unwrap_used`]). + - Running a lint only on a subset of code (e.g. `#[forbid(clippy::float_arithmetic)]` on a module). + +[`clippy::else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else +[`clippy::todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo +[`clippy::unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index e30a5f9fe..b80ac6370 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -18,7 +18,6 @@ because that's clearly a non-descriptive name. - [Cargo lints](#cargo-lints) - [Rustfix tests](#rustfix-tests) - [Testing manually](#testing-manually) - - [Running directly](#running-directly) - [Lint declaration](#lint-declaration) - [Lint registration](#lint-registration) - [Lint passes](#lint-passes) @@ -176,23 +175,26 @@ the tests. Manually testing against an example file can be useful if you have added some `println!`s and the test suite output becomes unreadable. To try Clippy with -your local modifications, run +your local modifications, run the following from the Clippy directory: -``` +```bash cargo dev lint input.rs ``` -from the working copy root. With tests in place, let's have a look at -implementing our lint now. +To run Clippy on an existing project rather than a single file you can use -## Running directly +```bash +cargo dev lint /path/to/project +``` -While it's easier to just use `cargo dev lint`, it might be desirable to get -`target/release/cargo-clippy` and `target/release/clippy-driver` to work as well in some cases. -By default, they don't work because clippy dynamically links rustc. To help them find rustc, -add the path printed by`rustc --print target-libdir` (ran inside this workspace so that the rustc version matches) -to your library search path. -On linux, this can be done by setting the `LD_LIBRARY_PATH` environment variable to that path. +Or set up a rustup toolchain that points to the local Clippy binaries + +```bash +cargo dev setup toolchain + +# Then in `/path/to/project` you can run +cargo +clippy clippy +``` ## Lint declaration diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 4a2727c51..7cefa6852 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -164,6 +164,32 @@ configuration of Clippy. By default, any configuration will replace the default * [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) +## `allowed-prefixes` +List of prefixes to allow when determining whether an item's name ends with the module's name. +If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`), +then don't emit a warning. + +#### Example + +```toml +allowed-prefixes = [ "to", "from" ] +``` + +#### Noteworthy + +- By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from` +- PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included, + `TryInto` will also be included) +- Use `".."` as part of the list to indicate that the configured values should be appended to the +default configuration of Clippy. By default, any configuration will replace the default value + +**Default Value:** `["to", "as", "into", "from", "try_into", "try_from"]` + +--- +**Affected lints:** +* [`module_name_repetitions`](https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions) + + ## `allowed-scripts` The list of unicode scripts allowed to be used in the scope. diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 53c10f7ce..781282213 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -39,6 +39,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ ]; const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"]; +const DEFAULT_ALLOWED_PREFIXES: &[&str] = &["to", "as", "into", "from", "try_into", "try_from"]; /// Conf with parse errors #[derive(Default)] @@ -589,6 +590,26 @@ define_Conf! { /// 2. Paths with any segment that containing the word 'prelude' /// are already allowed by default. (allowed_wildcard_imports: FxHashSet = FxHashSet::default()), + /// Lint: MODULE_NAME_REPETITIONS. + /// + /// List of prefixes to allow when determining whether an item's name ends with the module's name. + /// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`), + /// then don't emit a warning. + /// + /// #### Example + /// + /// ```toml + /// allowed-prefixes = [ "to", "from" ] + /// ``` + /// + /// #### Noteworthy + /// + /// - By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from` + /// - PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included, + /// `TryInto` will also be included) + /// - Use `".."` as part of the list to indicate that the configured values should be appended to the + /// default configuration of Clippy. By default, any configuration will replace the default value + (allowed_prefixes: Vec = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()), } /// Search for the configuration file. @@ -649,6 +670,7 @@ fn deserialize(file: &SourceFile) -> TryConf { Ok(mut conf) => { extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); + extend_vec_if_indicator_present(&mut conf.conf.allowed_prefixes, DEFAULT_ALLOWED_PREFIXES); // TODO: THIS SHOULD BE TESTED, this comment will be gone soon if conf.conf.allowed_idents_below_min_chars.contains("..") { conf.conf diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index ee559d45d..256231441 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -35,7 +35,6 @@ struct FmtContext { } // the "main" function of cargo dev fmt -#[allow(clippy::missing_panics_doc)] pub fn run(check: bool, verbose: bool) { fn try_run(context: &FmtContext) -> Result { let mut success = true; diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index bb62e902c..385191e03 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -9,6 +9,7 @@ unused_lifetimes, unused_qualifications )] +#![allow(clippy::missing_panics_doc)] // The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate. #[allow(unused_extern_crates)] diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 5bd9994e1..397a0e990 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -46,6 +46,13 @@ fn main() { } }, Some(("setup", sub_command)) => match sub_command.subcommand() { + Some(("git-hook", matches)) => { + if matches.get_flag("remove") { + setup::git_hook::remove_hook(); + } else { + setup::git_hook::install_hook(matches.get_flag("force-override")); + } + }, Some(("intellij", matches)) => { if matches.get_flag("remove") { setup::intellij::remove_rustc_src(); @@ -57,12 +64,12 @@ fn main() { ); } }, - Some(("git-hook", matches)) => { - if matches.get_flag("remove") { - setup::git_hook::remove_hook(); - } else { - setup::git_hook::install_hook(matches.get_flag("force-override")); - } + Some(("toolchain", matches)) => { + setup::toolchain::create( + matches.get_flag("force"), + matches.get_flag("release"), + matches.get_one::("name").unwrap(), + ); }, Some(("vscode-tasks", matches)) => { if matches.get_flag("remove") { @@ -210,6 +217,19 @@ fn get_clap_config() -> ArgMatches { .about("Support for setting up your personal development environment") .arg_required_else_help(true) .subcommands([ + Command::new("git-hook") + .about("Add a pre-commit git hook that formats your code to make it look pretty") + .args([ + Arg::new("remove") + .long("remove") + .action(ArgAction::SetTrue) + .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"), + Arg::new("force-override") + .long("force-override") + .short('f') + .action(ArgAction::SetTrue) + .help("Forces the override of an existing git pre-commit hook"), + ]), Command::new("intellij") .about("Alter dependencies so Intellij Rust can find rustc internals") .args([ @@ -225,18 +245,23 @@ fn get_clap_config() -> ArgMatches { .conflicts_with("remove") .required(true), ]), - Command::new("git-hook") - .about("Add a pre-commit git hook that formats your code to make it look pretty") + Command::new("toolchain") + .about("Install a rustup toolchain pointing to the local clippy build") .args([ - Arg::new("remove") - .long("remove") - .action(ArgAction::SetTrue) - .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"), - Arg::new("force-override") - .long("force-override") + Arg::new("force") + .long("force") .short('f') .action(ArgAction::SetTrue) - .help("Forces the override of an existing git pre-commit hook"), + .help("Override an existing toolchain"), + Arg::new("release") + .long("release") + .short('r') + .action(ArgAction::SetTrue) + .help("Point to --release clippy binaries"), + Arg::new("name") + .long("name") + .default_value("clippy") + .help("The name of the created toolchain"), ]), Command::new("vscode-tasks") .about("Add several tasks to vscode for formatting, validation and testing") diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 5d9cde06c..2940d5635 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -36,7 +36,6 @@ impl Context for io::Result { /// # Errors /// /// This function errors out if the files couldn't be created or written to. -#[allow(clippy::missing_panics_doc)] pub fn create( pass: &String, lint_name: Option<&String>, diff --git a/clippy_dev/src/setup/mod.rs b/clippy_dev/src/setup/mod.rs index f691ae4fa..b0d318146 100644 --- a/clippy_dev/src/setup/mod.rs +++ b/clippy_dev/src/setup/mod.rs @@ -1,5 +1,6 @@ pub mod git_hook; pub mod intellij; +pub mod toolchain; pub mod vscode; use std::path::Path; diff --git a/clippy_dev/src/setup/toolchain.rs b/clippy_dev/src/setup/toolchain.rs new file mode 100644 index 000000000..8d98c6c92 --- /dev/null +++ b/clippy_dev/src/setup/toolchain.rs @@ -0,0 +1,75 @@ +use std::env::consts::EXE_SUFFIX; +use std::env::current_dir; +use std::ffi::OsStr; +use std::fs; +use std::path::{Path, PathBuf}; +use walkdir::WalkDir; + +use super::verify_inside_clippy_dir; + +pub fn create(force: bool, release: bool, name: &str) { + if !verify_inside_clippy_dir() { + return; + } + + let rustup_home = std::env::var("RUSTUP_HOME").unwrap(); + let toolchain = std::env::var("RUSTUP_TOOLCHAIN").unwrap(); + + let src = PathBuf::from_iter([&rustup_home, "toolchains", &toolchain]); + let dest = PathBuf::from_iter([&rustup_home, "toolchains", name]); + + if dest.exists() { + if force { + fs::remove_dir_all(&dest).unwrap(); + } else { + println!("{} already exists, pass `--force` to override it", dest.display()); + return; + } + } + + for entry in WalkDir::new(&src) { + let entry = entry.unwrap(); + let relative = entry.path().strip_prefix(&src).unwrap(); + + if relative.starts_with("bin") + && matches!( + relative.file_stem().and_then(OsStr::to_str), + Some("cargo-clippy" | "clippy-driver") + ) + { + continue; + } + + let target = dest.join(relative); + if entry.file_type().is_dir() { + fs::create_dir(&target).unwrap(); + } else { + fs::hard_link(entry.path(), target).unwrap(); + } + } + + symlink_bin("cargo-clippy", &dest, release); + symlink_bin("clippy-driver", &dest, release); + + println!("Created toolchain {name}, use it in other projects with e.g. `cargo +{name} clippy`"); + println!("Note: This will need to be re-run whenever the Clippy `rust-toolchain` changes"); +} + +fn symlink_bin(bin: &str, dest: &Path, release: bool) { + #[cfg(windows)] + use std::os::windows::fs::symlink_file as symlink; + + #[cfg(not(windows))] + use std::os::unix::fs::symlink; + + let profile = if release { "release" } else { "debug" }; + let file_name = format!("{bin}{EXE_SUFFIX}"); + + let mut src = current_dir().unwrap(); + src.extend(["target", profile, &file_name]); + + let mut dest = dest.to_path_buf(); + dest.extend(["bin", &file_name]); + + symlink(src, dest).unwrap(); +} diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 1102c7fb2..389338973 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -56,7 +56,12 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync { && let Some(send) = cx.tcx.get_diagnostic_item(sym::Send) && let Some(sync) = cx.tcx.lang_items().sync_trait() && let [is_send, is_sync] = [send, sync].map(|id| implements_trait(cx, arg_ty, id, &[])) - && !(is_send && is_sync) + && let reason = match (is_send, is_sync) { + (false, false) => "neither `Send` nor `Sync`", + (false, true) => "not `Send`", + (true, false) => "not `Sync`", + _ => return, + } && !is_from_proc_macro(cx, expr) { span_lint_and_then( @@ -66,21 +71,12 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync { "usage of an `Arc` that is not `Send` and `Sync`", |diag| { with_forced_trimmed_paths!({ - diag.note(format!("`Arc<{arg_ty}>` is not `Send` and `Sync` as:")); - - if !is_send { - diag.note(format!("- the trait `Send` is not implemented for `{arg_ty}`")); - } - if !is_sync { - diag.note(format!("- the trait `Sync` is not implemented for `{arg_ty}`")); - } - - diag.help("consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types"); - - diag.note("if you intend to use `Arc` with `Send` and `Sync` traits"); - diag.note(format!( - "wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `{arg_ty}`" + "`Arc<{arg_ty}>` is not `Send` and `Sync` as `{arg_ty}` is {reason}" + )); + diag.help("if the `Arc` will not used be across threads replace it with an `Rc`"); + diag.help(format!( + "otherwise make `{arg_ty}` `Send` and `Sync` or consider a wrapper type such as `Mutex`" )); }); }, diff --git a/clippy_lints/src/attrs/duplicated_attributes.rs b/clippy_lints/src/attrs/duplicated_attributes.rs index 3a8844d07..736ee4864 100644 --- a/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/clippy_lints/src/attrs/duplicated_attributes.rs @@ -2,12 +2,12 @@ use super::DUPLICATED_ATTRIBUTES; use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::{Attribute, MetaItem}; use rustc_data_structures::fx::FxHashMap; -use rustc_lint::EarlyContext; +use rustc_lint::LateContext; use rustc_span::{sym, Span}; use std::collections::hash_map::Entry; fn emit_if_duplicated( - cx: &EarlyContext<'_>, + cx: &LateContext<'_>, attr: &MetaItem, attr_paths: &mut FxHashMap, complete_path: String, @@ -26,7 +26,7 @@ fn emit_if_duplicated( } fn check_duplicated_attr( - cx: &EarlyContext<'_>, + cx: &LateContext<'_>, attr: &MetaItem, attr_paths: &mut FxHashMap, parent: &mut Vec, @@ -64,7 +64,7 @@ fn check_duplicated_attr( } } -pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { +pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { let mut attr_paths = FxHashMap::default(); for attr in attrs { diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 684ad7de2..8f47bc765 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -17,7 +17,7 @@ mod useless_attribute; mod utils; use clippy_config::msrvs::Msrv; -use rustc_ast::{Attribute, Crate, MetaItemKind, NestedMetaItem}; +use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, impl_lint_pass}; @@ -534,11 +534,13 @@ declare_lint_pass!(Attributes => [ BLANKET_CLIPPY_RESTRICTION_LINTS, SHOULD_PANIC_WITHOUT_EXPECT, MIXED_ATTRIBUTES_STYLE, + DUPLICATED_ATTRIBUTES, ]); impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_crate(&mut self, cx: &LateContext<'tcx>) { blanket_clippy_restriction_lints::check_command_line(cx); + duplicated_attributes::check(cx, cx.tcx.hir().krate_attrs()); } fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) { @@ -578,6 +580,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { _ => {}, } mixed_attributes_style::check(cx, item.span, attrs); + duplicated_attributes::check(cx, attrs); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { @@ -606,17 +609,11 @@ impl_lint_pass!(EarlyAttributes => [ MAYBE_MISUSED_CFG, DEPRECATED_CLIPPY_CFG_ATTR, UNNECESSARY_CLIPPY_CFG, - DUPLICATED_ATTRIBUTES, ]); impl EarlyLintPass for EarlyAttributes { - fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { - duplicated_attributes::check(cx, &krate.attrs); - } - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) { empty_line_after::check(cx, item); - duplicated_attributes::check(cx, &item.attrs); } fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 6edfebb55..b6341b3fe 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -346,11 +346,18 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { _ => None, } .and_then(|op| { - Some(format!( - "{}{op}{}", - snippet_opt(cx, lhs.span)?, - snippet_opt(cx, rhs.span)? - )) + let lhs_snippet = snippet_opt(cx, lhs.span)?; + let rhs_snippet = snippet_opt(cx, rhs.span)?; + + if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')')) { + if let (ExprKind::Cast(..), BinOpKind::Ge) = (&lhs.kind, binop.node) { + // e.g. `(a as u64) < b`. Without the parens the `<` is + // interpreted as a start of generic arguments for `u64` + return Some(format!("({lhs_snippet}){op}{rhs_snippet}")); + } + } + + Some(format!("{lhs_snippet}{op}{rhs_snippet}")) }) }, ExprKind::MethodCall(path, receiver, [], _) => { diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 063aab282..d14898a81 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -754,11 +754,7 @@ impl_lint_pass!(Casts => [ impl<'tcx> LateLintPass<'tcx> for Casts { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !in_external_macro(cx.sess(), expr.span) { - ptr_as_ptr::check(cx, expr, &self.msrv); - } - - if expr.span.from_expansion() { + if in_external_macro(cx.sess(), expr.span) { return; } @@ -771,7 +767,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { cx.typeck_results().expr_ty(expr), ); - if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) { + if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) { return; } cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv); @@ -782,7 +778,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to); zero_ptr::check(cx, expr, cast_expr, cast_to_hir); - if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) { + if cast_to.is_numeric() { cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span); if cast_from.is_numeric() { cast_possible_wrap::check(cx, expr, cast_from, cast_to); diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index bff40c2ae..89e2b3449 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1016,9 +1016,18 @@ fn report<'tcx>( }, _ => (0, false), }; + let is_in_tuple = matches!( + get_parent_expr(cx, data.first_expr), + Some(Expr { + kind: ExprKind::Tup(..), + .. + }) + ); + let sugg = if !snip_is_macro && (calls_field || expr.precedence().order() < precedence) && !has_enclosing_paren(&snip) + && !is_in_tuple { format!("({snip})") } else { diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 5f9700b76..42cd19fb8 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -132,7 +132,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// Deriving `serde::Deserialize` will create a constructor - /// that may violate invariants hold by another constructor. + /// that may violate invariants held by another constructor. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs index 26f120cb3..f935ae2e3 100644 --- a/clippy_lints/src/doc/missing_headers.rs +++ b/clippy_lints/src/doc/missing_headers.rs @@ -11,7 +11,7 @@ use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_D pub fn check( cx: &LateContext<'_>, owner_id: OwnerId, - sig: &FnSig<'_>, + sig: FnSig<'_>, headers: DocHeaders, body_id: Option, panic_span: Option, diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index b135e4e35..4bced104d 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::Visitable; -use clippy_utils::{is_entrypoint_fn, method_chain_args}; +use clippy_utils::{is_entrypoint_fn, is_trait_impl_item, method_chain_args}; use pulldown_cmark::Event::{ Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, }; @@ -11,9 +11,8 @@ use pulldown_cmark::Tag::{BlockQuote, CodeBlock, Heading, Item, Link, Paragraph} use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options}; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{AnonConst, Expr}; +use rustc_hir::{AnonConst, Expr, ImplItemKind, ItemKind, Node, TraitItemKind, Unsafety}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; @@ -366,7 +365,6 @@ declare_clippy_lint! { #[derive(Clone)] pub struct Documentation { valid_idents: FxHashSet, - in_trait_impl: bool, check_private_items: bool, } @@ -374,7 +372,6 @@ impl Documentation { pub fn new(valid_idents: &[String], check_private_items: bool) -> Self { Self { valid_idents: valid_idents.iter().cloned().collect(), - in_trait_impl: false, check_private_items, } } @@ -394,36 +391,72 @@ impl_lint_pass!(Documentation => [ ]); impl<'tcx> LateLintPass<'tcx> for Documentation { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID); - check_attrs(cx, &self.valid_idents, attrs); - } - - fn check_variant(&mut self, cx: &LateContext<'tcx>, variant: &'tcx hir::Variant<'tcx>) { - let attrs = cx.tcx.hir().attrs(variant.hir_id); - check_attrs(cx, &self.valid_idents, attrs); - } - - fn check_field_def(&mut self, cx: &LateContext<'tcx>, variant: &'tcx hir::FieldDef<'tcx>) { - let attrs = cx.tcx.hir().attrs(variant.hir_id); - check_attrs(cx, &self.valid_idents, attrs); - } - - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - let attrs = cx.tcx.hir().attrs(item.hir_id()); + fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return; }; - match item.kind { - hir::ItemKind::Fn(ref sig, _, body_id) => { - if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) { - let body = cx.tcx.hir().body(body_id); + match cx.tcx.hir_node(cx.last_node_with_lint_attrs) { + Node::Item(item) => match item.kind { + ItemKind::Fn(sig, _, body_id) => { + if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) { + let body = cx.tcx.hir().body(body_id); - let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); + let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); + missing_headers::check( + cx, + item.owner_id, + sig, + headers, + Some(body_id), + panic_span, + self.check_private_items, + ); + } + }, + ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) { + (false, Unsafety::Unsafe) => span_lint( + cx, + MISSING_SAFETY_DOC, + cx.tcx.def_span(item.owner_id), + "docs for unsafe trait missing `# Safety` section", + ), + (true, Unsafety::Normal) => span_lint( + cx, + UNNECESSARY_SAFETY_DOC, + cx.tcx.def_span(item.owner_id), + "docs for safe trait have unnecessary `# Safety` section", + ), + _ => (), + }, + _ => (), + }, + Node::TraitItem(trait_item) => { + if let TraitItemKind::Fn(sig, ..) = trait_item.kind + && !in_external_macro(cx.tcx.sess, trait_item.span) + { missing_headers::check( cx, - item.owner_id, + trait_item.owner_id, + sig, + headers, + None, + None, + self.check_private_items, + ); + } + }, + Node::ImplItem(impl_item) => { + if let ImplItemKind::Fn(sig, body_id) = impl_item.kind + && !in_external_macro(cx.tcx.sess, impl_item.span) + && !is_trait_impl_item(cx, impl_item.hir_id()) + { + let body = cx.tcx.hir().body(body_id); + + let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(impl_item.owner_id), body.value); + missing_headers::check( + cx, + impl_item.owner_id, sig, headers, Some(body_id), @@ -432,67 +465,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { ); } }, - hir::ItemKind::Impl(impl_) => { - self.in_trait_impl = impl_.of_trait.is_some(); - }, - hir::ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) { - (false, hir::Unsafety::Unsafe) => span_lint( - cx, - MISSING_SAFETY_DOC, - cx.tcx.def_span(item.owner_id), - "docs for unsafe trait missing `# Safety` section", - ), - (true, hir::Unsafety::Normal) => span_lint( - cx, - UNNECESSARY_SAFETY_DOC, - cx.tcx.def_span(item.owner_id), - "docs for safe trait have unnecessary `# Safety` section", - ), - _ => (), - }, - _ => (), - } - } - - fn check_item_post(&mut self, _cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - if let hir::ItemKind::Impl { .. } = item.kind { - self.in_trait_impl = false; - } - } - - fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { - let attrs = cx.tcx.hir().attrs(item.hir_id()); - let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { - return; - }; - if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind { - if !in_external_macro(cx.tcx.sess, item.span) { - missing_headers::check(cx, item.owner_id, sig, headers, None, None, self.check_private_items); - } - } - } - - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { - let attrs = cx.tcx.hir().attrs(item.hir_id()); - let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { - return; - }; - if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) { - return; - } - if let hir::ImplItemKind::Fn(ref sig, body_id) = item.kind { - let body = cx.tcx.hir().body(body_id); - - let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); - missing_headers::check( - cx, - item.owner_id, - sig, - headers, - Some(body_id), - panic_span, - self.check_private_items, - ); + _ => {}, } } } diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 799ec9d55..a4c3b0604 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -7,8 +7,8 @@ use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::HirId; use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::HirId; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 661512256..33764d3eb 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -5,6 +5,7 @@ use clippy_utils::is_bool; use clippy_utils::macros::span_is_local; use clippy_utils::source::is_present_in_source; use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case}; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -147,6 +148,7 @@ pub struct ItemNameRepetitions { struct_threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool, + allowed_prefixes: FxHashSet, } impl ItemNameRepetitions { @@ -156,6 +158,7 @@ impl ItemNameRepetitions { struct_threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool, + allowed_prefixes: &[String], ) -> Self { Self { modules: Vec::new(), @@ -163,8 +166,13 @@ impl ItemNameRepetitions { struct_threshold, avoid_breaking_exported_api, allow_private_module_inception, + allowed_prefixes: allowed_prefixes.iter().map(|s| to_camel_case(s)).collect(), } } + + fn is_allowed_prefix(&self, prefix: &str) -> bool { + self.allowed_prefixes.contains(prefix) + } } impl_lint_pass!(ItemNameRepetitions => [ @@ -423,7 +431,9 @@ impl LateLintPass<'_> for ItemNameRepetitions { _ => (), } } - if rmatching.char_count == nchars { + if rmatching.char_count == nchars + && !self.is_allowed_prefix(&item_camel[..item_camel.len() - rmatching.byte_count]) + { span_lint( cx, MODULE_NAME_REPETITIONS, diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index c5f1afe68..00124dcdd 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// `std::::EPSILON`, etc. /// /// ### Why is this bad? - /// All of these have been superceded by the associated constants on their respective types, + /// All of these have been superseded by the associated constants on their respective types, /// such as `i128::MAX`. These legacy items may be deprecated in a future version of rust. /// /// ### Example diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b92364a9d..e2aac58bf 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -594,6 +594,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { pub_underscore_fields_behavior, ref allowed_duplicate_crates, allow_comparison_to_zero, + ref allowed_prefixes, blacklisted_names: _, cyclomatic_complexity_threshold: _, @@ -864,6 +865,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { struct_field_name_threshold, avoid_breaking_exported_api, allow_private_module_inception, + allowed_prefixes, )) }); store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments)); diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 2bb63ec2b..443d6189c 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -291,10 +291,7 @@ fn elision_suggestions( }) => { // expand `&'a T` to `&'a T` // ^^ ^^^ - let span = cx - .sess() - .source_map() - .span_extend_while_whitespace(usage.ident.span); + let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span); (span, String::new()) }, diff --git a/clippy_lints/src/manual_unwrap_or_default.rs b/clippy_lints/src/manual_unwrap_or_default.rs index c562ceb5b..84fb183e3 100644 --- a/clippy_lints/src/manual_unwrap_or_default.rs +++ b/clippy_lints/src/manual_unwrap_or_default.rs @@ -1,13 +1,14 @@ -use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::ty::GenericArgKind; use rustc_session::declare_lint_pass; use rustc_span::sym; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::higher::IfLetOrMatch; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::{in_constant, is_default_equivalent, peel_blocks, span_contains_comment}; @@ -105,19 +106,39 @@ fn get_some_and_none_bodies<'tcx>( } } -fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - let ExprKind::Match(match_expr, [arm1, arm2], MatchSource::Normal | MatchSource::ForLoopDesugar) = expr.kind else { - return false; +#[allow(clippy::needless_pass_by_value)] +fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, expr: &'tcx Expr<'tcx>) { + // Get expr_name ("if let" or "match" depending on kind of expression), the condition, the body for + // the some arm, the body for the none arm and the binding id of the some arm + let (expr_name, condition, body_some, body_none, binding_id) = match if_let_or_match { + IfLetOrMatch::Match(condition, [arm1, arm2], MatchSource::Normal | MatchSource::ForLoopDesugar) + // Make sure there are no guards to keep things simple + if arm1.guard.is_none() + && arm2.guard.is_none() + // Get the some and none bodies and the binding id of the some arm + && let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2) => + { + ("match", condition, body_some, body_none, binding_id) + }, + IfLetOrMatch::IfLet(condition, pat, if_expr, Some(else_expr), _) + if let Some(binding_id) = get_some(cx, pat) => + { + ("if let", condition, if_expr, else_expr, binding_id) + }, + _ => { + // All other cases (match with number of arms != 2, if let without else, etc.) + return; + }, }; - // We don't want conditions on the arms to simplify things. - if arm1.guard.is_none() - && arm2.guard.is_none() - // We check that the returned type implements the `Default` trait. - && let match_ty = cx.typeck_results().expr_ty(expr) - && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default) - && implements_trait(cx, match_ty, default_trait_id, &[]) - // We now get the bodies for both the `Some` and `None` arms. - && let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2) + + // We check if the return type of the expression implements Default. + let expr_type = cx.typeck_results().expr_ty(expr); + if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default) + && implements_trait(cx, expr_type, default_trait_id, &[]) + // We check if the initial condition implements Default. + && let Some(condition_ty) = cx.typeck_results().expr_ty(condition).walk().nth(1) + && let GenericArgKind::Type(condition_ty) = condition_ty.unpack() + && implements_trait(cx, condition_ty, default_trait_id, &[]) // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`. && let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind && let Res::Local(local_id) = path.res @@ -125,8 +146,9 @@ fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { // We now check the `None` arm is calling a method equivalent to `Default::default`. && let body_none = peel_blocks(body_none) && is_default_equivalent(cx, body_none) - && let Some(receiver) = Sugg::hir_opt(cx, match_expr).map(Sugg::maybe_par) + && let Some(receiver) = Sugg::hir_opt(cx, condition).map(Sugg::maybe_par) { + // Machine applicable only if there are no comments present let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { Applicability::MaybeIncorrect } else { @@ -136,48 +158,12 @@ fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { cx, MANUAL_UNWRAP_OR_DEFAULT, expr.span, - "match can be simplified with `.unwrap_or_default()`", + format!("{expr_name} can be simplified with `.unwrap_or_default()`"), "replace it with", format!("{receiver}.unwrap_or_default()"), applicability, ); } - true -} - -fn handle_if_let<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let ExprKind::If(cond, if_block, Some(else_expr)) = expr.kind - && let ExprKind::Let(let_) = cond.kind - && let ExprKind::Block(_, _) = else_expr.kind - // We check that the returned type implements the `Default` trait. - && let match_ty = cx.typeck_results().expr_ty(expr) - && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default) - && implements_trait(cx, match_ty, default_trait_id, &[]) - && let Some(binding_id) = get_some(cx, let_.pat) - // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`. - && let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(if_block).kind - && let Res::Local(local_id) = path.res - && local_id == binding_id - // We now check the `None` arm is calling a method equivalent to `Default::default`. - && let body_else = peel_blocks(else_expr) - && is_default_equivalent(cx, body_else) - && let Some(if_let_expr_snippet) = snippet_opt(cx, let_.init.span) - { - let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { - Applicability::MaybeIncorrect - } else { - Applicability::MachineApplicable - }; - span_lint_and_sugg( - cx, - MANUAL_UNWRAP_OR_DEFAULT, - expr.span, - "if let can be simplified with `.unwrap_or_default()`", - "replace it with", - format!("{if_let_expr_snippet}.unwrap_or_default()"), - applicability, - ); - } } impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault { @@ -185,8 +171,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault { if expr.span.from_expansion() || in_constant(cx, expr.hir_id) { return; } - if !handle_match(cx, expr) { - handle_if_let(cx, expr); + // Call handle only if the expression is `if let` or `match` + if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) { + handle(cx, if_let_or_match, expr); } } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2fb317c8c..0939c0285 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3938,7 +3938,6 @@ declare_clippy_lint! { /// This lint cannot detect if the split is intentionally restricted to a single type of newline (`"\n"` or /// `"\r\n"`), for example during the parsing of a specific file format in which precisely one newline type is /// valid. - /// ``` #[clippy::version = "1.77.0"] pub STR_SPLIT_AT_NEWLINE, pedantic, diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index ac5cc2f01..f5f1e94bb 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -2,7 +2,8 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::deref_closure_args; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{is_trait_method, strip_pat_refs}; +use clippy_utils::{get_parent_expr, is_trait_method, strip_pat_refs}; +use hir::ExprKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; @@ -35,7 +36,7 @@ pub(super) fn check<'tcx>( // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()` let mut applicability = Applicability::MachineApplicable; let any_search_snippet = if search_method == "find" - && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind + && let ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind && let closure_body = cx.tcx.hir().body(body) && let Some(closure_arg) = closure_body.params.first() { @@ -72,16 +73,24 @@ pub(super) fn check<'tcx>( ); } else { let iter = snippet(cx, search_recv.span, ".."); + let sugg = if is_receiver_of_method_call(cx, expr) { + format!( + "(!{iter}.any({}))", + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ) + } else { + format!( + "!{iter}.any({})", + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ) + }; span_lint_and_sugg( cx, SEARCH_IS_SOME, expr.span, msg, "consider using", - format!( - "!{iter}.any({})", - any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) - ), + sugg, applicability, ); } @@ -127,13 +136,18 @@ pub(super) fn check<'tcx>( let string = snippet(cx, search_recv.span, ".."); let mut applicability = Applicability::MachineApplicable; let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability); + let sugg = if is_receiver_of_method_call(cx, expr) { + format!("(!{string}.contains({find_arg}))") + } else { + format!("!{string}.contains({find_arg})") + }; span_lint_and_sugg( cx, SEARCH_IS_SOME, expr.span, msg, "consider using", - format!("!{string}.contains({find_arg})"), + sugg, applicability, ); }, @@ -142,3 +156,13 @@ pub(super) fn check<'tcx>( } } } + +fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + if let Some(parent_expr) = get_parent_expr(cx, expr) + && let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind + && receiver.hir_id == expr.hir_id + { + return true; + } + false +} diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index c555fc867..a24cd4f9c 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -23,7 +23,7 @@ use std::collections::VecDeque; declare_clippy_lint! { /// ### What it does - /// Checks for borrow operations (`&`) that used as a generic argument to a + /// Checks for borrow operations (`&`) that are used as a generic argument to a /// function when the borrowed value could be used. /// /// ### Why is this bad? diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 5ca388d67..ff10a841a 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -18,7 +18,7 @@ use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, DUMMY_SP, InnerSpan, Span}; +use rustc_span::{sym, InnerSpan, Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; // FIXME: this is a correctness problem but there's no suitable @@ -297,12 +297,7 @@ impl NonCopyConst { fn is_value_unfrozen_expr<'tcx>(&self, cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { let args = cx.typeck_results().node_args(hir_id); - let result = Self::const_eval_resolve( - cx.tcx, - cx.param_env, - ty::UnevaluatedConst::new(def_id, args), - DUMMY_SP, - ); + let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), DUMMY_SP); self.is_value_unfrozen_raw(cx, result, ty) } diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 3aa979cb1..87a3c3874 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -300,11 +300,8 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { e.span, "calling `as_bytes()` on `include_str!(..)`", "consider using `include_bytes!(..)` instead", - snippet_with_applicability(cx, receiver.span.source_callsite(), r#""foo""#, &mut applicability).replacen( - "include_str", - "include_bytes", - 1, - ), + snippet_with_applicability(cx, receiver.span.source_callsite(), r#""foo""#, &mut applicability) + .replacen("include_str", "include_bytes", 1), applicability, ); } else if lit_content.as_str().is_ascii() diff --git a/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index 234021f0f..2bea3be3d 100644 --- a/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>( }; // FIXME: This can be simplified once `NonZero` is stable. - let coercable_types = [ + let coercible_types = [ ("NonZeroU8", tcx.types.u8), ("NonZeroU16", tcx.types.u16), ("NonZeroU32", tcx.types.u32), @@ -44,7 +44,7 @@ pub(super) fn check<'tcx>( let int_type = substs.type_at(0); - let Some(nonzero_alias) = coercable_types.iter().find_map(|(nonzero_alias, t)| { + let Some(nonzero_alias) = coercible_types.iter().find_map(|(nonzero_alias, t)| { if *t == int_type && *t == from_ty { Some(nonzero_alias) } else { diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index a6a6e9a3b..ba8c7d6bf 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -1,10 +1,10 @@ -use rustc_hir_typeck::cast::check_cast; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; use rustc_ast::ExprPrecedence; use rustc_errors::Applicability; use rustc_hir::{Expr, Node}; +use rustc_hir_typeck::cast::check_cast; use rustc_lint::LateContext; use rustc_middle::ty::cast::CastKind; use rustc_middle::ty::Ty; diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 9f0bd4ea7..0395eb144 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -709,8 +709,12 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound), - (ImplTrait(_, lg, lc), ImplTrait(_, rg, rc)) => - over(lg, rg, eq_generic_bound) && both(lc, rc, |lc, rc| over(lc.0.as_slice(), rc.0.as_slice(), eq_precise_capture)), + (ImplTrait(_, lg, lc), ImplTrait(_, rg, rc)) => { + over(lg, rg, eq_generic_bound) + && both(lc, rc, |lc, rc| { + over(lc.0.as_slice(), rc.0.as_slice(), eq_precise_capture) + }) + }, (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), _ => false, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index aac699eed..5e242aea3 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3285,7 +3285,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St Right(r) => Right(r.data), }); - // 2. for the remaning segments, construct relative path using only mod names and `super` + // 2. for the remaining segments, construct relative path using only mod names and `super` let mut go_up_by = 0; let mut path = Vec::new(); for el in unique_parts { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 1afc5ed01..a06a82c56 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -10,7 +10,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety}; -use rustc_infer::infer::type_variable::{TypeVariableOrigin}; +use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::interpret::Scalar; diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs index 762830ffd..2241494b4 100644 --- a/clippy_utils/src/ty/type_certainty/mod.rs +++ b/clippy_utils/src/ty/type_certainty/mod.rs @@ -90,7 +90,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty { if let Some(def_id) = adt_def_id(expr_ty) { certainty.with_def_id(def_id) } else { - certainty + certainty.clear_def_id() } } diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index 4251151c4..deb06094d 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -26,12 +26,12 @@ use std::env::consts::EXE_SUFFIX; use std::fmt::{self, Write as _}; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; -use std::process::Command; +use std::process::{Command, ExitStatus}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::Duration; use std::{env, fs, thread}; -use cargo_metadata::diagnostic::{Diagnostic, DiagnosticLevel}; +use cargo_metadata::diagnostic::Diagnostic; use cargo_metadata::Message; use rayon::prelude::*; use serde::{Deserialize, Serialize}; @@ -97,16 +97,43 @@ struct Crate { options: Option>, } +/// A single emitted output from clippy being executed on a crate. It may either be a +/// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many +/// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution). +#[derive(Debug)] +enum ClippyCheckOutput { + ClippyWarning(ClippyWarning), + RustcIce(RustcIce), +} + +#[derive(Debug)] +struct RustcIce { + pub crate_name: String, + pub ice_content: String, +} +impl RustcIce { + pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option { + if status.code().unwrap_or(0) == 101 + /* ice exit status */ + { + Some(Self { + crate_name: crate_name.to_owned(), + ice_content: stderr.to_owned(), + }) + } else { + None + } + } +} + /// A single warning that clippy issued while checking a `Crate` #[derive(Debug)] struct ClippyWarning { - crate_name: String, file: String, line: usize, column: usize, lint_type: String, message: String, - is_ice: bool, } #[allow(unused)] @@ -131,13 +158,11 @@ impl ClippyWarning { }; Some(Self { - crate_name: crate_name.to_owned(), file, line: span.line_start, column: span.column_start, lint_type, message: diag.message, - is_ice: diag.level == DiagnosticLevel::Ice, }) } @@ -318,7 +343,7 @@ impl Crate { config: &LintcheckConfig, lint_filter: &[String], server: &Option, - ) -> Vec { + ) -> Vec { // advance the atomic index by one let index = target_dir_index.fetch_add(1, Ordering::SeqCst); // "loop" the index within 0..thread_limit @@ -342,9 +367,9 @@ impl Crate { let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir"); let mut cargo_clippy_args = if config.fix { - vec!["--fix", "--"] + vec!["--quiet", "--fix", "--"] } else { - vec!["--", "--message-format=json", "--"] + vec!["--quiet", "--message-format=json", "--"] }; let mut clippy_args = Vec::<&str>::new(); @@ -435,14 +460,21 @@ impl Crate { } // get all clippy warnings and ICEs - let warnings: Vec = Message::parse_stream(stdout.as_bytes()) + let mut entries: Vec = Message::parse_stream(stdout.as_bytes()) .filter_map(|msg| match msg { Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message, &self.name, &self.version), _ => None, }) + .map(ClippyCheckOutput::ClippyWarning) .collect(); - warnings + if let Some(ice) = RustcIce::from_stderr_and_status(&self.name, *status, &stderr) { + entries.push(ClippyCheckOutput::RustcIce(ice)); + } else if !status.success() { + println!("non-ICE bad exit status for {} {}: {}", self.name, self.version, stderr); + } + + entries } } @@ -642,7 +674,7 @@ fn main() { LintcheckServer::spawn(recursive_options) }); - let mut clippy_warnings: Vec = crates + let mut clippy_entries: Vec = crates .par_iter() .flat_map(|krate| { krate.run_clippy_lints( @@ -658,7 +690,9 @@ fn main() { .collect(); if let Some(server) = server { - clippy_warnings.extend(server.warnings()); + let server_clippy_entries = server.warnings().map(ClippyCheckOutput::ClippyWarning); + + clippy_entries.extend(server_clippy_entries); } // if we are in --fix mode, don't change the log files, terminate here @@ -666,20 +700,21 @@ fn main() { return; } + // split up warnings and ices + let mut warnings: Vec = vec![]; + let mut raw_ices: Vec = vec![]; + for entry in clippy_entries { + if let ClippyCheckOutput::ClippyWarning(x) = entry { + warnings.push(x); + } else if let ClippyCheckOutput::RustcIce(x) = entry { + raw_ices.push(x); + } + } + // generate some stats - let (stats_formatted, new_stats) = gather_stats(&clippy_warnings); + let (stats_formatted, new_stats) = gather_stats(&warnings); - // grab crashes/ICEs, save the crate name and the ice message - let ices: Vec<(&String, &String)> = clippy_warnings - .iter() - .filter(|warning| warning.is_ice) - .map(|w| (&w.crate_name, &w.message)) - .collect(); - - let mut all_msgs: Vec = clippy_warnings - .iter() - .map(|warn| warn.to_output(config.markdown)) - .collect(); + let mut all_msgs: Vec = warnings.iter().map(|warn| warn.to_output(config.markdown)).collect(); all_msgs.sort(); all_msgs.push("\n\n### Stats:\n\n".into()); all_msgs.push(stats_formatted); @@ -693,11 +728,18 @@ fn main() { } write!(text, "{}", all_msgs.join("")).unwrap(); text.push_str("\n\n### ICEs:\n"); - for (cratename, msg) in &ices { - let _: fmt::Result = write!(text, "{cratename}: '{msg}'"); + for ice in &raw_ices { + let _: fmt::Result = write!( + text, + "{}:\n{}\n========================================\n\n", + ice.crate_name, ice.ice_content + ); } println!("Writing logs to {}", config.lintcheck_results_path.display()); + if !raw_ices.is_empty() { + println!("WARNING: at least one ICE reported, check log file"); + } fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap(); fs::write(&config.lintcheck_results_path, text).unwrap(); diff --git a/rust-toolchain b/rust-toolchain index b2fe5c8be..521c0d129 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-04-04" +channel = "nightly-2024-04-18" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/tests/ui-internal/custom_ice_message.rs b/tests/ui-internal/custom_ice_message.rs index 400bfd5d9..9b0db660c 100644 --- a/tests/ui-internal/custom_ice_message.rs +++ b/tests/ui-internal/custom_ice_message.rs @@ -5,7 +5,6 @@ //@normalize-stderr-test: "'rustc'" -> "''" //@normalize-stderr-test: "rustc 1\.\d+.* running on .*" -> "rustc running on " //@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" -//@normalize-stderr-test: "this compiler `.*` is outdated" -> "this compiler is outdated" #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/custom_ice_message.stderr b/tests/ui-internal/custom_ice_message.stderr index 763ce59ba..b99e8c0e7 100644 --- a/tests/ui-internal/custom_ice_message.stderr +++ b/tests/ui-internal/custom_ice_message.stderr @@ -4,10 +4,9 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: the compiler unexpectedly panicked. this is a bug. -note: it seems that this compiler is outdated, a newer nightly should have been released in the meantime - | - = note: please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists - = note: if the problem still persists, we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml +note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml + +note: please make sure that you have updated to the latest nightly note: rustc running on diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes/clippy.toml b/tests/ui-toml/item_name_repetitions/allowed_prefixes/clippy.toml new file mode 100644 index 000000000..35145551b --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes/clippy.toml @@ -0,0 +1 @@ +allowed-prefixes = ["bar"] diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs new file mode 100644 index 000000000..4142ced5f --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs @@ -0,0 +1,15 @@ +#![warn(clippy::module_name_repetitions)] +#![allow(dead_code)] + +mod foo { + // #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name. + // In this test, allowed prefixes are configured to be ["bar"]. + + // this line should produce a warning: + pub fn to_foo() {} + + // but this line shouldn't + pub fn bar_foo() {} +} + +fn main() {} diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.stderr b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.stderr new file mode 100644 index 000000000..6cfe0eab4 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.stderr @@ -0,0 +1,11 @@ +error: item name ends with its containing module's name + --> tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs:9:12 + | +LL | pub fn to_foo() {} + | ^^^^^^ + | + = note: `-D clippy::module-name-repetitions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/clippy.toml b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/clippy.toml new file mode 100644 index 000000000..31ef52467 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/clippy.toml @@ -0,0 +1 @@ +allowed-prefixes = ["..", "bar"] diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs new file mode 100644 index 000000000..b132305d0 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs @@ -0,0 +1,21 @@ +#![warn(clippy::module_name_repetitions)] +#![allow(dead_code)] + +mod foo { + // #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name. + // In this test, allowed prefixes are configured to be all of the default prefixes and ["bar"]. + + // this line should produce a warning: + pub fn something_foo() {} + + // but none of the following should: + pub fn bar_foo() {} + pub fn to_foo() {} + pub fn as_foo() {} + pub fn into_foo() {} + pub fn from_foo() {} + pub fn try_into_foo() {} + pub fn try_from_foo() {} +} + +fn main() {} diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.stderr b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.stderr new file mode 100644 index 000000000..f495ec421 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.stderr @@ -0,0 +1,11 @@ +error: item name ends with its containing module's name + --> tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs:9:12 + | +LL | pub fn something_foo() {} + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::module-name-repetitions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 737c062ea..24645b61f 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -14,6 +14,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars + allowed-prefixes allowed-scripts allowed-wildcard-imports arithmetic-side-effects-allowed @@ -93,6 +94,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars + allowed-prefixes allowed-scripts allowed-wildcard-imports arithmetic-side-effects-allowed @@ -172,6 +174,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars + allowed-prefixes allowed-scripts allowed-wildcard-imports arithmetic-side-effects-allowed diff --git a/tests/ui/arc_with_non_send_sync.rs b/tests/ui/arc_with_non_send_sync.rs index 349e81912..c287480bb 100644 --- a/tests/ui/arc_with_non_send_sync.rs +++ b/tests/ui/arc_with_non_send_sync.rs @@ -33,16 +33,9 @@ fn main() { let _ = Arc::new(42); let _ = Arc::new(RefCell::new(42)); - //~^ ERROR: usage of an `Arc` that is not `Send` and `Sync` - //~| NOTE: the trait `Sync` is not implemented for `RefCell` let mutex = Mutex::new(1); let _ = Arc::new(mutex.lock().unwrap()); - //~^ ERROR: usage of an `Arc` that is not `Send` and `Sync` - //~| NOTE: the trait `Send` is not implemented for `MutexGuard<'_, i32>` let _ = Arc::new(&42 as *const i32); - //~^ ERROR: usage of an `Arc` that is not `Send` and `Sync` - //~| NOTE: the trait `Send` is not implemented for `*const i32` - //~| NOTE: the trait `Sync` is not implemented for `*const i32` } diff --git a/tests/ui/arc_with_non_send_sync.stderr b/tests/ui/arc_with_non_send_sync.stderr index d4e630376..da363a3eb 100644 --- a/tests/ui/arc_with_non_send_sync.stderr +++ b/tests/ui/arc_with_non_send_sync.stderr @@ -4,38 +4,31 @@ error: usage of an `Arc` that is not `Send` and `Sync` LL | let _ = Arc::new(RefCell::new(42)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Arc>` is not `Send` and `Sync` as: - = note: - the trait `Sync` is not implemented for `RefCell` - = help: consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types - = note: if you intend to use `Arc` with `Send` and `Sync` traits - = note: wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `RefCell` + = note: `Arc>` is not `Send` and `Sync` as `RefCell` is not `Sync` + = help: if the `Arc` will not used be across threads replace it with an `Rc` + = help: otherwise make `RefCell` `Send` and `Sync` or consider a wrapper type such as `Mutex` = note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::arc_with_non_send_sync)]` error: usage of an `Arc` that is not `Send` and `Sync` - --> tests/ui/arc_with_non_send_sync.rs:40:13 + --> tests/ui/arc_with_non_send_sync.rs:38:13 | LL | let _ = Arc::new(mutex.lock().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Arc>` is not `Send` and `Sync` as: - = note: - the trait `Send` is not implemented for `MutexGuard<'_, i32>` - = help: consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types - = note: if you intend to use `Arc` with `Send` and `Sync` traits - = note: wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `MutexGuard<'_, i32>` + = note: `Arc>` is not `Send` and `Sync` as `MutexGuard<'_, i32>` is not `Send` + = help: if the `Arc` will not used be across threads replace it with an `Rc` + = help: otherwise make `MutexGuard<'_, i32>` `Send` and `Sync` or consider a wrapper type such as `Mutex` error: usage of an `Arc` that is not `Send` and `Sync` - --> tests/ui/arc_with_non_send_sync.rs:44:13 + --> tests/ui/arc_with_non_send_sync.rs:40:13 | LL | let _ = Arc::new(&42 as *const i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Arc<*const i32>` is not `Send` and `Sync` as: - = note: - the trait `Send` is not implemented for `*const i32` - = note: - the trait `Sync` is not implemented for `*const i32` - = help: consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types - = note: if you intend to use `Arc` with `Send` and `Sync` traits - = note: wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `*const i32` + = note: `Arc<*const i32>` is not `Send` and `Sync` as `*const i32` is neither `Send` nor `Sync` + = help: if the `Arc` will not used be across threads replace it with an `Rc` + = help: otherwise make `*const i32` `Send` and `Sync` or consider a wrapper type such as `Mutex` error: aborting due to 3 previous errors diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs index a6f3b164c..f6fdebaf2 100644 --- a/tests/ui/auxiliary/proc_macro_attr.rs +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -176,3 +176,17 @@ pub fn with_empty_docs(_attr: TokenStream, input: TokenStream) -> TokenStream { } .into() } + +#[proc_macro_attribute] +pub fn duplicated_attr(_attr: TokenStream, input: TokenStream) -> TokenStream { + let item = parse_macro_input!(input as syn::Item); + let attrs: Vec = vec![]; + quote! { + #(#attrs)* + #[allow(unused)] + #[allow(unused)] + #[allow(unused)] + #item + } + .into() +} diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index ce76ad3d3..215c00890 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -463,6 +463,18 @@ fn issue11642() { } } +fn issue11738() { + macro_rules! m { + () => { + let _ = i32::MIN as u32; // cast_sign_loss + let _ = u32::MAX as u8; // cast_possible_truncation + let _ = std::f64::consts::PI as f32; // cast_possible_truncation + let _ = 0i8 as i32; // cast_lossless + }; + } + m!(); +} + fn issue12506() -> usize { let bar: Result, u32> = Ok(Some(10)); bar.unwrap().unwrap() as usize diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 3736e8aee..8b269c471 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -650,8 +650,47 @@ error: casting `i32` to `u32` may lose the sign of the value LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: casting `i32` to `u32` may lose the sign of the value + --> tests/ui/cast.rs:469:21 + | +LL | let _ = i32::MIN as u32; // cast_sign_loss + | ^^^^^^^^^^^^^^^ +... +LL | m!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: casting `u32` to `u8` may truncate the value + --> tests/ui/cast.rs:470:21 + | +LL | let _ = u32::MAX as u8; // cast_possible_truncation + | ^^^^^^^^^^^^^^ +... +LL | m!(); + | ---- in this macro invocation + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: ... or use `try_from` and handle the error accordingly + | +LL | let _ = u8::try_from(u32::MAX); // cast_possible_truncation + | ~~~~~~~~~~~~~~~~~~~~~~ + +error: casting `f64` to `f32` may truncate the value + --> tests/ui/cast.rs:471:21 + | +LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | m!(); + | ---- in this macro invocation + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:468:5 + --> tests/ui/cast.rs:480:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -663,10 +702,10 @@ LL | usize::try_from(bar.unwrap().unwrap()) | error: casting `i64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:468:5 + --> tests/ui/cast.rs:480:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 87 previous errors +error: aborting due to 90 previous errors diff --git a/tests/ui/crashes/ice-12585.rs b/tests/ui/crashes/ice-12585.rs new file mode 100644 index 000000000..7928115c0 --- /dev/null +++ b/tests/ui/crashes/ice-12585.rs @@ -0,0 +1,26 @@ +#![allow(clippy::unit_arg)] + +struct One { + x: i32, +} +struct Two { + x: i32, +} + +struct Product {} + +impl Product { + pub fn a_method(self, _: ()) {} +} + +fn from_array(_: [i32; 2]) -> Product { + todo!() +} + +pub fn main() { + let one = One { x: 1 }; + let two = Two { x: 2 }; + + let product = from_array([one.x, two.x]); + product.a_method(<()>::default()); +} diff --git a/tests/ui/crashes/ice-12616.stderr b/tests/ui/crashes/ice-12616.stderr index ef573f55c..c7cf5cf54 100644 --- a/tests/ui/crashes/ice-12616.stderr +++ b/tests/ui/crashes/ice-12616.stderr @@ -7,13 +7,5 @@ LL | s() as *const (); = note: `-D clippy::ptr-as-ptr` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` -error: `as` casting between raw pointers without changing its mutability - --> tests/ui/crashes/ice-12616.rs:6:5 - | -LL | s() as *const (); - | ^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `s().cast::<()>()` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/doc/doc-fixable.fixed b/tests/ui/doc/doc-fixable.fixed index 178d4a1aa..7e22c847b 100644 --- a/tests/ui/doc/doc-fixable.fixed +++ b/tests/ui/doc/doc-fixable.fixed @@ -235,3 +235,8 @@ fn parenthesized_word() {} /// OSes /// UXes fn plural_acronym_test() {} + +extern { + /// `foo()` + fn in_extern(); +} diff --git a/tests/ui/doc/doc-fixable.rs b/tests/ui/doc/doc-fixable.rs index 01edb44c6..3e2cb0df5 100644 --- a/tests/ui/doc/doc-fixable.rs +++ b/tests/ui/doc/doc-fixable.rs @@ -235,3 +235,8 @@ fn parenthesized_word() {} /// OSes /// UXes fn plural_acronym_test() {} + +extern { + /// foo() + fn in_extern(); +} diff --git a/tests/ui/doc/doc-fixable.stderr b/tests/ui/doc/doc-fixable.stderr index ac876306b..cd2228c47 100644 --- a/tests/ui/doc/doc-fixable.stderr +++ b/tests/ui/doc/doc-fixable.stderr @@ -352,5 +352,16 @@ help: try LL | /// `ABes` | ~~~~~~ -error: aborting due to 32 previous errors +error: item in documentation is missing backticks + --> tests/ui/doc/doc-fixable.rs:240:9 + | +LL | /// foo() + | ^^^^^ + | +help: try + | +LL | /// `foo()` + | ~~~~~~~ + +error: aborting due to 33 previous errors diff --git a/tests/ui/duplicated_attributes.rs b/tests/ui/duplicated_attributes.rs index d051c881f..d51e7e37b 100644 --- a/tests/ui/duplicated_attributes.rs +++ b/tests/ui/duplicated_attributes.rs @@ -1,9 +1,14 @@ +//@aux-build:proc_macro_attr.rs + #![warn(clippy::duplicated_attributes)] #![cfg(any(unix, windows))] #![allow(dead_code)] #![allow(dead_code)] //~ ERROR: duplicated attribute #![cfg(any(unix, windows))] // Should not warn! +#[macro_use] +extern crate proc_macro_attr; + #[cfg(any(unix, windows, target_os = "linux"))] #[allow(dead_code)] #[allow(dead_code)] //~ ERROR: duplicated attribute @@ -12,7 +17,10 @@ fn foo() {} #[cfg(unix)] #[cfg(windows)] -#[cfg(unix)] //~ ERROR: duplicated attribute +#[cfg(unix)] // cfgs are not handled fn bar() {} +#[proc_macro_attr::duplicated_attr()] // Should not warn! +fn babar() {} + fn main() {} diff --git a/tests/ui/duplicated_attributes.stderr b/tests/ui/duplicated_attributes.stderr index 9e26ba990..0903617a8 100644 --- a/tests/ui/duplicated_attributes.stderr +++ b/tests/ui/duplicated_attributes.stderr @@ -1,16 +1,16 @@ error: duplicated attribute - --> tests/ui/duplicated_attributes.rs:4:10 + --> tests/ui/duplicated_attributes.rs:6:10 | LL | #![allow(dead_code)] | ^^^^^^^^^ | note: first defined here - --> tests/ui/duplicated_attributes.rs:3:10 + --> tests/ui/duplicated_attributes.rs:5:10 | LL | #![allow(dead_code)] | ^^^^^^^^^ help: remove this attribute - --> tests/ui/duplicated_attributes.rs:4:10 + --> tests/ui/duplicated_attributes.rs:6:10 | LL | #![allow(dead_code)] | ^^^^^^^^^ @@ -18,38 +18,21 @@ LL | #![allow(dead_code)] = help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]` error: duplicated attribute - --> tests/ui/duplicated_attributes.rs:9:9 + --> tests/ui/duplicated_attributes.rs:14:9 | LL | #[allow(dead_code)] | ^^^^^^^^^ | note: first defined here - --> tests/ui/duplicated_attributes.rs:8:9 + --> tests/ui/duplicated_attributes.rs:13:9 | LL | #[allow(dead_code)] | ^^^^^^^^^ help: remove this attribute - --> tests/ui/duplicated_attributes.rs:9:9 + --> tests/ui/duplicated_attributes.rs:14:9 | LL | #[allow(dead_code)] | ^^^^^^^^^ -error: duplicated attribute - --> tests/ui/duplicated_attributes.rs:15:7 - | -LL | #[cfg(unix)] - | ^^^^ - | -note: first defined here - --> tests/ui/duplicated_attributes.rs:13:7 - | -LL | #[cfg(unix)] - | ^^^^ -help: remove this attribute - --> tests/ui/duplicated_attributes.rs:15:7 - | -LL | #[cfg(unix)] - | ^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/manual_unwrap_or_default.fixed b/tests/ui/manual_unwrap_or_default.fixed index a0b707628..d6e736ba9 100644 --- a/tests/ui/manual_unwrap_or_default.fixed +++ b/tests/ui/manual_unwrap_or_default.fixed @@ -16,6 +16,16 @@ fn main() { let x: Option> = None; x.unwrap_or_default(); + + // Issue #12564 + // No error as &Vec<_> doesn't implement std::default::Default + let mut map = std::collections::HashMap::from([(0, vec![0; 3]), (1, vec![1; 3]), (2, vec![2])]); + let x: &[_] = if let Some(x) = map.get(&0) { x } else { &[] }; + // Same code as above written using match. + let x: &[_] = match map.get(&0) { + Some(x) => x, + None => &[], + }; } // Issue #12531 diff --git a/tests/ui/manual_unwrap_or_default.rs b/tests/ui/manual_unwrap_or_default.rs index 1d4cca12f..462d5d90e 100644 --- a/tests/ui/manual_unwrap_or_default.rs +++ b/tests/ui/manual_unwrap_or_default.rs @@ -37,6 +37,16 @@ fn main() { } else { Vec::default() }; + + // Issue #12564 + // No error as &Vec<_> doesn't implement std::default::Default + let mut map = std::collections::HashMap::from([(0, vec![0; 3]), (1, vec![1; 3]), (2, vec![2])]); + let x: &[_] = if let Some(x) = map.get(&0) { x } else { &[] }; + // Same code as above written using match. + let x: &[_] = match map.get(&0) { + Some(x) => x, + None => &[], + }; } // Issue #12531 diff --git a/tests/ui/manual_unwrap_or_default.stderr b/tests/ui/manual_unwrap_or_default.stderr index d89212e60..3f1da4443 100644 --- a/tests/ui/manual_unwrap_or_default.stderr +++ b/tests/ui/manual_unwrap_or_default.stderr @@ -53,7 +53,7 @@ LL | | }; | |_____^ help: replace it with: `x.unwrap_or_default()` error: match can be simplified with `.unwrap_or_default()` - --> tests/ui/manual_unwrap_or_default.rs:46:20 + --> tests/ui/manual_unwrap_or_default.rs:56:20 | LL | Some(_) => match *b { | ____________________^ diff --git a/tests/ui/module_name_repetitions.rs b/tests/ui/module_name_repetitions.rs index a6cf03890..b75ef87ab 100644 --- a/tests/ui/module_name_repetitions.rs +++ b/tests/ui/module_name_repetitions.rs @@ -19,6 +19,20 @@ mod foo { // Should not warn pub struct Foobar; + + // #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name. + pub fn to_foo() {} + pub fn into_foo() {} + pub fn as_foo() {} + pub fn from_foo() {} + pub fn try_into_foo() {} + pub fn try_from_foo() {} + pub trait IntoFoo {} + pub trait ToFoo {} + pub trait AsFoo {} + pub trait FromFoo {} + pub trait TryIntoFoo {} + pub trait TryFromFoo {} } fn main() {} diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index 8afb4df20..6b8a103d4 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -1,3 +1,4 @@ +//@needs-asm-support //@aux-build:proc_macros.rs #![allow(unused)] #![allow(deref_nullptr)] diff --git a/tests/ui/multiple_unsafe_ops_per_block.stderr b/tests/ui/multiple_unsafe_ops_per_block.stderr index cff85ae11..e732bde07 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -1,5 +1,5 @@ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:36:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:37:5 | LL | / unsafe { LL | | STATIC += 1; @@ -8,12 +8,12 @@ LL | | } | |_____^ | note: modification of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:37:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:38:9 | LL | STATIC += 1; | ^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:38:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:39:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | not_very_safe(); = help: to override `-D warnings` add `#[allow(clippy::multiple_unsafe_ops_per_block)]` error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:45:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:46:5 | LL | / unsafe { LL | | drop(u.u); @@ -30,18 +30,18 @@ LL | | } | |_____^ | note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:46:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:47:14 | LL | drop(u.u); | ^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:47:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:48:9 | LL | *raw_ptr(); | ^^^^^^^^^^ error: this `unsafe` block contains 3 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:52:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:53:5 | LL | / unsafe { LL | | asm!("nop"); @@ -51,23 +51,23 @@ LL | | } | |_____^ | note: inline assembly used here - --> tests/ui/multiple_unsafe_ops_per_block.rs:53:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:54:9 | LL | asm!("nop"); | ^^^^^^^^^^^ note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:54:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:55:9 | LL | sample.not_very_safe(); | ^^^^^^^^^^^^^^^^^^^^^^ note: modification of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:55:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:56:9 | LL | STATIC = 0; | ^^^^^^^^^^ error: this `unsafe` block contains 6 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:61:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:62:5 | LL | / unsafe { LL | | drop(u.u); @@ -79,55 +79,55 @@ LL | | } | |_____^ | note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:62:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:63:14 | LL | drop(u.u); | ^^^ note: access of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:63:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:64:14 | LL | drop(STATIC); | ^^^^^^ note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:64:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:65:9 | LL | sample.not_very_safe(); | ^^^^^^^^^^^^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:65:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:66:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:66:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:67:9 | LL | *raw_ptr(); | ^^^^^^^^^^ note: inline assembly used here - --> tests/ui/multiple_unsafe_ops_per_block.rs:67:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:68:9 | LL | asm!("nop"); | ^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:105:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:106:5 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:105:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:106:14 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:105:39 + --> tests/ui/multiple_unsafe_ops_per_block.rs:106:39 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:123:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:124:5 | LL | / unsafe { LL | | x(); @@ -136,18 +136,18 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:124:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:125:9 | LL | x(); | ^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:125:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:126:9 | LL | x(); | ^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:134:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:135:9 | LL | / unsafe { LL | | T::X(); @@ -156,18 +156,18 @@ LL | | } | |_________^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:135:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:136:13 | LL | T::X(); | ^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:136:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:137:13 | LL | T::X(); | ^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:144:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:145:5 | LL | / unsafe { LL | | x.0(); @@ -176,12 +176,12 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:145:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:146:9 | LL | x.0(); | ^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:146:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:147:9 | LL | x.0(); | ^^^^^ diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index 998f5430f..5121077b4 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -251,3 +251,11 @@ mod issue_10253 { (&S).f::<()>(); } } + +fn issue_12268() { + let option = Some((&1,)); + let x = (&1,); + option.unwrap_or((x.0,)); + //~^ ERROR: this expression creates a reference which is immediately dereferenced by the + // compiler +} diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index acb2c74d8..e3a5cb280 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -251,3 +251,11 @@ mod issue_10253 { (&S).f::<()>(); } } + +fn issue_12268() { + let option = Some((&1,)); + let x = (&1,); + option.unwrap_or((&x.0,)); + //~^ ERROR: this expression creates a reference which is immediately dereferenced by the + // compiler +} diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index 5f0283387..4b2b17e7e 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -163,5 +163,11 @@ error: this expression borrows a value the compiler would automatically borrow LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` -error: aborting due to 27 previous errors +error: this expression creates a reference which is immediately dereferenced by the compiler + --> tests/ui/needless_borrow.rs:258:23 + | +LL | option.unwrap_or((&x.0,)); + | ^^^^ help: change this to: `x.0` + +error: aborting due to 28 previous errors diff --git a/tests/ui/nonminimal_bool_methods.fixed b/tests/ui/nonminimal_bool_methods.fixed index bd4be3e5a..aba599678 100644 --- a/tests/ui/nonminimal_bool_methods.fixed +++ b/tests/ui/nonminimal_bool_methods.fixed @@ -109,4 +109,12 @@ fn dont_warn_for_negated_partial_ord_comparison() { let _ = !(a >= b); } +fn issue_12625() { + let a = 0; + let b = 0; + if (a as u64) < b {} //~ ERROR: this boolean expression can be simplified + if (a as u64) < b {} //~ ERROR: this boolean expression can be simplified + if a as u64 > b {} //~ ERROR: this boolean expression can be simplified +} + fn main() {} diff --git a/tests/ui/nonminimal_bool_methods.rs b/tests/ui/nonminimal_bool_methods.rs index 4523c7385..35f22db1d 100644 --- a/tests/ui/nonminimal_bool_methods.rs +++ b/tests/ui/nonminimal_bool_methods.rs @@ -109,4 +109,12 @@ fn dont_warn_for_negated_partial_ord_comparison() { let _ = !(a >= b); } +fn issue_12625() { + let a = 0; + let b = 0; + if !(a as u64 >= b) {} //~ ERROR: this boolean expression can be simplified + if !((a as u64) >= b) {} //~ ERROR: this boolean expression can be simplified + if !(a as u64 <= b) {} //~ ERROR: this boolean expression can be simplified +} + fn main() {} diff --git a/tests/ui/nonminimal_bool_methods.stderr b/tests/ui/nonminimal_bool_methods.stderr index e32c8dacd..18da4e0d3 100644 --- a/tests/ui/nonminimal_bool_methods.stderr +++ b/tests/ui/nonminimal_bool_methods.stderr @@ -79,5 +79,23 @@ error: this boolean expression can be simplified LL | if !res.is_none() {} | ^^^^^^^^^^^^^^ help: try: `res.is_some()` -error: aborting due to 13 previous errors +error: this boolean expression can be simplified + --> tests/ui/nonminimal_bool_methods.rs:115:8 + | +LL | if !(a as u64 >= b) {} + | ^^^^^^^^^^^^^^^^ help: try: `(a as u64) < b` + +error: this boolean expression can be simplified + --> tests/ui/nonminimal_bool_methods.rs:116:8 + | +LL | if !((a as u64) >= b) {} + | ^^^^^^^^^^^^^^^^^^ help: try: `(a as u64) < b` + +error: this boolean expression can be simplified + --> tests/ui/nonminimal_bool_methods.rs:117:8 + | +LL | if !(a as u64 <= b) {} + | ^^^^^^^^^^^^^^^^ help: try: `a as u64 > b` + +error: aborting due to 16 previous errors diff --git a/tests/ui/ptr_as_ptr.fixed b/tests/ui/ptr_as_ptr.fixed index 61d37b8ba..fa15c3235 100644 --- a/tests/ui/ptr_as_ptr.fixed +++ b/tests/ui/ptr_as_ptr.fixed @@ -1,5 +1,4 @@ //@aux-build:proc_macros.rs -//@compile-flags: -Zdeduplicate-diagnostics=yes #![warn(clippy::ptr_as_ptr)] diff --git a/tests/ui/ptr_as_ptr.rs b/tests/ui/ptr_as_ptr.rs index 8f2068cd2..7ab52e63d 100644 --- a/tests/ui/ptr_as_ptr.rs +++ b/tests/ui/ptr_as_ptr.rs @@ -1,5 +1,4 @@ //@aux-build:proc_macros.rs -//@compile-flags: -Zdeduplicate-diagnostics=yes #![warn(clippy::ptr_as_ptr)] diff --git a/tests/ui/ptr_as_ptr.stderr b/tests/ui/ptr_as_ptr.stderr index e6cd697c7..e162f35ba 100644 --- a/tests/ui/ptr_as_ptr.stderr +++ b/tests/ui/ptr_as_ptr.stderr @@ -1,5 +1,5 @@ error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:19:33 + --> tests/ui/ptr_as_ptr.rs:18:33 | LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `Box::into_raw(Box::new(o)).cast::>()` @@ -8,37 +8,37 @@ LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::i = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:28:13 + --> tests/ui/ptr_as_ptr.rs:27:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:29:13 + --> tests/ui/ptr_as_ptr.rs:28:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:34:17 + --> tests/ui/ptr_as_ptr.rs:33:17 | LL | let _ = *ptr_ptr as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:47:25 + --> tests/ui/ptr_as_ptr.rs:46:25 | LL | let _: *const i32 = ptr as *const _; | ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:48:23 + --> tests/ui/ptr_as_ptr.rs:47:23 | LL | let _: *mut i32 = mut_ptr as _; | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:51:21 + --> tests/ui/ptr_as_ptr.rs:50:21 | LL | let _ = inline!($ptr as *const i32); | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::()` @@ -46,157 +46,157 @@ LL | let _ = inline!($ptr as *const i32); = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:72:13 + --> tests/ui/ptr_as_ptr.rs:71:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:73:13 + --> tests/ui/ptr_as_ptr.rs:72:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:80:9 + --> tests/ui/ptr_as_ptr.rs:79:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:84:9 + --> tests/ui/ptr_as_ptr.rs:83:9 | LL | std::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:89:9 + --> tests/ui/ptr_as_ptr.rs:88:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:93:9 + --> tests/ui/ptr_as_ptr.rs:92:9 | LL | core::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:98:9 + --> tests/ui/ptr_as_ptr.rs:97:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:102:9 + --> tests/ui/ptr_as_ptr.rs:101:9 | LL | std::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:107:9 + --> tests/ui/ptr_as_ptr.rs:106:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:111:9 + --> tests/ui/ptr_as_ptr.rs:110:9 | LL | core::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:118:9 + --> tests/ui/ptr_as_ptr.rs:117:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:122:9 + --> tests/ui/ptr_as_ptr.rs:121:9 | LL | std::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:127:9 + --> tests/ui/ptr_as_ptr.rs:126:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:131:9 + --> tests/ui/ptr_as_ptr.rs:130:9 | LL | core::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:136:9 + --> tests/ui/ptr_as_ptr.rs:135:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:140:9 + --> tests/ui/ptr_as_ptr.rs:139:9 | LL | std::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:145:9 + --> tests/ui/ptr_as_ptr.rs:144:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:149:9 + --> tests/ui/ptr_as_ptr.rs:148:9 | LL | core::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:156:9 + --> tests/ui/ptr_as_ptr.rs:155:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:160:9 + --> tests/ui/ptr_as_ptr.rs:159:9 | LL | std::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:165:9 + --> tests/ui/ptr_as_ptr.rs:164:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:169:9 + --> tests/ui/ptr_as_ptr.rs:168:9 | LL | core::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:174:9 + --> tests/ui/ptr_as_ptr.rs:173:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:178:9 + --> tests/ui/ptr_as_ptr.rs:177:9 | LL | std::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:183:9 + --> tests/ui/ptr_as_ptr.rs:182:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:187:9 + --> tests/ui/ptr_as_ptr.rs:186:9 | LL | core::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 51636392f..86a937b4d 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -213,3 +213,53 @@ mod issue7392 { let _ = !v.iter().any(|fp| test_u32_2(*fp.field)); } } + +mod issue_11910 { + fn computations() -> u32 { + 0 + } + + struct Foo; + impl Foo { + fn bar(&self, _: bool) {} + } + + fn test_normal_for_iter() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let _ = !v.iter().any(|x| *x == 42); + Foo.bar(!v.iter().any(|x| *x == 42)); + } + + fn test_then_for_iter() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + (!v.iter().any(|x| *x == 42)).then(computations); + } + + fn test_then_some_for_iter() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + (!v.iter().any(|x| *x == 42)).then_some(0); + } + + fn test_normal_for_str() { + let s = "hello"; + let _ = !s.contains("world"); + Foo.bar(!s.contains("world")); + let s = String::from("hello"); + let _ = !s.contains("world"); + Foo.bar(!s.contains("world")); + } + + fn test_then_for_str() { + let s = "hello"; + let _ = (!s.contains("world")).then(computations); + let s = String::from("hello"); + let _ = (!s.contains("world")).then(computations); + } + + fn test_then_some_for_str() { + let s = "hello"; + let _ = (!s.contains("world")).then_some(0); + let s = String::from("hello"); + let _ = (!s.contains("world")).then_some(0); + } +} diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index c7d773e18..c0103a015 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -219,3 +219,53 @@ mod issue7392 { let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); } } + +mod issue_11910 { + fn computations() -> u32 { + 0 + } + + struct Foo; + impl Foo { + fn bar(&self, _: bool) {} + } + + fn test_normal_for_iter() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let _ = v.iter().find(|x| **x == 42).is_none(); + Foo.bar(v.iter().find(|x| **x == 42).is_none()); + } + + fn test_then_for_iter() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + v.iter().find(|x| **x == 42).is_none().then(computations); + } + + fn test_then_some_for_iter() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + v.iter().find(|x| **x == 42).is_none().then_some(0); + } + + fn test_normal_for_str() { + let s = "hello"; + let _ = s.find("world").is_none(); + Foo.bar(s.find("world").is_none()); + let s = String::from("hello"); + let _ = s.find("world").is_none(); + Foo.bar(s.find("world").is_none()); + } + + fn test_then_for_str() { + let s = "hello"; + let _ = s.find("world").is_none().then(computations); + let s = String::from("hello"); + let _ = s.find("world").is_none().then(computations); + } + + fn test_then_some_for_str() { + let s = "hello"; + let _ = s.find("world").is_none().then_some(0); + let s = String::from("hello"); + let _ = s.find("world").is_none().then_some(0); + } +} diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index 4ad1e2508..2c858b9fb 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -282,5 +282,77 @@ error: called `is_none()` after searching an `Iterator` with `find` LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_2(*fp.field))` -error: aborting due to 43 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> tests/ui/search_is_some_fixable_none.rs:235:17 + | +LL | let _ = v.iter().find(|x| **x == 42).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> tests/ui/search_is_some_fixable_none.rs:236:17 + | +LL | Foo.bar(v.iter().find(|x| **x == 42).is_none()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> tests/ui/search_is_some_fixable_none.rs:241:9 + | +LL | v.iter().find(|x| **x == 42).is_none().then(computations); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))` + +error: called `is_none()` after searching an `Iterator` with `find` + --> tests/ui/search_is_some_fixable_none.rs:246:9 + | +LL | v.iter().find(|x| **x == 42).is_none().then_some(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:251:17 + | +LL | let _ = s.find("world").is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:252:17 + | +LL | Foo.bar(s.find("world").is_none()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:254:17 + | +LL | let _ = s.find("world").is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:255:17 + | +LL | Foo.bar(s.find("world").is_none()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:260:17 + | +LL | let _ = s.find("world").is_none().then(computations); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:262:17 + | +LL | let _ = s.find("world").is_none().then(computations); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:267:17 + | +LL | let _ = s.find("world").is_none().then_some(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` + +error: called `is_none()` after calling `find()` on a string + --> tests/ui/search_is_some_fixable_none.rs:269:17 + | +LL | let _ = s.find("world").is_none().then_some(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` + +error: aborting due to 55 previous errors diff --git a/tests/ui/unconditional_recursion.rs b/tests/ui/unconditional_recursion.rs index 70b390b00..a51fc567f 100644 --- a/tests/ui/unconditional_recursion.rs +++ b/tests/ui/unconditional_recursion.rs @@ -266,7 +266,7 @@ struct S13 { impl S13 { fn new() -> Self { - // Shoud not warn! + // Should not warn! Self::default() } } diff --git a/tests/ui/unnecessary_clippy_cfg.stderr b/tests/ui/unnecessary_clippy_cfg.stderr index fbc05743c..3d58c9eb5 100644 --- a/tests/ui/unnecessary_clippy_cfg.stderr +++ b/tests/ui/unnecessary_clippy_cfg.stderr @@ -57,5 +57,41 @@ error: no need to put clippy lints behind a `clippy` cfg LL | #![cfg_attr(clippy, deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#![deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg)]` -error: aborting due to 8 previous errors +error: duplicated attribute + --> tests/ui/unnecessary_clippy_cfg.rs:8:26 + | +LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] + | ^^^^^^^^^ + | +note: first defined here + --> tests/ui/unnecessary_clippy_cfg.rs:6:26 + | +LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] + | ^^^^^^^^^ +help: remove this attribute + --> tests/ui/unnecessary_clippy_cfg.rs:8:26 + | +LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] + | ^^^^^^^^^ + = note: `-D clippy::duplicated-attributes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]` + +error: duplicated attribute + --> tests/ui/unnecessary_clippy_cfg.rs:17:25 + | +LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] + | ^^^^^^^^^ + | +note: first defined here + --> tests/ui/unnecessary_clippy_cfg.rs:15:25 + | +LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] + | ^^^^^^^^^ +help: remove this attribute + --> tests/ui/unnecessary_clippy_cfg.rs:17:25 + | +LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] + | ^^^^^^^^^ + +error: aborting due to 10 previous errors diff --git a/tests/ui/useless_attribute.fixed b/tests/ui/useless_attribute.fixed index d1cdf73d5..81759086f 100644 --- a/tests/ui/useless_attribute.fixed +++ b/tests/ui/useless_attribute.fixed @@ -1,6 +1,6 @@ //@aux-build:proc_macro_derive.rs -#![allow(unused)] +#![allow(unused, clippy::duplicated_attributes)] #![warn(clippy::useless_attribute)] #![warn(unreachable_pub)] #![feature(rustc_private)] diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index d6aa7fa24..59a9dcf09 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -1,6 +1,6 @@ //@aux-build:proc_macro_derive.rs -#![allow(unused)] +#![allow(unused, clippy::duplicated_attributes)] #![warn(clippy::useless_attribute)] #![warn(unreachable_pub)] #![feature(rustc_private)] diff --git a/triagebot.toml b/triagebot.toml index d8131044f..901977da2 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -19,7 +19,12 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" -users_on_vacation = ["y21"] +users_on_vacation = [ + "y21", + "matthiaskrgr", + "giraffate", + "Centri3", +] [assign.owners] "/.github" = ["@flip1995"]