Merge remote-tracking branch 'upstream/master' into rustup

This commit is contained in:
Philipp Krones
2022-09-28 14:27:32 +02:00
323 changed files with 3669 additions and 1716 deletions

View File

@@ -6,11 +6,161 @@ document.
## Unreleased / In Rust Nightly ## Unreleased / In Rust Nightly
[d7b5cbf0...master](https://github.com/rust-lang/rust-clippy/compare/d7b5cbf0...master) [3c7e7dbc...master](https://github.com/rust-lang/rust-clippy/compare/3c7e7dbc...master)
## Rust 1.64
Current stable, released 2022-09-22
[d7b5cbf0...3c7e7dbc](https://github.com/rust-lang/rust-clippy/compare/d7b5cbf0...3c7e7dbc)
### New Lints
* [`arithmetic_side_effects`]
[#9130](https://github.com/rust-lang/rust-clippy/pull/9130)
* [`invalid_utf8_in_unchecked`]
[#9105](https://github.com/rust-lang/rust-clippy/pull/9105)
* [`assertions_on_result_states`]
[#9225](https://github.com/rust-lang/rust-clippy/pull/9225)
* [`manual_find`]
[#8649](https://github.com/rust-lang/rust-clippy/pull/8649)
* [`manual_retain`]
[#8972](https://github.com/rust-lang/rust-clippy/pull/8972)
* [`default_instead_of_iter_empty`]
[#8989](https://github.com/rust-lang/rust-clippy/pull/8989)
* [`manual_rem_euclid`]
[#9031](https://github.com/rust-lang/rust-clippy/pull/9031)
* [`obfuscated_if_else`]
[#9148](https://github.com/rust-lang/rust-clippy/pull/9148)
* [`std_instead_of_core`]
[#9103](https://github.com/rust-lang/rust-clippy/pull/9103)
* [`std_instead_of_alloc`]
[#9103](https://github.com/rust-lang/rust-clippy/pull/9103)
* [`alloc_instead_of_core`]
[#9103](https://github.com/rust-lang/rust-clippy/pull/9103)
* [`explicit_auto_deref`]
[#8355](https://github.com/rust-lang/rust-clippy/pull/8355)
### Moves and Deprecations
* Moved [`format_push_string`] to `restriction` (now allow-by-default)
[#9161](https://github.com/rust-lang/rust-clippy/pull/9161)
### Enhancements
* [`significant_drop_in_scrutinee`]: Now gives more context in the lint message
[#8981](https://github.com/rust-lang/rust-clippy/pull/8981)
* [`single_match`], [`single_match_else`]: Now catches more `Option` cases
[#8985](https://github.com/rust-lang/rust-clippy/pull/8985)
* [`unused_async`]: Now works for async methods
[#9025](https://github.com/rust-lang/rust-clippy/pull/9025)
* [`manual_filter_map`], [`manual_find_map`]: Now lint more expressions
[#8958](https://github.com/rust-lang/rust-clippy/pull/8958)
* [`question_mark`]: Now works for simple `if let` expressions
[#8356](https://github.com/rust-lang/rust-clippy/pull/8356)
* [`undocumented_unsafe_blocks`]: Now finds comments before the start of closures
[#9117](https://github.com/rust-lang/rust-clippy/pull/9117)
* [`trait_duplication_in_bounds`]: Now catches duplicate bounds in where clauses
[#8703](https://github.com/rust-lang/rust-clippy/pull/8703)
* [`shadow_reuse`], [`shadow_same`], [`shadow_unrelated`]: Now lint in const blocks
[#9124](https://github.com/rust-lang/rust-clippy/pull/9124)
* [`slow_vector_initialization`]: Now detects cases with `vec.capacity()`
[#8953](https://github.com/rust-lang/rust-clippy/pull/8953)
* [`unused_self`]: Now respects the `avoid-breaking-exported-api` config option
[#9199](https://github.com/rust-lang/rust-clippy/pull/9199)
* [`box_collection`]: Now supports all std collections
[#9170](https://github.com/rust-lang/rust-clippy/pull/9170)
### False Positive Fixes
* [`significant_drop_in_scrutinee`]: Now ignores calls to `IntoIterator::into_iter`
[#9140](https://github.com/rust-lang/rust-clippy/pull/9140)
* [`while_let_loop`]: Now ignores cases when the significant drop order would change
[#8981](https://github.com/rust-lang/rust-clippy/pull/8981)
* [`branches_sharing_code`]: Now ignores cases where moved variables have a significant
drop or variable modifications can affect the conditions
[#9138](https://github.com/rust-lang/rust-clippy/pull/9138)
* [`let_underscore_lock`]: Now ignores bindings that aren't locked
[#8990](https://github.com/rust-lang/rust-clippy/pull/8990)
* [`trivially_copy_pass_by_ref`]: Now tracks lifetimes and ignores cases where unsafe
pointers are used
[#8639](https://github.com/rust-lang/rust-clippy/pull/8639)
* [`let_unit_value`]: No longer ignores `#[allow]` attributes on the value
[#9082](https://github.com/rust-lang/rust-clippy/pull/9082)
* [`declare_interior_mutable_const`]: Now ignores the `thread_local!` macro
[#9015](https://github.com/rust-lang/rust-clippy/pull/9015)
* [`if_same_then_else`]: Now ignores branches with `todo!` and `unimplemented!`
[#9006](https://github.com/rust-lang/rust-clippy/pull/9006)
* [`enum_variant_names`]: Now ignores names with `_` prefixes
[#9032](https://github.com/rust-lang/rust-clippy/pull/9032)
* [`let_unit_value`]: Now ignores cases, where the unit type is manually specified
[#9056](https://github.com/rust-lang/rust-clippy/pull/9056)
* [`match_same_arms`]: Now ignores branches with `todo!`
[#9207](https://github.com/rust-lang/rust-clippy/pull/9207)
* [`assign_op_pattern`]: Ignores cases that break borrowing rules
[#9214](https://github.com/rust-lang/rust-clippy/pull/9214)
* [`extra_unused_lifetimes`]: No longer triggers in derive macros
[#9037](https://github.com/rust-lang/rust-clippy/pull/9037)
* [`mismatching_type_param_order`]: Now ignores complicated generic parameters
[#9146](https://github.com/rust-lang/rust-clippy/pull/9146)
* [`equatable_if_let`]: No longer lints in macros
[#9074](https://github.com/rust-lang/rust-clippy/pull/9074)
* [`new_without_default`]: Now ignores generics and lifetime parameters on `fn new`
[#9115](https://github.com/rust-lang/rust-clippy/pull/9115)
* [`needless_borrow`]: Now ignores cases that result in the execution of different traits
[#9096](https://github.com/rust-lang/rust-clippy/pull/9096)
* [`declare_interior_mutable_const`]: No longer triggers in thread-local initializers
[#9246](https://github.com/rust-lang/rust-clippy/pull/9246)
### Suggestion Fixes/Improvements
* [`type_repetition_in_bounds`]: The suggestion now works with maybe bounds
[#9132](https://github.com/rust-lang/rust-clippy/pull/9132)
* [`transmute_ptr_to_ref`]: Now suggests `pointer::cast` when possible
[#8939](https://github.com/rust-lang/rust-clippy/pull/8939)
* [`useless_format`]: Now suggests the correct variable name
[#9237](https://github.com/rust-lang/rust-clippy/pull/9237)
* [`or_fun_call`]: The lint emission will now only span over the `unwrap_or` call
[#9144](https://github.com/rust-lang/rust-clippy/pull/9144)
* [`neg_multiply`]: Now suggests adding parentheses around suggestion if needed
[#9026](https://github.com/rust-lang/rust-clippy/pull/9026)
* [`unnecessary_lazy_evaluations`]: Now suggest for `bool::then_some` for lazy evaluation
[#9099](https://github.com/rust-lang/rust-clippy/pull/9099)
* [`manual_flatten`]: Improved message for long code snippets
[#9156](https://github.com/rust-lang/rust-clippy/pull/9156)
* [`explicit_counter_loop`]: The suggestion is now machine applicable
[#9149](https://github.com/rust-lang/rust-clippy/pull/9149)
* [`needless_borrow`]: Now keeps parentheses around fields, when needed
[#9210](https://github.com/rust-lang/rust-clippy/pull/9210)
* [`while_let_on_iterator`]: The suggestion now works in `FnOnce` closures
[#9134](https://github.com/rust-lang/rust-clippy/pull/9134)
### ICE Fixes
* Fix ICEs related to `#![feature(generic_const_exprs)]` usage
[#9241](https://github.com/rust-lang/rust-clippy/pull/9241)
* Fix ICEs related to reference lints
[#9093](https://github.com/rust-lang/rust-clippy/pull/9093)
* [`question_mark`]: Fix ICE on zero field tuple structs
[#9244](https://github.com/rust-lang/rust-clippy/pull/9244)
### Documentation Improvements
* [`needless_option_take`]: Now includes a "What it does" and "Why is this bad?" section.
[#9022](https://github.com/rust-lang/rust-clippy/pull/9022)
### Others
* Using `--cap-lints=allow` and only `--force-warn`ing some will now work with Clippy's driver
[#9036](https://github.com/rust-lang/rust-clippy/pull/9036)
* Clippy now tries to read the `rust-version` from `Cargo.toml` to identify the
minimum supported rust version
[#8774](https://github.com/rust-lang/rust-clippy/pull/8774)
## Rust 1.63 ## Rust 1.63
Current stable, released 2022-08-11 Released 2022-08-11
[7c21f91b...d7b5cbf0](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...d7b5cbf0) [7c21f91b...d7b5cbf0](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...d7b5cbf0)
@@ -3609,6 +3759,7 @@ Released 2018-09-13
[`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
[`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box [`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
[`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection [`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection
[`box_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_default
[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec [`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
[`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code [`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
@@ -4124,6 +4275,7 @@ Released 2018-09-13
[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented [`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init [`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec [`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec
[`uninlined_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
[`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg [`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg
[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp [`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
[`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash [`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash

View File

@@ -28,7 +28,7 @@ tempfile = { version = "3.2", optional = true }
termize = "0.1" termize = "0.1"
[dev-dependencies] [dev-dependencies]
compiletest_rs = { version = "0.8", features = ["tmp"] } compiletest_rs = { version = "0.9", features = ["tmp"] }
tester = "0.9" tester = "0.9"
regex = "1.5" regex = "1.5"
toml = "0.5" toml = "0.5"
@@ -42,6 +42,7 @@ filetime = "0.2"
rustc-workspace-hack = "1.0" rustc-workspace-hack = "1.0"
# UI test dependencies # UI test dependencies
clap = { version = "3.1", features = ["derive"] }
clippy_utils = { path = "clippy_utils" } clippy_utils = { path = "clippy_utils" }
derive-new = "0.5" derive-new = "0.5"
if_chain = "1.0" if_chain = "1.0"

View File

@@ -82,16 +82,16 @@ pub fn run(check: bool, verbose: bool) {
fn output_err(err: CliError) { fn output_err(err: CliError) {
match err { match err {
CliError::CommandFailed(command, stderr) => { CliError::CommandFailed(command, stderr) => {
eprintln!("error: A command failed! `{}`\nstderr: {}", command, stderr); eprintln!("error: A command failed! `{command}`\nstderr: {stderr}");
}, },
CliError::IoError(err) => { CliError::IoError(err) => {
eprintln!("error: {}", err); eprintln!("error: {err}");
}, },
CliError::RustfmtNotInstalled => { CliError::RustfmtNotInstalled => {
eprintln!("error: rustfmt nightly is not installed."); eprintln!("error: rustfmt nightly is not installed.");
}, },
CliError::WalkDirError(err) => { CliError::WalkDirError(err) => {
eprintln!("error: {}", err); eprintln!("error: {err}");
}, },
CliError::IntellijSetupActive => { CliError::IntellijSetupActive => {
eprintln!( eprintln!(

View File

@@ -41,7 +41,7 @@ fn main() {
matches.contains_id("msrv"), matches.contains_id("msrv"),
) { ) {
Ok(_) => update_lints::update(update_lints::UpdateMode::Change), Ok(_) => update_lints::update(update_lints::UpdateMode::Change),
Err(e) => eprintln!("Unable to create lint: {}", e), Err(e) => eprintln!("Unable to create lint: {e}"),
} }
}, },
Some(("setup", sub_command)) => match sub_command.subcommand() { Some(("setup", sub_command)) => match sub_command.subcommand() {

View File

@@ -1,5 +1,5 @@
use crate::clippy_project_root; use crate::clippy_project_root;
use indoc::{indoc, writedoc}; use indoc::{formatdoc, writedoc};
use std::fmt::Write as _; use std::fmt::Write as _;
use std::fs::{self, OpenOptions}; use std::fs::{self, OpenOptions};
use std::io::prelude::*; use std::io::prelude::*;
@@ -23,7 +23,7 @@ impl<T> Context for io::Result<T> {
match self { match self {
Ok(t) => Ok(t), Ok(t) => Ok(t),
Err(e) => { Err(e) => {
let message = format!("{}: {}", text.as_ref(), e); let message = format!("{}: {e}", text.as_ref());
Err(io::Error::new(ErrorKind::Other, message)) Err(io::Error::new(ErrorKind::Other, message))
}, },
} }
@@ -72,7 +72,7 @@ fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
let lint_contents = get_lint_file_contents(lint, enable_msrv); let lint_contents = get_lint_file_contents(lint, enable_msrv);
let lint_path = format!("clippy_lints/src/{}.rs", lint.name); let lint_path = format!("clippy_lints/src/{}.rs", lint.name);
write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())?; write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())?;
println!("Generated lint file: `{}`", lint_path); println!("Generated lint file: `{lint_path}`");
Ok(()) Ok(())
} }
@@ -86,7 +86,7 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
path.push("src"); path.push("src");
fs::create_dir(&path)?; fs::create_dir(&path)?;
let header = format!("// compile-flags: --crate-name={}", lint_name); let header = format!("// compile-flags: --crate-name={lint_name}");
write_file(path.join("main.rs"), get_test_file_contents(lint_name, Some(&header)))?; write_file(path.join("main.rs"), get_test_file_contents(lint_name, Some(&header)))?;
Ok(()) Ok(())
@@ -106,7 +106,7 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
let test_contents = get_test_file_contents(lint.name, None); let test_contents = get_test_file_contents(lint.name, None);
write_file(lint.project_root.join(&test_path), test_contents)?; write_file(lint.project_root.join(&test_path), test_contents)?;
println!("Generated test file: `{}`", test_path); println!("Generated test file: `{test_path}`");
} }
Ok(()) Ok(())
@@ -186,38 +186,36 @@ pub(crate) fn get_stabilization_version() -> String {
} }
fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String { fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String {
let mut contents = format!( let mut contents = formatdoc!(
indoc! {" r#"
#![allow(unused)] #![allow(unused)]
#![warn(clippy::{})] #![warn(clippy::{lint_name})]
fn main() {{ fn main() {{
// test code goes here // test code goes here
}} }}
"}, "#
lint_name
); );
if let Some(header) = header_commands { if let Some(header) = header_commands {
contents = format!("{}\n{}", header, contents); contents = format!("{header}\n{contents}");
} }
contents contents
} }
fn get_manifest_contents(lint_name: &str, hint: &str) -> String { fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
format!( formatdoc!(
indoc! {r#" r#"
# {} # {hint}
[package] [package]
name = "{}" name = "{lint_name}"
version = "0.1.0" version = "0.1.0"
publish = false publish = false
[workspace] [workspace]
"#}, "#
hint, lint_name
) )
} }
@@ -238,38 +236,32 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
let name_upper = lint_name.to_uppercase(); let name_upper = lint_name.to_uppercase();
result.push_str(&if enable_msrv { result.push_str(&if enable_msrv {
format!( formatdoc!(
indoc! {" r#"
use clippy_utils::msrvs; use clippy_utils::msrvs;
{pass_import} {pass_import}
use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::{{declare_tool_lint, impl_lint_pass}}; use rustc_session::{{declare_tool_lint, impl_lint_pass}};
"}, "#
pass_type = pass_type,
pass_import = pass_import,
context_import = context_import,
) )
} else { } else {
format!( formatdoc!(
indoc! {" r#"
{pass_import} {pass_import}
use rustc_lint::{{{context_import}, {pass_type}}}; use rustc_lint::{{{context_import}, {pass_type}}};
use rustc_session::{{declare_lint_pass, declare_tool_lint}}; use rustc_session::{{declare_lint_pass, declare_tool_lint}};
"}, "#
pass_import = pass_import,
pass_type = pass_type,
context_import = context_import
) )
}); });
let _ = write!(result, "{}", get_lint_declaration(&name_upper, category)); let _ = write!(result, "{}", get_lint_declaration(&name_upper, category));
result.push_str(&if enable_msrv { result.push_str(&if enable_msrv {
format!( formatdoc!(
indoc! {" r#"
pub struct {name_camel} {{ pub struct {name_camel} {{
msrv: Option<RustcVersion>, msrv: Option<RustcVersion>,
}} }}
@@ -290,24 +282,15 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
// TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed. // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed.
// TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`. // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`.
// TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs` // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
"}, "#
pass_type = pass_type,
pass_lifetimes = pass_lifetimes,
name_upper = name_upper,
name_camel = name_camel,
context_import = context_import,
) )
} else { } else {
format!( formatdoc!(
indoc! {" r#"
declare_lint_pass!({name_camel} => [{name_upper}]); declare_lint_pass!({name_camel} => [{name_upper}]);
impl {pass_type}{pass_lifetimes} for {name_camel} {{}} impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
"}, "#
pass_type = pass_type,
pass_lifetimes = pass_lifetimes,
name_upper = name_upper,
name_camel = name_camel,
) )
}); });
@@ -315,8 +298,8 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
} }
fn get_lint_declaration(name_upper: &str, category: &str) -> String { fn get_lint_declaration(name_upper: &str, category: &str) -> String {
format!( formatdoc!(
indoc! {r#" r#"
declare_clippy_lint! {{ declare_clippy_lint! {{
/// ### What it does /// ### What it does
/// ///
@@ -330,15 +313,13 @@ fn get_lint_declaration(name_upper: &str, category: &str) -> String {
/// ```rust /// ```rust
/// // example code which does not raise clippy warning /// // example code which does not raise clippy warning
/// ``` /// ```
#[clippy::version = "{version}"] #[clippy::version = "{}"]
pub {name_upper}, pub {name_upper},
{category}, {category},
"default lint description" "default lint description"
}} }}
"#}, "#,
version = get_stabilization_version(), get_stabilization_version(),
name_upper = name_upper,
category = category,
) )
} }
@@ -352,7 +333,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
_ => {}, _ => {},
} }
let ty_dir = lint.project_root.join(format!("clippy_lints/src/{}", ty)); let ty_dir = lint.project_root.join(format!("clippy_lints/src/{ty}"));
assert!( assert!(
ty_dir.exists() && ty_dir.is_dir(), ty_dir.exists() && ty_dir.is_dir(),
"Directory `{}` does not exist!", "Directory `{}` does not exist!",
@@ -412,10 +393,10 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
} }
write_file(lint_file_path.as_path(), lint_file_contents)?; write_file(lint_file_path.as_path(), lint_file_contents)?;
println!("Generated lint file: `clippy_lints/src/{}/{}.rs`", ty, lint.name); println!("Generated lint file: `clippy_lints/src/{ty}/{}.rs`", lint.name);
println!( println!(
"Be sure to add a call to `{}::check` in `clippy_lints/src/{}/mod.rs`!", "Be sure to add a call to `{}::check` in `clippy_lints/src/{ty}/mod.rs`!",
lint.name, ty lint.name
); );
Ok(()) Ok(())
@@ -542,7 +523,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
.chain(std::iter::once(&*lint_name_upper)) .chain(std::iter::once(&*lint_name_upper))
.filter(|s| !s.is_empty()) .filter(|s| !s.is_empty())
{ {
let _ = write!(new_arr_content, "\n {},", ident); let _ = write!(new_arr_content, "\n {ident},");
} }
new_arr_content.push('\n'); new_arr_content.push('\n');

View File

@@ -10,8 +10,8 @@ use std::time::{Duration, SystemTime};
/// Panics if the python commands could not be spawned /// Panics if the python commands could not be spawned
pub fn run(port: u16, lint: Option<&String>) -> ! { pub fn run(port: u16, lint: Option<&String>) -> ! {
let mut url = Some(match lint { let mut url = Some(match lint {
None => format!("http://localhost:{}", port), None => format!("http://localhost:{port}"),
Some(lint) => format!("http://localhost:{}/#{}", port, lint), Some(lint) => format!("http://localhost:{port}/#{lint}"),
}); });
loop { loop {

View File

@@ -30,10 +30,7 @@ pub fn install_hook(force_override: bool) {
println!("info: the hook can be removed with `cargo dev remove git-hook`"); println!("info: the hook can be removed with `cargo dev remove git-hook`");
println!("git hook successfully installed"); println!("git hook successfully installed");
}, },
Err(err) => eprintln!( Err(err) => eprintln!("error: unable to copy `{HOOK_SOURCE_FILE}` to `{HOOK_TARGET_FILE}` ({err})"),
"error: unable to copy `{}` to `{}` ({})",
HOOK_SOURCE_FILE, HOOK_TARGET_FILE, err
),
} }
} }
@@ -77,7 +74,7 @@ pub fn remove_hook() {
fn delete_git_hook_file(path: &Path) -> bool { fn delete_git_hook_file(path: &Path) -> bool {
if let Err(err) = fs::remove_file(path) { if let Err(err) = fs::remove_file(path) {
eprintln!("error: unable to delete existing pre-commit git hook ({})", err); eprintln!("error: unable to delete existing pre-commit git hook ({err})");
false false
} else { } else {
true true

View File

@@ -60,7 +60,7 @@ fn check_and_get_rustc_dir(rustc_path: &str) -> Result<PathBuf, ()> {
path = absolute_path; path = absolute_path;
}, },
Err(err) => { Err(err) => {
eprintln!("error: unable to get the absolute path of rustc ({})", err); eprintln!("error: unable to get the absolute path of rustc ({err})");
return Err(()); return Err(());
}, },
}; };
@@ -103,14 +103,14 @@ fn inject_deps_into_project(rustc_source_dir: &Path, project: &ClippyProjectInfo
fn read_project_file(file_path: &str) -> Result<String, ()> { fn read_project_file(file_path: &str) -> Result<String, ()> {
let path = Path::new(file_path); let path = Path::new(file_path);
if !path.exists() { if !path.exists() {
eprintln!("error: unable to find the file `{}`", file_path); eprintln!("error: unable to find the file `{file_path}`");
return Err(()); return Err(());
} }
match fs::read_to_string(path) { match fs::read_to_string(path) {
Ok(content) => Ok(content), Ok(content) => Ok(content),
Err(err) => { Err(err) => {
eprintln!("error: the file `{}` could not be read ({})", file_path, err); eprintln!("error: the file `{file_path}` could not be read ({err})");
Err(()) Err(())
}, },
} }
@@ -124,10 +124,7 @@ fn inject_deps_into_manifest(
) -> std::io::Result<()> { ) -> std::io::Result<()> {
// do not inject deps if we have already done so // do not inject deps if we have already done so
if cargo_toml.contains(RUSTC_PATH_SECTION) { if cargo_toml.contains(RUSTC_PATH_SECTION) {
eprintln!( eprintln!("warn: dependencies are already setup inside {manifest_path}, skipping file");
"warn: dependencies are already setup inside {}, skipping file",
manifest_path
);
return Ok(()); return Ok(());
} }
@@ -142,11 +139,7 @@ fn inject_deps_into_manifest(
let new_deps = extern_crates.map(|dep| { let new_deps = extern_crates.map(|dep| {
// format the dependencies that are going to be put inside the Cargo.toml // format the dependencies that are going to be put inside the Cargo.toml
format!( format!("{dep} = {{ path = \"{}/{dep}\" }}\n", rustc_source_dir.display())
"{dep} = {{ path = \"{source_path}/{dep}\" }}\n",
dep = dep,
source_path = rustc_source_dir.display()
)
}); });
// format a new [dependencies]-block with the new deps we need to inject // format a new [dependencies]-block with the new deps we need to inject
@@ -163,11 +156,11 @@ fn inject_deps_into_manifest(
// etc // etc
let new_manifest = cargo_toml.replacen("[dependencies]\n", &all_deps, 1); let new_manifest = cargo_toml.replacen("[dependencies]\n", &all_deps, 1);
// println!("{}", new_manifest); // println!("{new_manifest}");
let mut file = File::create(manifest_path)?; let mut file = File::create(manifest_path)?;
file.write_all(new_manifest.as_bytes())?; file.write_all(new_manifest.as_bytes())?;
println!("info: successfully setup dependencies inside {}", manifest_path); println!("info: successfully setup dependencies inside {manifest_path}");
Ok(()) Ok(())
} }
@@ -214,8 +207,8 @@ fn remove_rustc_src_from_project(project: &ClippyProjectInfo) -> bool {
}, },
Err(err) => { Err(err) => {
eprintln!( eprintln!(
"error: unable to open file `{}` to remove rustc dependencies for {} ({})", "error: unable to open file `{}` to remove rustc dependencies for {} ({err})",
project.cargo_file, project.name, err project.cargo_file, project.name
); );
false false
}, },

View File

@@ -17,10 +17,7 @@ pub fn install_tasks(force_override: bool) {
println!("info: the task file can be removed with `cargo dev remove vscode-tasks`"); println!("info: the task file can be removed with `cargo dev remove vscode-tasks`");
println!("vscode tasks successfully installed"); println!("vscode tasks successfully installed");
}, },
Err(err) => eprintln!( Err(err) => eprintln!("error: unable to copy `{TASK_SOURCE_FILE}` to `{TASK_TARGET_FILE}` ({err})"),
"error: unable to copy `{}` to `{}` ({})",
TASK_SOURCE_FILE, TASK_TARGET_FILE, err
),
} }
} }
@@ -44,23 +41,17 @@ fn check_install_precondition(force_override: bool) -> bool {
return delete_vs_task_file(path); return delete_vs_task_file(path);
} }
eprintln!( eprintln!("error: there is already a `task.json` file inside the `{VSCODE_DIR}` directory");
"error: there is already a `task.json` file inside the `{}` directory",
VSCODE_DIR
);
println!("info: use the `--force-override` flag to override the existing `task.json` file"); println!("info: use the `--force-override` flag to override the existing `task.json` file");
return false; return false;
} }
} else { } else {
match fs::create_dir(vs_dir_path) { match fs::create_dir(vs_dir_path) {
Ok(_) => { Ok(_) => {
println!("info: created `{}` directory for clippy", VSCODE_DIR); println!("info: created `{VSCODE_DIR}` directory for clippy");
}, },
Err(err) => { Err(err) => {
eprintln!( eprintln!("error: the task target directory `{VSCODE_DIR}` could not be created ({err})");
"error: the task target directory `{}` could not be created ({})",
VSCODE_DIR, err
);
}, },
} }
} }
@@ -82,7 +73,7 @@ pub fn remove_tasks() {
fn delete_vs_task_file(path: &Path) -> bool { fn delete_vs_task_file(path: &Path) -> bool {
if let Err(err) = fs::remove_file(path) { if let Err(err) = fs::remove_file(path) {
eprintln!("error: unable to delete the existing `tasks.json` file ({})", err); eprintln!("error: unable to delete the existing `tasks.json` file ({err})");
return false; return false;
} }

View File

@@ -86,7 +86,7 @@ fn generate_lint_files(
) )
.sorted() .sorted()
{ {
writeln!(res, "[`{}`]: {}#{}", lint, DOCS_LINK, lint).unwrap(); writeln!(res, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap();
} }
}, },
); );
@@ -99,7 +99,7 @@ fn generate_lint_files(
"// end lints modules, do not remove this comment, its used in `update_lints`", "// end lints modules, do not remove this comment, its used in `update_lints`",
|res| { |res| {
for lint_mod in usable_lints.iter().map(|l| &l.module).unique().sorted() { for lint_mod in usable_lints.iter().map(|l| &l.module).unique().sorted() {
writeln!(res, "mod {};", lint_mod).unwrap(); writeln!(res, "mod {lint_mod};").unwrap();
} }
}, },
); );
@@ -129,7 +129,7 @@ fn generate_lint_files(
for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) { for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) {
let content = gen_lint_group_list(&lint_group, lints.iter()); let content = gen_lint_group_list(&lint_group, lints.iter());
process_file( process_file(
&format!("clippy_lints/src/lib.register_{}.rs", lint_group), &format!("clippy_lints/src/lib.register_{lint_group}.rs"),
update_mode, update_mode,
&content, &content,
); );
@@ -190,9 +190,9 @@ fn print_lint_names(header: &str, lints: &BTreeSet<String>) -> bool {
if lints.is_empty() { if lints.is_empty() {
return false; return false;
} }
println!("{}", header); println!("{header}");
for lint in lints.iter().sorted() { for lint in lints.iter().sorted() {
println!(" {}", lint); println!(" {lint}");
} }
println!(); println!();
true true
@@ -205,16 +205,16 @@ pub fn print_lints() {
let grouped_by_lint_group = Lint::by_lint_group(usable_lints.into_iter()); let grouped_by_lint_group = Lint::by_lint_group(usable_lints.into_iter());
for (lint_group, mut lints) in grouped_by_lint_group { for (lint_group, mut lints) in grouped_by_lint_group {
println!("\n## {}", lint_group); println!("\n## {lint_group}");
lints.sort_by_key(|l| l.name.clone()); lints.sort_by_key(|l| l.name.clone());
for lint in lints { for lint in lints {
println!("* [{}]({}#{}) ({})", lint.name, DOCS_LINK, lint.name, lint.desc); println!("* [{}]({DOCS_LINK}#{}) ({})", lint.name, lint.name, lint.desc);
} }
} }
println!("there are {} lints", usable_lint_count); println!("there are {usable_lint_count} lints");
} }
/// Runs the `rename_lint` command. /// Runs the `rename_lint` command.
@@ -235,10 +235,10 @@ pub fn print_lints() {
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
pub fn rename(old_name: &str, new_name: &str, uplift: bool) { pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
if let Some((prefix, _)) = old_name.split_once("::") { if let Some((prefix, _)) = old_name.split_once("::") {
panic!("`{}` should not contain the `{}` prefix", old_name, prefix); panic!("`{old_name}` should not contain the `{prefix}` prefix");
} }
if let Some((prefix, _)) = new_name.split_once("::") { if let Some((prefix, _)) = new_name.split_once("::") {
panic!("`{}` should not contain the `{}` prefix", new_name, prefix); panic!("`{new_name}` should not contain the `{prefix}` prefix");
} }
let (mut lints, deprecated_lints, mut renamed_lints) = gather_all(); let (mut lints, deprecated_lints, mut renamed_lints) = gather_all();
@@ -251,14 +251,14 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
found_new_name = true; found_new_name = true;
} }
} }
let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{}`", old_name)); let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{old_name}`"));
let lint = RenamedLint { let lint = RenamedLint {
old_name: format!("clippy::{}", old_name), old_name: format!("clippy::{old_name}"),
new_name: if uplift { new_name: if uplift {
new_name.into() new_name.into()
} else { } else {
format!("clippy::{}", new_name) format!("clippy::{new_name}")
}, },
}; };
@@ -266,13 +266,11 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
// case. // case.
assert!( assert!(
!renamed_lints.iter().any(|l| lint.old_name == l.old_name), !renamed_lints.iter().any(|l| lint.old_name == l.old_name),
"`{}` has already been renamed", "`{old_name}` has already been renamed"
old_name
); );
assert!( assert!(
!deprecated_lints.iter().any(|l| lint.old_name == l.name), !deprecated_lints.iter().any(|l| lint.old_name == l.name),
"`{}` has already been deprecated", "`{old_name}` has already been deprecated"
old_name
); );
// Update all lint level attributes. (`clippy::lint_name`) // Update all lint level attributes. (`clippy::lint_name`)
@@ -309,14 +307,12 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
if uplift { if uplift {
write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints)); write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints));
println!( println!(
"`{}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually.", "`{old_name}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually."
old_name
); );
} else if found_new_name { } else if found_new_name {
write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints)); write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints));
println!( println!(
"`{}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually.", "`{new_name}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually."
new_name
); );
} else { } else {
// Rename the lint struct and source files sharing a name with the lint. // Rename the lint struct and source files sharing a name with the lint.
@@ -327,16 +323,16 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
// Rename test files. only rename `.stderr` and `.fixed` files if the new test name doesn't exist. // Rename test files. only rename `.stderr` and `.fixed` files if the new test name doesn't exist.
if try_rename_file( if try_rename_file(
Path::new(&format!("tests/ui/{}.rs", old_name)), Path::new(&format!("tests/ui/{old_name}.rs")),
Path::new(&format!("tests/ui/{}.rs", new_name)), Path::new(&format!("tests/ui/{new_name}.rs")),
) { ) {
try_rename_file( try_rename_file(
Path::new(&format!("tests/ui/{}.stderr", old_name)), Path::new(&format!("tests/ui/{old_name}.stderr")),
Path::new(&format!("tests/ui/{}.stderr", new_name)), Path::new(&format!("tests/ui/{new_name}.stderr")),
); );
try_rename_file( try_rename_file(
Path::new(&format!("tests/ui/{}.fixed", old_name)), Path::new(&format!("tests/ui/{old_name}.fixed")),
Path::new(&format!("tests/ui/{}.fixed", new_name)), Path::new(&format!("tests/ui/{new_name}.fixed")),
); );
} }
@@ -344,8 +340,8 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
let replacements; let replacements;
let replacements = if lint.module == old_name let replacements = if lint.module == old_name
&& try_rename_file( && try_rename_file(
Path::new(&format!("clippy_lints/src/{}.rs", old_name)), Path::new(&format!("clippy_lints/src/{old_name}.rs")),
Path::new(&format!("clippy_lints/src/{}.rs", new_name)), Path::new(&format!("clippy_lints/src/{new_name}.rs")),
) { ) {
// Edit the module name in the lint list. Note there could be multiple lints. // Edit the module name in the lint list. Note there could be multiple lints.
for lint in lints.iter_mut().filter(|l| l.module == old_name) { for lint in lints.iter_mut().filter(|l| l.module == old_name) {
@@ -356,14 +352,14 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
} else if !lint.module.contains("::") } else if !lint.module.contains("::")
// Catch cases like `methods/lint_name.rs` where the lint is stored in `methods/mod.rs` // Catch cases like `methods/lint_name.rs` where the lint is stored in `methods/mod.rs`
&& try_rename_file( && try_rename_file(
Path::new(&format!("clippy_lints/src/{}/{}.rs", lint.module, old_name)), Path::new(&format!("clippy_lints/src/{}/{old_name}.rs", lint.module)),
Path::new(&format!("clippy_lints/src/{}/{}.rs", lint.module, new_name)), Path::new(&format!("clippy_lints/src/{}/{new_name}.rs", lint.module)),
) )
{ {
// Edit the module name in the lint list. Note there could be multiple lints, or none. // Edit the module name in the lint list. Note there could be multiple lints, or none.
let renamed_mod = format!("{}::{}", lint.module, old_name); let renamed_mod = format!("{}::{old_name}", lint.module);
for lint in lints.iter_mut().filter(|l| l.module == renamed_mod) { for lint in lints.iter_mut().filter(|l| l.module == renamed_mod) {
lint.module = format!("{}::{}", lint.module, new_name); lint.module = format!("{}::{new_name}", lint.module);
} }
replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)];
replacements.as_slice() replacements.as_slice()
@@ -379,7 +375,7 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
} }
generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
println!("{} has been successfully renamed", old_name); println!("{old_name} has been successfully renamed");
} }
println!("note: `cargo uitest` still needs to be run to update the test results"); println!("note: `cargo uitest` still needs to be run to update the test results");
@@ -408,7 +404,7 @@ pub fn deprecate(name: &str, reason: Option<&String>) {
}); });
generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
println!("info: `{}` has successfully been deprecated", name); println!("info: `{name}` has successfully been deprecated");
if reason == DEFAULT_DEPRECATION_REASON { if reason == DEFAULT_DEPRECATION_REASON {
println!("note: the deprecation reason must be updated in `clippy_lints/src/deprecated_lints.rs`"); println!("note: the deprecation reason must be updated in `clippy_lints/src/deprecated_lints.rs`");
@@ -421,7 +417,7 @@ pub fn deprecate(name: &str, reason: Option<&String>) {
let name_upper = name.to_uppercase(); let name_upper = name.to_uppercase();
let (mut lints, deprecated_lints, renamed_lints) = gather_all(); let (mut lints, deprecated_lints, renamed_lints) = gather_all();
let Some(lint) = lints.iter().find(|l| l.name == name_lower) else { eprintln!("error: failed to find lint `{}`", name); return; }; let Some(lint) = lints.iter().find(|l| l.name == name_lower) else { eprintln!("error: failed to find lint `{name}`"); return; };
let mod_path = { let mod_path = {
let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module));
@@ -450,7 +446,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
} }
fn remove_test_assets(name: &str) { fn remove_test_assets(name: &str) {
let test_file_stem = format!("tests/ui/{}", name); let test_file_stem = format!("tests/ui/{name}");
let path = Path::new(&test_file_stem); let path = Path::new(&test_file_stem);
// Some lints have their own directories, delete them // Some lints have their own directories, delete them
@@ -512,8 +508,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy()));
eprintln!( eprintln!(
"warn: you will have to manually remove any code related to `{}` from `{}`", "warn: you will have to manually remove any code related to `{name}` from `{}`",
name,
path.display() path.display()
); );
@@ -528,7 +523,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
content.replace_range(lint.declaration_range.clone(), ""); content.replace_range(lint.declaration_range.clone(), "");
// Remove the module declaration (mod xyz;) // Remove the module declaration (mod xyz;)
let mod_decl = format!("\nmod {};", name); let mod_decl = format!("\nmod {name};");
content = content.replacen(&mod_decl, "", 1); content = content.replacen(&mod_decl, "", 1);
remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content); remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content);
@@ -621,13 +616,13 @@ fn round_to_fifty(count: usize) -> usize {
fn process_file(path: impl AsRef<Path>, update_mode: UpdateMode, content: &str) { fn process_file(path: impl AsRef<Path>, update_mode: UpdateMode, content: &str) {
if update_mode == UpdateMode::Check { if update_mode == UpdateMode::Check {
let old_content = let old_content =
fs::read_to_string(&path).unwrap_or_else(|e| panic!("Cannot read from {}: {}", path.as_ref().display(), e)); fs::read_to_string(&path).unwrap_or_else(|e| panic!("Cannot read from {}: {e}", path.as_ref().display()));
if content != old_content { if content != old_content {
exit_with_failure(); exit_with_failure();
} }
} else { } else {
fs::write(&path, content.as_bytes()) fs::write(&path, content.as_bytes())
.unwrap_or_else(|e| panic!("Cannot write to {}: {}", path.as_ref().display(), e)); .unwrap_or_else(|e| panic!("Cannot write to {}: {e}", path.as_ref().display()));
} }
} }
@@ -731,11 +726,10 @@ fn gen_lint_group_list<'a>(group_name: &str, lints: impl Iterator<Item = &'a Lin
let _ = writeln!( let _ = writeln!(
output, output,
"store.register_group(true, \"clippy::{0}\", Some(\"clippy_{0}\"), vec![", "store.register_group(true, \"clippy::{group_name}\", Some(\"clippy_{group_name}\"), vec![",
group_name
); );
for (module, name) in details { for (module, name) in details {
let _ = writeln!(output, " LintId::of({}::{}),", module, name); let _ = writeln!(output, " LintId::of({module}::{name}),");
} }
output.push_str("])\n"); output.push_str("])\n");
@@ -783,7 +777,7 @@ fn gen_register_lint_list<'a>(
if !is_public { if !is_public {
output.push_str(" #[cfg(feature = \"internal\")]\n"); output.push_str(" #[cfg(feature = \"internal\")]\n");
} }
let _ = writeln!(output, " {}::{},", module_name, lint_name); let _ = writeln!(output, " {module_name}::{lint_name},");
} }
output.push_str("])\n"); output.push_str("])\n");
@@ -841,7 +835,7 @@ fn gather_all() -> (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>) {
for (rel_path, file) in clippy_lints_src_files() { for (rel_path, file) in clippy_lints_src_files() {
let path = file.path(); let path = file.path();
let contents = let contents =
fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {}", path.display(), e)); fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display()));
let module = rel_path let module = rel_path
.components() .components()
.map(|c| c.as_os_str().to_str().unwrap()) .map(|c| c.as_os_str().to_str().unwrap())
@@ -1050,7 +1044,7 @@ fn remove_line_splices(s: &str) -> String {
.trim_matches('#') .trim_matches('#')
.strip_prefix('"') .strip_prefix('"')
.and_then(|s| s.strip_suffix('"')) .and_then(|s| s.strip_suffix('"'))
.unwrap_or_else(|| panic!("expected quoted string, found `{}`", s)); .unwrap_or_else(|| panic!("expected quoted string, found `{s}`"));
let mut res = String::with_capacity(s.len()); let mut res = String::with_capacity(s.len());
unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, ch| { unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, ch| {
if ch.is_ok() { if ch.is_ok() {
@@ -1076,10 +1070,10 @@ fn replace_region_in_file(
end: &str, end: &str,
write_replacement: impl FnMut(&mut String), write_replacement: impl FnMut(&mut String),
) { ) {
let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {}", path.display(), e)); let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display()));
let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) { let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) {
Ok(x) => x, Ok(x) => x,
Err(delim) => panic!("Couldn't find `{}` in file `{}`", delim, path.display()), Err(delim) => panic!("Couldn't find `{delim}` in file `{}`", path.display()),
}; };
match update_mode { match update_mode {
@@ -1087,7 +1081,7 @@ fn replace_region_in_file(
UpdateMode::Check => (), UpdateMode::Check => (),
UpdateMode::Change => { UpdateMode::Change => {
if let Err(e) = fs::write(path, new_contents.as_bytes()) { if let Err(e) = fs::write(path, new_contents.as_bytes()) {
panic!("Cannot write to `{}`: {}", path.display(), e); panic!("Cannot write to `{}`: {e}", path.display());
} }
}, },
} }
@@ -1135,7 +1129,7 @@ fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
fn panic_file(error: io::Error, name: &Path, action: &str) -> ! { fn panic_file(error: io::Error, name: &Path, action: &str) -> ! {
panic!("failed to {} file `{}`: {}", action, name.display(), error) panic!("failed to {action} file `{}`: {error}", name.display())
} }
fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option<String>) { fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option<String>) {

View File

@@ -18,7 +18,7 @@ quine-mc_cluskey = "0.2"
regex-syntax = "0.6" regex-syntax = "0.6"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", optional = true } serde_json = { version = "1.0", optional = true }
tempfile = { version = "3.2", optional = true } tempfile = { version = "3.3.0", optional = true }
toml = "0.5" toml = "0.5"
unicode-normalization = "0.1" unicode-normalization = "0.1"
unicode-script = { version = "0.5", default-features = false } unicode-script = { version = "0.5", default-features = false }

View File

@@ -92,7 +92,7 @@ impl ApproxConstant {
cx, cx,
APPROX_CONSTANT, APPROX_CONSTANT,
e.span, e.span,
&format!("approximate value of `{}::consts::{}` found", module, &name), &format!("approximate value of `{module}::consts::{}` found", &name),
None, None,
"consider using the constant directly", "consider using the constant directly",
); );
@@ -126,7 +126,7 @@ fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool {
// The value is a truncated constant // The value is a truncated constant
true true
} else { } else {
let round_const = format!("{:.*}", value.len() - 2, constant); let round_const = format!("{constant:.*}", value.len() - 2);
value == round_const value == round_const
} }
} }

View File

@@ -44,7 +44,7 @@ fn check_expr_asm_syntax(lint: &'static Lint, cx: &EarlyContext<'_>, expr: &Expr
cx, cx,
lint, lint,
expr.span, expr.span,
&format!("{} x86 assembly syntax used", style), &format!("{style} x86 assembly syntax used"),
None, None,
&format!("use {} x86 assembly syntax", !style), &format!("use {} x86 assembly syntax", !style),
); );

View File

@@ -60,9 +60,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
cx, cx,
ASSERTIONS_ON_CONSTANTS, ASSERTIONS_ON_CONSTANTS,
macro_call.span, macro_call.span,
&format!("`assert!(false{})` should probably be replaced", assert_arg), &format!("`assert!(false{assert_arg})` should probably be replaced"),
None, None,
&format!("use `panic!({})` or `unreachable!({0})`", panic_arg), &format!("use `panic!({panic_arg})` or `unreachable!({panic_arg})`"),
); );
} }
} }

View File

@@ -69,9 +69,8 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
"called `assert!` with `Result::is_ok`", "called `assert!` with `Result::is_ok`",
"replace with", "replace with",
format!( format!(
"{}.unwrap(){}", "{}.unwrap(){semicolon}",
snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0, snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
semicolon
), ),
app, app,
); );
@@ -84,9 +83,8 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
"called `assert!` with `Result::is_err`", "called `assert!` with `Result::is_err`",
"replace with", "replace with",
format!( format!(
"{}.unwrap_err(){}", "{}.unwrap_err(){semicolon}",
snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0, snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
semicolon
), ),
app, app,
); );

View File

@@ -541,10 +541,7 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribut
cx, cx,
INLINE_ALWAYS, INLINE_ALWAYS,
attr.span, attr.span,
&format!( &format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"),
"you have declared `#[inline(always)]` on `{}`. This is usually a bad idea",
name
),
); );
} }
} }
@@ -720,7 +717,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
let mut unix_suggested = false; let mut unix_suggested = false;
for (os, span) in mismatched { for (os, span) in mismatched {
let sugg = format!("target_os = \"{}\"", os); let sugg = format!("target_os = \"{os}\"");
diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect); diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect);
if !unix_suggested && is_unix(os) { if !unix_suggested && is_unix(os) {

View File

@@ -117,8 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
); );
} }
} else { } else {
let span = let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
if span.from_expansion() || expr.span.from_expansion() { if span.from_expansion() || expr.span.from_expansion() {
return; return;
} }

View File

@@ -98,9 +98,9 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
cx, cx,
BOOL_ASSERT_COMPARISON, BOOL_ASSERT_COMPARISON,
macro_call.span, macro_call.span,
&format!("used `{}!` with a literal bool", macro_name), &format!("used `{macro_name}!` with a literal bool"),
"replace it with", "replace it with",
format!("{}!(..)", non_eq_mac), format!("{non_eq_mac}!(..)"),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} }

View File

@@ -263,9 +263,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
} }
.and_then(|op| { .and_then(|op| {
Some(format!( Some(format!(
"{}{}{}", "{}{op}{}",
snippet_opt(cx, lhs.span)?, snippet_opt(cx, lhs.span)?,
op,
snippet_opt(cx, rhs.span)? snippet_opt(cx, rhs.span)?
)) ))
}) })
@@ -285,7 +284,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
let path: &str = path.ident.name.as_str(); let path: &str = path.ident.name.as_str();
a == path a == path
}) })
.and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, receiver.span)?, neg_method))) .and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", snippet_opt(cx, receiver.span)?)))
}, },
_ => None, _ => None,
} }

View File

@@ -0,0 +1,61 @@
use clippy_utils::{diagnostics::span_lint_and_help, is_default_equivalent, path_def_id};
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
/// checks for `Box::new(T::default())`, which is better written as
/// `Box::<T>::default()`.
///
/// ### Why is this bad?
/// First, it's more complex, involving two calls instead of one.
/// Second, `Box::default()` can be faster
/// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box).
///
/// ### Known problems
/// The lint may miss some cases (e.g. Box::new(String::from(""))).
/// On the other hand, it will trigger on cases where the `default`
/// code comes from a macro that does something different based on
/// e.g. target operating system.
///
/// ### Example
/// ```rust
/// let x: Box<String> = Box::new(Default::default());
/// ```
/// Use instead:
/// ```rust
/// let x: Box<String> = Box::default();
/// ```
#[clippy::version = "1.65.0"]
pub BOX_DEFAULT,
perf,
"Using Box::new(T::default()) instead of Box::default()"
}
declare_lint_pass!(BoxDefault => [BOX_DEFAULT]);
impl LateLintPass<'_> for BoxDefault {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::Call(box_new, [arg]) = expr.kind
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_new.kind
&& let ExprKind::Call(..) = arg.kind
&& !in_external_macro(cx.sess(), expr.span)
&& expr.span.eq_ctxt(arg.span)
&& seg.ident.name == sym::new
&& path_def_id(cx, ty) == cx.tcx.lang_items().owned_box()
&& is_default_equivalent(cx, arg)
{
span_lint_and_help(
cx,
BOX_DEFAULT,
expr.span,
"`Box::new(_)` of default value",
None,
"use `Box::default()` instead",
);
}
}
}

View File

@@ -40,7 +40,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: b
} }
fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) { fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) {
let message = format!("package `{}` is missing `{}` metadata", package.name, field); let message = format!("package `{}` is missing `{field}` metadata", package.name);
span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message); span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message);
} }

View File

@@ -57,10 +57,8 @@ fn lint(cx: &LateContext<'_>, feature: &str, substring: &str, is_prefix: bool) {
}, },
DUMMY_SP, DUMMY_SP,
&format!( &format!(
"the \"{}\" {} in the feature name \"{}\" is {}", "the \"{substring}\" {} in the feature name \"{feature}\" is {}",
substring,
if is_prefix { "prefix" } else { "suffix" }, if is_prefix { "prefix" } else { "suffix" },
feature,
if is_negative { "negative" } else { "redundant" } if is_negative { "negative" } else { "redundant" }
), ),
None, None,

View File

@@ -196,7 +196,7 @@ impl LateLintPass<'_> for Cargo {
}, },
Err(e) => { Err(e) => {
for lint in NO_DEPS_LINTS { for lint in NO_DEPS_LINTS {
span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {}", e)); span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}"));
} }
}, },
} }
@@ -212,7 +212,7 @@ impl LateLintPass<'_> for Cargo {
}, },
Err(e) => { Err(e) => {
for lint in WITH_DEPS_LINTS { for lint in WITH_DEPS_LINTS {
span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {}", e)); span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}"));
} }
}, },
} }

View File

@@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) {
cx, cx,
MULTIPLE_CRATE_VERSIONS, MULTIPLE_CRATE_VERSIONS,
DUMMY_SP, DUMMY_SP,
&format!("multiple versions for dependency `{}`: {}", name, versions), &format!("multiple versions for dependency `{name}`: {versions}"),
); );
} }
} }

View File

@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
expr.span, expr.span,
"borrow as raw pointer", "borrow as raw pointer",
"try", "try",
format!("{}::ptr::{}!({})", core_or_std, macro_name, snip), format!("{core_or_std}::ptr::{macro_name}!({snip})"),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }

View File

@@ -41,15 +41,9 @@ pub(super) fn check(
); );
let message = if cast_from.is_bool() { let message = if cast_from.is_bool() {
format!( format!("casting `{cast_from:}` to `{cast_to:}` is more cleanly stated with `{cast_to:}::from(_)`")
"casting `{0:}` to `{1:}` is more cleanly stated with `{1:}::from(_)`",
cast_from, cast_to
)
} else { } else {
format!( format!("casting `{cast_from}` to `{cast_to}` may become silently lossy if you later change the type")
"casting `{}` to `{}` may become silently lossy if you later change the type",
cast_from, cast_to
)
}; };
span_lint_and_sugg( span_lint_and_sugg(
@@ -58,7 +52,7 @@ pub(super) fn check(
expr.span, expr.span,
&message, &message,
"try", "try",
format!("{}::from({})", cast_to, sugg), format!("{cast_to}::from({sugg})"),
applicability, applicability,
); );
} }

View File

@@ -103,10 +103,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
return; return;
} }
format!( format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",)
"casting `{}` to `{}` may truncate the value{}",
cast_from, cast_to, suffix,
)
}, },
(ty::Adt(def, _), true) if def.is_enum() => { (ty::Adt(def, _), true) if def.is_enum() => {
@@ -142,20 +139,17 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
CAST_ENUM_TRUNCATION, CAST_ENUM_TRUNCATION,
expr.span, expr.span,
&format!( &format!(
"casting `{}::{}` to `{}` will truncate the value{}", "casting `{cast_from}::{}` to `{cast_to}` will truncate the value{suffix}",
cast_from, variant.name, cast_to, suffix, variant.name,
), ),
); );
return; return;
} }
format!( format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",)
"casting `{}` to `{}` may truncate the value{}",
cast_from, cast_to, suffix,
)
}, },
(ty::Float(_), true) => { (ty::Float(_), true) => {
format!("casting `{}` to `{}` may truncate the value", cast_from, cast_to) format!("casting `{cast_from}` to `{cast_to}` may truncate the value")
}, },
(ty::Float(FloatTy::F64), false) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => { (ty::Float(FloatTy::F64), false) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => {

View File

@@ -35,10 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
cx, cx,
CAST_POSSIBLE_WRAP, CAST_POSSIBLE_WRAP,
expr.span, expr.span,
&format!( &format!("casting `{cast_from}` to `{cast_to}` may wrap around the value{suffix}",),
"casting `{}` to `{}` may wrap around the value{}",
cast_from, cast_to, suffix,
),
); );
} }
} }

View File

@@ -49,9 +49,7 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f
CAST_PTR_ALIGNMENT, CAST_PTR_ALIGNMENT,
expr.span, expr.span,
&format!( &format!(
"casting from `{}` to a more-strictly-aligned pointer (`{}`) ({} < {} bytes)", "casting from `{cast_from}` to a more-strictly-aligned pointer (`{cast_to}`) ({} < {} bytes)",
cast_from,
cast_to,
from_layout.align.abi.bytes(), from_layout.align.abi.bytes(),
to_layout.align.abi.bytes(), to_layout.align.abi.bytes(),
), ),

View File

@@ -14,10 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, c
cx, cx,
CAST_SIGN_LOSS, CAST_SIGN_LOSS,
expr.span, expr.span,
&format!( &format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"),
"casting `{}` to `{}` may lose the sign of the value",
cast_from, cast_to
),
); );
} }
} }

View File

@@ -35,8 +35,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Optio
CAST_SLICE_DIFFERENT_SIZES, CAST_SLICE_DIFFERENT_SIZES,
expr.span, expr.span,
&format!( &format!(
"casting between raw pointers to `[{}]` (element size {}) and `[{}]` (element size {}) does not adjust the count", "casting between raw pointers to `[{}]` (element size {from_size}) and `[{}]` (element size {to_size}) does not adjust the count",
start_ty.ty, from_size, end_ty.ty, to_size, start_ty.ty, end_ty.ty,
), ),
|diag| { |diag| {
let ptr_snippet = source::snippet(cx, left_cast.span, ".."); let ptr_snippet = source::snippet(cx, left_cast.span, "..");

View File

@@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
diag.span_suggestion( diag.span_suggestion(
expr.span, expr.span,
"use a byte literal instead", "use a byte literal instead",
format!("b{}", snippet), format!("b{snippet}"),
applicability, applicability,
); );
} }

View File

@@ -25,9 +25,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
cx, cx,
FN_TO_NUMERIC_CAST, FN_TO_NUMERIC_CAST,
expr.span, expr.span,
&format!("casting function pointer `{}` to `{}`", from_snippet, cast_to), &format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
"try", "try",
format!("{} as usize", from_snippet), format!("{from_snippet} as usize"),
applicability, applicability,
); );
} }

View File

@@ -23,9 +23,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
cx, cx,
FN_TO_NUMERIC_CAST_ANY, FN_TO_NUMERIC_CAST_ANY,
expr.span, expr.span,
&format!("casting function pointer `{}` to `{}`", from_snippet, cast_to), &format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
"did you mean to invoke the function?", "did you mean to invoke the function?",
format!("{}() as {}", from_snippet, cast_to), format!("{from_snippet}() as {cast_to}"),
applicability, applicability,
); );
}, },

View File

@@ -24,12 +24,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
cx, cx,
FN_TO_NUMERIC_CAST_WITH_TRUNCATION, FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
expr.span, expr.span,
&format!( &format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"),
"casting function pointer `{}` to `{}`, which truncates the value",
from_snippet, cast_to
),
"try", "try",
format!("{} as usize", from_snippet), format!("{from_snippet} as usize"),
applicability, applicability,
); );
} }

View File

@@ -33,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option<RustcVer
let turbofish = match &cast_to_hir_ty.kind { let turbofish = match &cast_to_hir_ty.kind {
TyKind::Infer => Cow::Borrowed(""), TyKind::Infer => Cow::Borrowed(""),
TyKind::Ptr(mut_ty) if matches!(mut_ty.ty.kind, TyKind::Infer) => Cow::Borrowed(""), TyKind::Ptr(mut_ty) if matches!(mut_ty.ty.kind, TyKind::Infer) => Cow::Borrowed(""),
_ => Cow::Owned(format!("::<{}>", to_pointee_ty)), _ => Cow::Owned(format!("::<{to_pointee_ty}>")),
}; };
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
@@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option<RustcVer
expr.span, expr.span,
"`as` casting between raw pointers without changing its mutability", "`as` casting between raw pointers without changing its mutability",
"try `pointer::cast`, a safer alternative", "try `pointer::cast`, a safer alternative",
format!("{}.cast{}()", cast_expr_sugg.maybe_par(), turbofish), format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()),
applicability, applicability,
); );
} }

View File

@@ -71,10 +71,7 @@ pub(super) fn check<'tcx>(
cx, cx,
UNNECESSARY_CAST, UNNECESSARY_CAST,
expr.span, expr.span,
&format!( &format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
"casting to the same type is unnecessary (`{}` -> `{}`)",
cast_from, cast_to
),
"try", "try",
literal_str, literal_str,
Applicability::MachineApplicable, Applicability::MachineApplicable,
@@ -101,9 +98,9 @@ fn lint_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &st
cx, cx,
UNNECESSARY_CAST, UNNECESSARY_CAST,
expr.span, expr.span,
&format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to), &format!("casting {literal_kind_name} literal to `{cast_to}` is unnecessary"),
"try", "try",
format!("{}_{}", matchless.trim_end_matches('.'), cast_to), format!("{}_{cast_to}", matchless.trim_end_matches('.')),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }

View File

@@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
item.span, item.span,
"checked cast can be simplified", "checked cast can be simplified",
"try", "try",
format!("{}::try_from({}).is_ok()", to_type, snippet), format!("{to_type}::try_from({snippet}).is_ok()"),
applicability, applicability,
); );
} }

View File

@@ -107,8 +107,7 @@ impl CognitiveComplexity {
COGNITIVE_COMPLEXITY, COGNITIVE_COMPLEXITY,
fn_span, fn_span,
&format!( &format!(
"the function has a cognitive complexity of ({}/{})", "the function has a cognitive complexity of ({rust_cc}/{})",
rust_cc,
self.limit.limit() self.limit.limit()
), ),
None, None,

View File

@@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
cx, cx,
DEFAULT_TRAIT_ACCESS, DEFAULT_TRAIT_ACCESS,
expr.span, expr.span,
&format!("calling `{}` is more clear than this expression", replacement), &format!("calling `{replacement}` is more clear than this expression"),
"try", "try",
replacement, replacement,
Applicability::Unspecified, // First resolve the TODO above Applicability::Unspecified, // First resolve the TODO above
@@ -210,7 +210,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
.map(|(field, rhs)| { .map(|(field, rhs)| {
// extract and store the assigned value for help message // extract and store the assigned value for help message
let value_snippet = snippet_with_macro_callsite(cx, rhs.span, ".."); let value_snippet = snippet_with_macro_callsite(cx, rhs.span, "..");
format!("{}: {}", field, value_snippet) format!("{field}: {value_snippet}")
}) })
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join(", "); .join(", ");
@@ -227,7 +227,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
.map(ToString::to_string) .map(ToString::to_string)
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", "); .join(", ");
format!("{}::<{}>", adt_def_ty_name, &tys_str) format!("{adt_def_ty_name}::<{}>", &tys_str)
} else { } else {
binding_type.to_string() binding_type.to_string()
} }
@@ -235,12 +235,12 @@ impl<'tcx> LateLintPass<'tcx> for Default {
let sugg = if ext_with_default { let sugg = if ext_with_default {
if field_list.is_empty() { if field_list.is_empty() {
format!("{}::default()", binding_type) format!("{binding_type}::default()")
} else { } else {
format!("{} {{ {}, ..Default::default() }}", binding_type, field_list) format!("{binding_type} {{ {field_list}, ..Default::default() }}")
} }
} else { } else {
format!("{} {{ {} }}", binding_type, field_list) format!("{binding_type} {{ {field_list} }}")
}; };
// span lint once per statement that binds default // span lint once per statement that binds default
@@ -250,10 +250,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
first_assign.unwrap().span, first_assign.unwrap().span,
"field assignment outside of initializer for an instance created with Default::default()", "field assignment outside of initializer for an instance created with Default::default()",
Some(local.span), Some(local.span),
&format!( &format!("consider initializing the variable with `{sugg}` and removing relevant reassignments"),
"consider initializing the variable with `{}` and removing relevant reassignments",
sugg
),
); );
self.reassigned_linted.insert(span); self.reassigned_linted.insert(span);
} }

View File

@@ -23,7 +23,7 @@ declare_clippy_lint! {
/// let _ = std::iter::empty::<usize>(); /// let _ = std::iter::empty::<usize>();
/// let iter: std::iter::Empty<usize> = std::iter::empty(); /// let iter: std::iter::Empty<usize> = std::iter::empty();
/// ``` /// ```
#[clippy::version = "1.63.0"] #[clippy::version = "1.64.0"]
pub DEFAULT_INSTEAD_OF_ITER_EMPTY, pub DEFAULT_INSTEAD_OF_ITER_EMPTY,
style, style,
"check `std::iter::Empty::default()` and replace with `std::iter::empty()`" "check `std::iter::Empty::default()` and replace with `std::iter::empty()`"

View File

@@ -95,8 +95,8 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
src src
} else { } else {
match lit.node { match lit.node {
LitKind::Int(src, _) => format!("{}", src), LitKind::Int(src, _) => format!("{src}"),
LitKind::Float(src, _) => format!("{}", src), LitKind::Float(src, _) => format!("{src}"),
_ => return, _ => return,
} }
}; };

View File

@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use rustc_hir::{self as hir, HirId, Item, ItemKind}; use rustc_hir::{self as hir, HirId, Item, ItemKind};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::layout::LayoutOf;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym; use rustc_span::sym;
use rustc_hir_analysis::hir_ty_to_ty;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@@ -135,7 +135,7 @@ declare_clippy_lint! {
/// let x = String::new(); /// let x = String::new();
/// let y: &str = &x; /// let y: &str = &x;
/// ``` /// ```
#[clippy::version = "1.60.0"] #[clippy::version = "1.64.0"]
pub EXPLICIT_AUTO_DEREF, pub EXPLICIT_AUTO_DEREF,
complexity, complexity,
"dereferencing when the compiler would automatically dereference" "dereferencing when the compiler would automatically dereference"
@@ -1308,7 +1308,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
}; };
let expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX { let expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX {
format!("({})", expr_str) format!("({expr_str})")
} else { } else {
expr_str.into_owned() expr_str.into_owned()
}; };
@@ -1322,7 +1322,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
Mutability::Mut => "explicit `deref_mut` method call", Mutability::Mut => "explicit `deref_mut` method call",
}, },
"try this", "try this",
format!("{}{}{}", addr_of_str, deref_str, expr_str), format!("{addr_of_str}{deref_str}{expr_str}"),
app, app,
); );
}, },
@@ -1336,7 +1336,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
&& !has_enclosing_paren(&snip) && !has_enclosing_paren(&snip)
&& (expr.precedence().order() < data.position.precedence() || calls_field) && (expr.precedence().order() < data.position.precedence() || calls_field)
{ {
format!("({})", snip) format!("({snip})")
} else { } else {
snip.into() snip.into()
}; };
@@ -1379,9 +1379,9 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
let sugg = let sugg =
if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) { if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) {
format!("{}({})", prefix, snip) format!("{prefix}({snip})")
} else { } else {
format!("{}{}", prefix, snip) format!("{prefix}{snip}")
}; };
diag.span_suggestion(data.span, "try this", sugg, app); diag.span_suggestion(data.span, "try this", sugg, app);
}, },
@@ -1460,14 +1460,14 @@ impl Dereferencing {
} else { } else {
pat.always_deref = false; pat.always_deref = false;
let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0; let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0;
pat.replacements.push((e.span, format!("&{}", snip))); pat.replacements.push((e.span, format!("&{snip}")));
} }
}, },
_ if !e.span.from_expansion() => { _ if !e.span.from_expansion() => {
// Double reference might be needed at this point. // Double reference might be needed at this point.
pat.always_deref = false; pat.always_deref = false;
let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app); let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app);
pat.replacements.push((e.span, format!("&{}", snip))); pat.replacements.push((e.span, format!("&{snip}")));
}, },
// Edge case for macros. The span of the identifier will usually match the context of the // Edge case for macros. The span of the identifier will usually match the context of the
// binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc

View File

@@ -191,7 +191,7 @@ declare_clippy_lint! {
/// ``` /// ```
#[clippy::version = "1.63.0"] #[clippy::version = "1.63.0"]
pub DERIVE_PARTIAL_EQ_WITHOUT_EQ, pub DERIVE_PARTIAL_EQ_WITHOUT_EQ,
style, nursery,
"deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`" "deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`"
} }

View File

@@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
reason: Some(reason), .. reason: Some(reason), ..
} = conf } = conf
{ {
diag.note(&format!("{} (from clippy.toml)", reason)); diag.note(&format!("{reason} (from clippy.toml)"));
} }
}); });
} }

View File

@@ -99,8 +99,7 @@ impl EarlyLintPass for DisallowedScriptIdents {
DISALLOWED_SCRIPT_IDENTS, DISALLOWED_SCRIPT_IDENTS,
span, span,
&format!( &format!(
"identifier `{}` has a Unicode script that is not allowed by configuration: {}", "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}",
symbol_str,
script.full_name() script.full_name()
), ),
); );

View File

@@ -1,9 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{ use rustc_hir::{def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind,
};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span; use rustc_span::Span;
@@ -92,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
conf::DisallowedType::Simple(path) => (path, None), conf::DisallowedType::Simple(path) => (path, None),
conf::DisallowedType::WithReason { path, reason } => ( conf::DisallowedType::WithReason { path, reason } => (
path, path,
reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)), reason.as_ref().map(|reason| format!("{reason} (from clippy.toml)")),
), ),
}; };
let segs: Vec<_> = path.split("::").collect(); let segs: Vec<_> = path.split("::").collect();
@@ -130,7 +128,7 @@ fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) {
cx, cx,
DISALLOWED_TYPES, DISALLOWED_TYPES,
span, span,
&format!("`{}` is not allowed according to config", name), &format!("`{name}` is not allowed according to config"),
|diag| { |diag| {
if let Some(reason) = reason { if let Some(reason) = reason {
diag.note(reason); diag.note(reason);

View File

@@ -237,7 +237,15 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
panic_span: None, panic_span: None,
}; };
fpu.visit_expr(body.value); fpu.visit_expr(body.value);
lint_for_missing_headers(cx, item.def_id.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span); lint_for_missing_headers(
cx,
item.def_id.def_id,
item.span,
sig,
headers,
Some(body_id),
fpu.panic_span,
);
} }
}, },
hir::ItemKind::Impl(impl_) => { hir::ItemKind::Impl(impl_) => {
@@ -287,7 +295,15 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
panic_span: None, panic_span: None,
}; };
fpu.visit_expr(body.value); fpu.visit_expr(body.value);
lint_for_missing_headers(cx, item.def_id.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span); lint_for_missing_headers(
cx,
item.def_id.def_id,
item.span,
sig,
headers,
Some(body_id),
fpu.panic_span,
);
} }
} }
} }
@@ -790,7 +806,7 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
diag.span_suggestion_with_style( diag.span_suggestion_with_style(
span, span,
"try", "try",
format!("`{}`", snippet), format!("`{snippet}`"),
applicability, applicability,
// always show the suggestion in a separate line, since the // always show the suggestion in a separate line, since the
// inline presentation adds another pair of backticks // inline presentation adds another pair of backticks

View File

@@ -1,7 +1,8 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
use clippy_utils::get_parent_node;
use clippy_utils::is_must_use_func_call; use clippy_utils::is_must_use_func_call;
use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item}; use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item};
use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym; use rustc_span::sym;
@@ -202,11 +203,13 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
&& let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id) && let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id)
{ {
let arg_ty = cx.typeck_results().expr_ty(arg); let arg_ty = cx.typeck_results().expr_ty(arg);
let is_copy = is_copy(cx, arg_ty);
let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
let (lint, msg) = match fn_name { let (lint, msg) = match fn_name {
sym::mem_drop if arg_ty.is_ref() => (DROP_REF, DROP_REF_SUMMARY), sym::mem_drop if arg_ty.is_ref() => (DROP_REF, DROP_REF_SUMMARY),
sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY), sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY),
sym::mem_drop if is_copy(cx, arg_ty) => (DROP_COPY, DROP_COPY_SUMMARY), sym::mem_drop if is_copy && !drop_is_single_call_in_arm => (DROP_COPY, DROP_COPY_SUMMARY),
sym::mem_forget if is_copy(cx, arg_ty) => (FORGET_COPY, FORGET_COPY_SUMMARY), sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY),
sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => { sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => {
span_lint_and_help( span_lint_and_help(
cx, cx,
@@ -221,7 +224,9 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
sym::mem_drop sym::mem_drop
if !(arg_ty.needs_drop(cx.tcx, cx.param_env) if !(arg_ty.needs_drop(cx.tcx, cx.param_env)
|| is_must_use_func_call(cx, arg) || is_must_use_func_call(cx, arg)
|| is_must_use_ty(cx, arg_ty)) => || is_must_use_ty(cx, arg_ty)
|| drop_is_single_call_in_arm
) =>
{ {
(DROP_NON_DROP, DROP_NON_DROP_SUMMARY) (DROP_NON_DROP, DROP_NON_DROP_SUMMARY)
}, },
@@ -236,8 +241,23 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
expr.span, expr.span,
msg, msg,
Some(arg.span), Some(arg.span),
&format!("argument has type `{}`", arg_ty), &format!("argument has type `{arg_ty}`"),
); );
} }
} }
} }
// dropping returned value of a function like in the following snippet is considered idiomatic, see
// #9482 for examples match <var> {
// <pat> => drop(fn_with_side_effect_and_returning_some_value()),
// ..
// }
fn is_single_call_in_arm<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'_>, drop_expr: &'tcx Expr<'_>) -> bool {
if matches!(arg.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)) {
let parent_node = get_parent_node(cx.tcx, drop_expr.hir_id);
if let Some(Node::Arm(Arm { body, .. })) = &parent_node {
return body.hir_id == drop_expr.hir_id;
}
}
false
}

View File

@@ -113,13 +113,8 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
), ),
}; };
format!( format!(
"if let {}::{} = {}.entry({}) {} else {}", "if let {}::{entry_kind} = {map_str}.entry({key_str}) {then_str} else {else_str}",
map_ty.entry_path(), map_ty.entry_path(),
entry_kind,
map_str,
key_str,
then_str,
else_str,
) )
} else { } else {
// if .. { insert } else { insert } // if .. { insert } else { insert }
@@ -137,16 +132,11 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
let indent_str = snippet_indent(cx, expr.span); let indent_str = snippet_indent(cx, expr.span);
let indent_str = indent_str.as_deref().unwrap_or(""); let indent_str = indent_str.as_deref().unwrap_or("");
format!( format!(
"match {}.entry({}) {{\n{indent} {entry}::{} => {}\n\ "match {map_str}.entry({key_str}) {{\n{indent_str} {entry}::{then_entry} => {}\n\
{indent} {entry}::{} => {}\n{indent}}}", {indent_str} {entry}::{else_entry} => {}\n{indent_str}}}",
map_str,
key_str,
then_entry,
reindent_multiline(then_str.into(), true, Some(4 + indent_str.len())), reindent_multiline(then_str.into(), true, Some(4 + indent_str.len())),
else_entry,
reindent_multiline(else_str.into(), true, Some(4 + indent_str.len())), reindent_multiline(else_str.into(), true, Some(4 + indent_str.len())),
entry = map_ty.entry_path(), entry = map_ty.entry_path(),
indent = indent_str,
) )
} }
} else { } else {
@@ -163,20 +153,16 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
then_search.snippet_occupied(cx, then_expr.span, &mut app) then_search.snippet_occupied(cx, then_expr.span, &mut app)
}; };
format!( format!(
"if let {}::{} = {}.entry({}) {}", "if let {}::{entry_kind} = {map_str}.entry({key_str}) {body_str}",
map_ty.entry_path(), map_ty.entry_path(),
entry_kind,
map_str,
key_str,
body_str,
) )
} else if let Some(insertion) = then_search.as_single_insertion() { } else if let Some(insertion) = then_search.as_single_insertion() {
let value_str = snippet_with_context(cx, insertion.value.span, then_expr.span.ctxt(), "..", &mut app).0; let value_str = snippet_with_context(cx, insertion.value.span, then_expr.span.ctxt(), "..", &mut app).0;
if contains_expr.negated { if contains_expr.negated {
if insertion.value.can_have_side_effects() { if insertion.value.can_have_side_effects() {
format!("{}.entry({}).or_insert_with(|| {});", map_str, key_str, value_str) format!("{map_str}.entry({key_str}).or_insert_with(|| {value_str});")
} else { } else {
format!("{}.entry({}).or_insert({});", map_str, key_str, value_str) format!("{map_str}.entry({key_str}).or_insert({value_str});")
} }
} else { } else {
// TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here. // TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here.
@@ -186,7 +172,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
} else { } else {
let block_str = then_search.snippet_closure(cx, then_expr.span, &mut app); let block_str = then_search.snippet_closure(cx, then_expr.span, &mut app);
if contains_expr.negated { if contains_expr.negated {
format!("{}.entry({}).or_insert_with(|| {});", map_str, key_str, block_str) format!("{map_str}.entry({key_str}).or_insert_with(|| {block_str});")
} else { } else {
// TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here. // TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here.
// This would need to be a different lint. // This would need to be a different lint.

View File

@@ -202,12 +202,11 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
cx, cx,
ENUM_VARIANT_NAMES, ENUM_VARIANT_NAMES,
span, span,
&format!("all variants have the same {}fix: `{}`", what, value), &format!("all variants have the same {what}fix: `{value}`"),
None, None,
&format!( &format!(
"remove the {}fixes and use full paths to \ "remove the {what}fixes and use full paths to \
the variants instead of glob imports", the variants instead of glob imports"
what
), ),
); );
} }

View File

@@ -51,9 +51,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
false false
}, },
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => { PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.as_opt_usize().is_some() && array_rec(a),
!etc.as_opt_usize().is_some() && array_rec(a)
}
PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x),
PatKind::Path(_) | PatKind::Lit(_) => true, PatKind::Path(_) | PatKind::Lit(_) => true,
} }
@@ -93,9 +91,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
"this pattern matching can be expressed using equality", "this pattern matching can be expressed using equality",
"try", "try",
format!( format!(
"{} == {}", "{} == {pat_str}",
snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0, snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0,
pat_str,
), ),
applicability, applicability,
); );

View File

@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_hir; use clippy_utils::diagnostics::span_lint_hir;
use rustc_hir::intravisit; use rustc_hir::intravisit;
use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind}; use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::FakeReadCause; use rustc_middle::mir::FakeReadCause;
@@ -10,7 +11,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
use rustc_span::symbol::kw; use rustc_span::symbol::kw;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct BoxedLocal { pub struct BoxedLocal {
@@ -177,7 +177,13 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
} }
} }
fn fake_read(&mut self, _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} fn fake_read(
&mut self,
_: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>,
_: FakeReadCause,
_: HirId,
) {
}
} }
impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> { impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {

View File

@@ -129,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
then { then {
// Mutable closure is used after current expr; we cannot consume it. // Mutable closure is used after current expr; we cannot consume it.
snippet = format!("&mut {}", snippet); snippet = format!("&mut {snippet}");
} }
} }
diag.span_suggestion( diag.span_suggestion(
@@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
diag.span_suggestion( diag.span_suggestion(
expr.span, expr.span,
"replace the closure with the method itself", "replace the closure with the method itself",
format!("{}::{}", name, path.ident.name), format!("{name}::{}", path.ident.name),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
}) })

View File

@@ -97,7 +97,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
item.span, item.span,
msg, msg,
|diag| { |diag| {
let sugg = format!("#[non_exhaustive]\n{}", indent); let sugg = format!("#[non_exhaustive]\n{indent}");
diag.span_suggestion(suggestion_span, diag.span_suggestion(suggestion_span,
"try adding #[non_exhaustive]", "try adding #[non_exhaustive]",
sugg, sugg,

View File

@@ -80,12 +80,12 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
// used. // used.
let (used, sugg_mac) = if let Some(macro_name) = calling_macro { let (used, sugg_mac) = if let Some(macro_name) = calling_macro {
( (
format!("{}!({}(), ...)", macro_name, dest_name), format!("{macro_name}!({dest_name}(), ...)"),
macro_name.replace("write", "print"), macro_name.replace("write", "print"),
) )
} else { } else {
( (
format!("{}().write_fmt(...)", dest_name), format!("{dest_name}().write_fmt(...)"),
"print".into(), "print".into(),
) )
}; };
@@ -100,9 +100,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
cx, cx,
EXPLICIT_WRITE, EXPLICIT_WRITE,
expr.span, expr.span,
&format!("use of `{}.unwrap()`", used), &format!("use of `{used}.unwrap()`"),
"try this", "try this",
format!("{}{}!({})", prefix, sugg_mac, inputs_snippet), format!("{prefix}{sugg_mac}!({inputs_snippet})"),
applicability, applicability,
) )
} }

View File

@@ -173,9 +173,9 @@ impl FloatFormat {
T: fmt::UpperExp + fmt::LowerExp + fmt::Display, T: fmt::UpperExp + fmt::LowerExp + fmt::Display,
{ {
match self { match self {
Self::LowerExp => format!("{:e}", f), Self::LowerExp => format!("{f:e}"),
Self::UpperExp => format!("{:E}", f), Self::UpperExp => format!("{f:E}"),
Self::Normal => format!("{}", f), Self::Normal => format!("{f}"),
} }
} }
} }

View File

@@ -142,8 +142,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node; if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node;
then { then {
let op = format!( let op = format!(
"{}{}{}", "{suggestion}{}{}",
suggestion,
// Check for float literals without numbers following the decimal // Check for float literals without numbers following the decimal
// separator such as `2.` and adds a trailing zero // separator such as `2.` and adds a trailing zero
if sym.as_str().ends_with('.') { if sym.as_str().ends_with('.') {
@@ -172,7 +171,7 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, ar
expr.span, expr.span,
"logarithm for bases 2, 10 and e can be computed more accurately", "logarithm for bases 2, 10 and e can be computed more accurately",
"consider using", "consider using",
format!("{}.{}()", Sugg::hir(cx, receiver, "..").maybe_par(), method), format!("{}.{method}()", Sugg::hir(cx, receiver, "..").maybe_par()),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }
@@ -251,7 +250,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
expr.span, expr.span,
"exponent for bases 2 and e can be computed more accurately", "exponent for bases 2 and e can be computed more accurately",
"consider using", "consider using",
format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method), format!("{}.{method}()", prepare_receiver_sugg(cx, &args[0])),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }

View File

@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
[_] => { [_] => {
// Simulate macro expansion, converting {{ and }} to { and }. // Simulate macro expansion, converting {{ and }} to { and }.
let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}"); let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}");
let sugg = format!("{}.to_string()", s_expand); let sugg = format!("{s_expand}.to_string()");
span_useless_format(cx, call_site, sugg, applicability); span_useless_format(cx, call_site, sugg, applicability);
}, },
[..] => {}, [..] => {},

View File

@@ -1,16 +1,18 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::is_diag_trait_item; use clippy_utils::macros::FormatParamKind::{Implicit, Named, Numbered, Starred};
use clippy_utils::macros::{is_format_macro, FormatArgsExpn}; use clippy_utils::macros::{is_format_macro, FormatArgsExpn, FormatParam, FormatParamUsage};
use clippy_utils::source::snippet_opt; use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
use clippy_utils::ty::implements_trait; use clippy_utils::ty::implements_trait;
use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs};
use if_chain::if_chain; use if_chain::if_chain;
use itertools::Itertools; use itertools::Itertools;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, HirId}; use rustc_hir::{Expr, ExprKind, HirId, Path, QPath};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, ExpnData, ExpnKind, Span, Symbol}; use rustc_span::{sym, ExpnData, ExpnKind, Span, Symbol};
declare_clippy_lint! { declare_clippy_lint! {
@@ -64,7 +66,67 @@ declare_clippy_lint! {
"`to_string` applied to a type that implements `Display` in format args" "`to_string` applied to a type that implements `Display` in format args"
} }
declare_lint_pass!(FormatArgs => [FORMAT_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS]); declare_clippy_lint! {
/// ### What it does
/// Detect when a variable is not inlined in a format string,
/// and suggests to inline it.
///
/// ### Why is this bad?
/// Non-inlined code is slightly more difficult to read and understand,
/// as it requires arguments to be matched against the format string.
/// The inlined syntax, where allowed, is simpler.
///
/// ### Example
/// ```rust
/// # let var = 42;
/// # let width = 1;
/// # let prec = 2;
/// format!("{}", var);
/// format!("{v:?}", v = var);
/// format!("{0} {0}", var);
/// format!("{0:1$}", var, width);
/// format!("{:.*}", prec, var);
/// ```
/// Use instead:
/// ```rust
/// # let var = 42;
/// # let width = 1;
/// # let prec = 2;
/// format!("{var}");
/// format!("{var:?}");
/// format!("{var} {var}");
/// format!("{var:width$}");
/// format!("{var:.prec$}");
/// ```
///
/// ### Known Problems
///
/// There may be a false positive if the format string is expanded from certain proc macros:
///
/// ```ignore
/// println!(indoc!("{}"), var);
/// ```
///
/// If a format string contains a numbered argument that cannot be inlined
/// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
#[clippy::version = "1.65.0"]
pub UNINLINED_FORMAT_ARGS,
pedantic,
"using non-inlined variables in `format!` calls"
}
impl_lint_pass!(FormatArgs => [FORMAT_IN_FORMAT_ARGS, UNINLINED_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS]);
pub struct FormatArgs {
msrv: Option<RustcVersion>,
}
impl FormatArgs {
#[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self {
Self { msrv }
}
}
impl<'tcx> LateLintPass<'tcx> for FormatArgs { impl<'tcx> LateLintPass<'tcx> for FormatArgs {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
@@ -86,11 +148,75 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs {
check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value); check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value);
check_to_string_in_format_args(cx, name, arg.param.value); check_to_string_in_format_args(cx, name, arg.param.value);
} }
if meets_msrv(self.msrv, msrvs::FORMAT_ARGS_CAPTURE) {
check_uninlined_args(cx, &format_args, outermost_expn_data.call_site);
} }
} }
} }
} }
extract_msrv_attr!(LateContext);
}
fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_site: Span) {
if args.format_string.span.from_expansion() {
return;
}
let mut fixes = Vec::new();
// If any of the arguments are referenced by an index number,
// and that argument is not a simple variable and cannot be inlined,
// we cannot remove any other arguments in the format string,
// because the index numbers might be wrong after inlining.
// Example of an un-inlinable format: print!("{}{1}", foo, 2)
if !args.params().all(|p| check_one_arg(cx, &p, &mut fixes)) || fixes.is_empty() {
return;
}
// FIXME: Properly ignore a rare case where the format string is wrapped in a macro.
// Example: `format!(indoc!("{}"), foo);`
// If inlined, they will cause a compilation error:
// > to avoid ambiguity, `format_args!` cannot capture variables
// > when the format string is expanded from a macro
// @Alexendoo explanation:
// > indoc! is a proc macro that is producing a string literal with its span
// > set to its input it's not marked as from expansion, and since it's compatible
// > tokenization wise clippy_utils::is_from_proc_macro wouldn't catch it either
// This might be a relatively expensive test, so do it only we are ready to replace.
// See more examples in tests/ui/uninlined_format_args.rs
span_lint_and_then(
cx,
UNINLINED_FORMAT_ARGS,
call_site,
"variables can be used directly in the `format!` string",
|diag| {
diag.multipart_suggestion("change this to", fixes, Applicability::MachineApplicable);
},
);
}
fn check_one_arg(cx: &LateContext<'_>, param: &FormatParam<'_>, fixes: &mut Vec<(Span, String)>) -> bool {
if matches!(param.kind, Implicit | Starred | Named(_) | Numbered)
&& let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind
&& let Path { span, segments, .. } = path
&& let [segment] = segments
{
let replacement = match param.usage {
FormatParamUsage::Argument => segment.ident.name.to_string(),
FormatParamUsage::Width => format!("{}$", segment.ident.name),
FormatParamUsage::Precision => format!(".{}$", segment.ident.name),
};
fixes.push((param.span, replacement));
let arg_span = expand_past_previous_comma(cx, *span);
fixes.push((arg_span, String::new()));
true // successful inlining, continue checking
} else {
// if we can't inline a numbered argument, we can't continue
param.kind != Numbered
}
}
fn outermost_expn_data(expn_data: ExpnData) -> ExpnData { fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
if expn_data.call_site.from_expansion() { if expn_data.call_site.from_expansion() {
outermost_expn_data(expn_data.call_site.ctxt().outer_expn_data()) outermost_expn_data(expn_data.call_site.ctxt().outer_expn_data())
@@ -99,12 +225,7 @@ fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
} }
} }
fn check_format_in_format_args( fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) {
cx: &LateContext<'_>,
call_site: Span,
name: Symbol,
arg: &Expr<'_>,
) {
let expn_data = arg.span.ctxt().outer_expn_data(); let expn_data = arg.span.ctxt().outer_expn_data();
if expn_data.call_site.from_expansion() { if expn_data.call_site.from_expansion() {
return; return;
@@ -117,11 +238,10 @@ fn check_format_in_format_args(
cx, cx,
FORMAT_IN_FORMAT_ARGS, FORMAT_IN_FORMAT_ARGS,
call_site, call_site,
&format!("`format!` in `{}!` args", name), &format!("`format!` in `{name}!` args"),
|diag| { |diag| {
diag.help(&format!( diag.help(&format!(
"combine the `format!(..)` arguments with the outer `{}!(..)` call", "combine the `format!(..)` arguments with the outer `{name}!(..)` call"
name
)); ));
diag.help("or consider changing `format!` to `format_args!`"); diag.help("or consider changing `format!` to `format_args!`");
}, },
@@ -149,8 +269,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex
TO_STRING_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS,
value.span.with_lo(receiver.span.hi()), value.span.with_lo(receiver.span.hi()),
&format!( &format!(
"`to_string` applied to a type that implements `Display` in `{}!` args", "`to_string` applied to a type that implements `Display` in `{name}!` args"
name
), ),
"remove this", "remove this",
String::new(), String::new(),
@@ -162,16 +281,13 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex
TO_STRING_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS,
value.span, value.span,
&format!( &format!(
"`to_string` applied to a type that implements `Display` in `{}!` args", "`to_string` applied to a type that implements `Display` in `{name}!` args"
name
), ),
"use this", "use this",
format!( format!(
"{}{:*>width$}{}", "{}{:*>n_needed_derefs$}{receiver_snippet}",
if needs_ref { "&" } else { "" }, if needs_ref { "&" } else { "" },
"", ""
receiver_snippet,
width = n_needed_derefs
), ),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
@@ -180,9 +296,12 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex
} }
} }
// Returns true if `hir_id` is referred to by multiple format params /// Returns true if `hir_id` is referred to by multiple format params
fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool { fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool {
args.params().filter(|param| param.value.hir_id == hir_id).at_most_one().is_err() args.params()
.filter(|param| param.value.hir_id == hir_id)
.at_most_one()
.is_err()
} }
fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>) fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
@@ -192,7 +311,11 @@ where
let mut n_total = 0; let mut n_total = 0;
let mut n_needed = 0; let mut n_needed = 0;
loop { loop {
if let Some(Adjustment { kind: Adjust::Deref(overloaded_deref), target }) = iter.next() { if let Some(Adjustment {
kind: Adjust::Deref(overloaded_deref),
target,
}) = iter.next()
{
n_total += 1; n_total += 1;
if overloaded_deref.is_some() { if overloaded_deref.is_some() {
n_needed = n_total; n_needed = n_total;

View File

@@ -214,12 +214,12 @@ fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait:
cx, cx,
PRINT_IN_FORMAT_IMPL, PRINT_IN_FORMAT_IMPL,
macro_call.span, macro_call.span,
&format!("use of `{}!` in `{}` impl", name, impl_trait.name), &format!("use of `{name}!` in `{}` impl", impl_trait.name),
"replace with", "replace with",
if let Some(formatter_name) = impl_trait.formatter_name { if let Some(formatter_name) = impl_trait.formatter_name {
format!("{}!({}, ..)", replacement, formatter_name) format!("{replacement}!({formatter_name}, ..)")
} else { } else {
format!("{}!(..)", replacement) format!("{replacement}!(..)")
}, },
Applicability::HasPlaceholders, Applicability::HasPlaceholders,
); );

View File

@@ -154,11 +154,10 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
eqop_span, eqop_span,
&format!( &format!(
"this looks like you are trying to use `.. {op}= ..`, but you \ "this looks like you are trying to use `.. {op}= ..`, but you \
really are doing `.. = ({op} ..)`", really are doing `.. = ({op} ..)`"
op = op
), ),
None, None,
&format!("to remove this lint, use either `{op}=` or `= {op}`", op = op), &format!("to remove this lint, use either `{op}=` or `= {op}`"),
); );
} }
} }
@@ -191,16 +190,12 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) {
SUSPICIOUS_UNARY_OP_FORMATTING, SUSPICIOUS_UNARY_OP_FORMATTING,
eqop_span, eqop_span,
&format!( &format!(
"by not having a space between `{binop}` and `{unop}` it looks like \ "by not having a space between `{binop_str}` and `{unop_str}` it looks like \
`{binop}{unop}` is a single operator", `{binop_str}{unop_str}` is a single operator"
binop = binop_str,
unop = unop_str
), ),
None, None,
&format!( &format!(
"put a space between `{binop}` and `{unop}` and remove the space after `{unop}`", "put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"
binop = binop_str,
unop = unop_str
), ),
); );
} }
@@ -246,12 +241,11 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
cx, cx,
SUSPICIOUS_ELSE_FORMATTING, SUSPICIOUS_ELSE_FORMATTING,
else_span, else_span,
&format!("this is an `else {}` but the formatting might hide it", else_desc), &format!("this is an `else {else_desc}` but the formatting might hide it"),
None, None,
&format!( &format!(
"to remove this lint, remove the `else` or remove the new line between \ "to remove this lint, remove the `else` or remove the new line between \
`else` and `{}`", `else` and `{else_desc}`",
else_desc,
), ),
); );
} }
@@ -320,11 +314,10 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
cx, cx,
SUSPICIOUS_ELSE_FORMATTING, SUSPICIOUS_ELSE_FORMATTING,
else_span, else_span,
&format!("this looks like {} but the `else` is missing", looks_like), &format!("this looks like {looks_like} but the `else` is missing"),
None, None,
&format!( &format!(
"to remove this lint, add the missing `else` or add a new line before {}", "to remove this lint, add the missing `else` or add a new line before {next_thing}",
next_thing,
), ),
); );
} }

View File

@@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
exp.span, exp.span,
"this call to `from_str_radix` can be replaced with a call to `str::parse`", "this call to `from_str_radix` can be replaced with a call to `str::parse`",
"try", "try",
format!("{}.parse::<{}>()", sugg, prim_ty.name_str()), format!("{sugg}.parse::<{}>()", prim_ty.name_str()),
Applicability::MaybeIncorrect Applicability::MaybeIncorrect
); );
} }

View File

@@ -47,7 +47,8 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use); let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
if let Some(attr) = attr { if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
} else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.def_id.def_id).is_none() { } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.def_id.def_id).is_none()
{
check_must_use_candidate( check_must_use_candidate(
cx, cx,
sig.decl, sig.decl,
@@ -143,7 +144,7 @@ fn check_must_use_candidate<'tcx>(
diag.span_suggestion( diag.span_suggestion(
fn_span, fn_span,
"add the attribute", "add the attribute",
format!("#[must_use] {}", snippet), format!("#[must_use] {snippet}"),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }

View File

@@ -59,10 +59,7 @@ fn check_arg_number(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, fn_span: Span,
cx, cx,
TOO_MANY_ARGUMENTS, TOO_MANY_ARGUMENTS,
fn_span, fn_span,
&format!( &format!("this function has too many arguments ({args}/{too_many_arguments_threshold})"),
"this function has too many arguments ({}/{})",
args, too_many_arguments_threshold
),
); );
} }
} }

View File

@@ -78,10 +78,7 @@ pub(super) fn check_fn(
cx, cx,
TOO_MANY_LINES, TOO_MANY_LINES,
span, span,
&format!( &format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"),
"this function has too many lines ({}/{})",
line_count, too_many_lines_threshold
),
); );
} }
} }

View File

@@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
{ {
let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]");
let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) {
format!("({})", cond_snip) format!("({cond_snip})")
} else { } else {
cond_snip.into_owned() cond_snip.into_owned()
}; };
@@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
let mut method_body = if then_block.stmts.is_empty() { let mut method_body = if then_block.stmts.is_empty() {
arg_snip.into_owned() arg_snip.into_owned()
} else { } else {
format!("{{ /* snippet */ {} }}", arg_snip) format!("{{ /* snippet */ {arg_snip} }}")
}; };
let method_name = if switch_to_eager_eval(cx, expr) && meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) { let method_name = if switch_to_eager_eval(cx, expr) && meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) {
"then_some" "then_some"
@@ -102,14 +102,13 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
}; };
let help = format!( let help = format!(
"consider using `bool::{}` like: `{}.{}({})`", "consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`",
method_name, cond_snip, method_name, method_body,
); );
span_lint_and_help( span_lint_and_help(
cx, cx,
IF_THEN_SOME_ELSE_NONE, IF_THEN_SOME_ELSE_NONE,
expr.span, expr.span,
&format!("this could be simplified with `bool::{}`", method_name), &format!("this could be simplified with `bool::{method_name}`"),
None, None,
&help, &help,
); );

View File

@@ -5,6 +5,7 @@ use rustc_errors::Diagnostic;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor}; use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor};
use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind}; use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
@@ -12,7 +13,6 @@ use rustc_middle::ty::{Ty, TypeckResults};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_hir_analysis::hir_ty_to_ty;
use if_chain::if_chain; use if_chain::if_chain;
@@ -89,8 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
( (
generics_suggestion_span, generics_suggestion_span,
format!( format!(
"<{}{}S: ::std::hash::BuildHasher{}>", "<{generics_snip}{}S: ::std::hash::BuildHasher{}>",
generics_snip,
if generics_snip.is_empty() { "" } else { ", " }, if generics_snip.is_empty() { "" } else { ", " },
if vis.suggestions.is_empty() { if vis.suggestions.is_empty() {
"" ""
@@ -263,8 +262,8 @@ impl<'tcx> ImplicitHasherType<'tcx> {
fn type_arguments(&self) -> String { fn type_arguments(&self) -> String {
match *self { match *self {
ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{}, {}", k, v), ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{k}, {v}"),
ImplicitHasherType::HashSet(.., ref t) => format!("{}", t), ImplicitHasherType::HashSet(.., ref t) => format!("{t}"),
} }
} }

View File

@@ -53,7 +53,7 @@ fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) {
span, span,
"missing `return` statement", "missing `return` statement",
|diag| { |diag| {
diag.span_suggestion(span, "add `return` as shown", format!("return {}", snip), app); diag.span_suggestion(span, "add `return` as shown", format!("return {snip}"), app);
}, },
); );
} }
@@ -71,7 +71,7 @@ fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, exp
diag.span_suggestion( diag.span_suggestion(
break_span, break_span,
"change `break` to `return` as shown", "change `break` to `return` as shown",
format!("return {}", snip), format!("return {snip}"),
app, app,
); );
}, },

View File

@@ -170,7 +170,7 @@ fn print_lint_and_sugg(cx: &LateContext<'_>, var_name: &str, expr: &Expr<'_>) {
expr.span, expr.span,
"implicitly performing saturating subtraction", "implicitly performing saturating subtraction",
"try", "try",
format!("{} = {}.saturating_sub({});", var_name, var_name, '1'), format!("{var_name} = {var_name}.saturating_sub({});", '1'),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }

View File

@@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
let mut fields_snippet = String::new(); let mut fields_snippet = String::new();
let (last_ident, idents) = ordered_fields.split_last().unwrap(); let (last_ident, idents) = ordered_fields.split_last().unwrap();
for ident in idents { for ident in idents {
let _ = write!(fields_snippet, "{}, ", ident); let _ = write!(fields_snippet, "{ident}, ");
} }
fields_snippet.push_str(&last_ident.to_string()); fields_snippet.push_str(&last_ident.to_string());
@@ -100,10 +100,8 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
String::new() String::new()
}; };
let sugg = format!("{} {{ {}{} }}", let sugg = format!("{} {{ {fields_snippet}{base_snippet} }}",
snippet(cx, qpath.span(), ".."), snippet(cx, qpath.span(), ".."),
fields_snippet,
base_snippet,
); );
span_lint_and_sugg( span_lint_and_sugg(

View File

@@ -139,14 +139,14 @@ fn lint_slice(cx: &LateContext<'_>, slice: &SliceLintInformation) {
.map(|(index, _)| *index) .map(|(index, _)| *index)
.collect::<FxHashSet<_>>(); .collect::<FxHashSet<_>>();
let value_name = |index| format!("{}_{}", slice.ident.name, index); let value_name = |index| format!("{}_{index}", slice.ident.name);
if let Some(max_index) = used_indices.iter().max() { if let Some(max_index) = used_indices.iter().max() {
let opt_ref = if slice.needs_ref { "ref " } else { "" }; let opt_ref = if slice.needs_ref { "ref " } else { "" };
let pat_sugg_idents = (0..=*max_index) let pat_sugg_idents = (0..=*max_index)
.map(|index| { .map(|index| {
if used_indices.contains(&index) { if used_indices.contains(&index) {
format!("{}{}", opt_ref, value_name(index)) format!("{opt_ref}{}", value_name(index))
} else { } else {
"_".to_string() "_".to_string()
} }

View File

@@ -131,23 +131,19 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
INHERENT_TO_STRING_SHADOW_DISPLAY, INHERENT_TO_STRING_SHADOW_DISPLAY,
item.span, item.span,
&format!( &format!(
"type `{}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`", "type `{self_type}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`"
self_type
), ),
None, None,
&format!("remove the inherent method from type `{}`", self_type), &format!("remove the inherent method from type `{self_type}`"),
); );
} else { } else {
span_lint_and_help( span_lint_and_help(
cx, cx,
INHERENT_TO_STRING, INHERENT_TO_STRING,
item.span, item.span,
&format!( &format!("implementation of inherent method `to_string(&self) -> String` for type `{self_type}`"),
"implementation of inherent method `to_string(&self) -> String` for type `{}`",
self_type
),
None, None,
&format!("implement trait `Display` for type `{}` instead", self_type), &format!("implement trait `Display` for type `{self_type}` instead"),
); );
} }
} }

View File

@@ -51,7 +51,7 @@ fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) {
cx, cx,
INLINE_FN_WITHOUT_BODY, INLINE_FN_WITHOUT_BODY,
attr.span, attr.span,
&format!("use of `#[inline]` on trait method `{}` which has no body", name), &format!("use of `#[inline]` on trait method `{name}` which has no body"),
|diag| { |diag| {
diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable); diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
}, },

View File

@@ -138,8 +138,8 @@ impl IntPlusOne {
if let Some(snippet) = snippet_opt(cx, node.span) { if let Some(snippet) = snippet_opt(cx, node.span) {
if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) { if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) {
let rec = match side { let rec = match side {
Side::Lhs => Some(format!("{} {} {}", snippet, binop_string, other_side_snippet)), Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")),
Side::Rhs => Some(format!("{} {} {}", other_side_snippet, binop_string, snippet)), Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")),
}; };
return rec; return rec;
} }

View File

@@ -80,10 +80,7 @@ fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefI
cx, cx,
ITER_NOT_RETURNING_ITERATOR, ITER_NOT_RETURNING_ITERATOR,
sig.span, sig.span,
&format!( &format!("this method is named `{name}` but its return type does not implement `Iterator`"),
"this method is named `{}` but its return type does not implement `Iterator`",
name
),
); );
} }
} }

View File

@@ -2,12 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_then;
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind}; use rustc_hir::{Item, ItemKind};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, ConstKind}; use rustc_middle::ty::{self, ConstKind};
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{BytePos, Pos, Span}; use rustc_span::{BytePos, Pos, Span};
use rustc_hir_analysis::hir_ty_to_ty;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@@ -210,7 +210,8 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
} }
} }
if cx.access_levels.is_exported(visited_trait.def_id.def_id) && trait_items.iter().any(|i| is_named_self(cx, i, sym::len)) if cx.access_levels.is_exported(visited_trait.def_id.def_id)
&& trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
{ {
let mut current_and_super_traits = DefIdSet::default(); let mut current_and_super_traits = DefIdSet::default();
fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx); fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx);
@@ -278,15 +279,13 @@ impl<'tcx> LenOutput<'tcx> {
_ => "", _ => "",
}; };
match self { match self {
Self::Integral => format!("expected signature: `({}self) -> bool`", self_ref), Self::Integral => format!("expected signature: `({self_ref}self) -> bool`"),
Self::Option(_) => format!( Self::Option(_) => {
"expected signature: `({}self) -> bool` or `({}self) -> Option<bool>", format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Option<bool>")
self_ref, self_ref },
), Self::Result(..) => {
Self::Result(..) => format!( format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Result<bool>")
"expected signature: `({}self) -> bool` or `({}self) -> Result<bool>", },
self_ref, self_ref
),
} }
} }
} }
@@ -326,8 +325,7 @@ fn check_for_is_empty<'tcx>(
let (msg, is_empty_span, self_kind) = match is_empty { let (msg, is_empty_span, self_kind) = match is_empty {
None => ( None => (
format!( format!(
"{} `{}` has a public `len` method, but no `is_empty` method", "{item_kind} `{}` has a public `len` method, but no `is_empty` method",
item_kind,
item_name.as_str(), item_name.as_str(),
), ),
None, None,
@@ -335,8 +333,7 @@ fn check_for_is_empty<'tcx>(
), ),
Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => ( Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => (
format!( format!(
"{} `{}` has a public `len` method, but a private `is_empty` method", "{item_kind} `{}` has a public `len` method, but a private `is_empty` method",
item_kind,
item_name.as_str(), item_name.as_str(),
), ),
Some(cx.tcx.def_span(is_empty.def_id)), Some(cx.tcx.def_span(is_empty.def_id)),
@@ -348,8 +345,7 @@ fn check_for_is_empty<'tcx>(
{ {
( (
format!( format!(
"{} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature", "{item_kind} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature",
item_kind,
item_name.as_str(), item_name.as_str(),
), ),
Some(cx.tcx.def_span(is_empty.def_id)), Some(cx.tcx.def_span(is_empty.def_id)),
@@ -419,10 +415,9 @@ fn check_len(
LEN_ZERO, LEN_ZERO,
span, span,
&format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }), &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
&format!("using `{}is_empty` is clearer and more explicit", op), &format!("using `{op}is_empty` is clearer and more explicit"),
format!( format!(
"{}{}.is_empty()", "{op}{}.is_empty()",
op,
snippet_with_applicability(cx, receiver.span, "_", &mut applicability) snippet_with_applicability(cx, receiver.span, "_", &mut applicability)
), ),
applicability, applicability,
@@ -439,10 +434,9 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex
COMPARISON_TO_EMPTY, COMPARISON_TO_EMPTY,
span, span,
"comparison to empty slice", "comparison to empty slice",
&format!("using `{}is_empty` is clearer and more explicit", op), &format!("using `{op}is_empty` is clearer and more explicit"),
format!( format!(
"{}{}.is_empty()", "{op}{}.is_empty()",
op,
snippet_with_applicability(cx, lit1.span, "_", &mut applicability) snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
), ),
applicability, applicability,

View File

@@ -106,8 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
// use mutably after the `if` // use mutably after the `if`
let sug = format!( let sug = format!(
"let {mut}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};", "let {mutability}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};",
mut=mutability,
name=ident.name, name=ident.name,
cond=snippet(cx, cond.span, "_"), cond=snippet(cx, cond.span, "_"),
then=if then.stmts.len() > 1 { " ..;" } else { "" }, then=if then.stmts.len() > 1 { " ..;" } else { "" },

View File

@@ -21,6 +21,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(booleans::NONMINIMAL_BOOL), LintId::of(booleans::NONMINIMAL_BOOL),
LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR), LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
LintId::of(borrow_deref_ref::BORROW_DEREF_REF), LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
LintId::of(box_default::BOX_DEFAULT),
LintId::of(casts::CAST_ABS_TO_UNSIGNED), LintId::of(casts::CAST_ABS_TO_UNSIGNED),
LintId::of(casts::CAST_ENUM_CONSTRUCTOR), LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
LintId::of(casts::CAST_ENUM_TRUNCATION), LintId::of(casts::CAST_ENUM_TRUNCATION),
@@ -44,7 +45,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(derivable_impls::DERIVABLE_IMPLS), LintId::of(derivable_impls::DERIVABLE_IMPLS),
LintId::of(derive::DERIVE_HASH_XOR_EQ), LintId::of(derive::DERIVE_HASH_XOR_EQ),
LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
LintId::of(disallowed_methods::DISALLOWED_METHODS), LintId::of(disallowed_methods::DISALLOWED_METHODS),
LintId::of(disallowed_names::DISALLOWED_NAMES), LintId::of(disallowed_names::DISALLOWED_NAMES),
LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(disallowed_types::DISALLOWED_TYPES),

View File

@@ -60,6 +60,7 @@ store.register_lints(&[
booleans::NONMINIMAL_BOOL, booleans::NONMINIMAL_BOOL,
booleans::OVERLY_COMPLEX_BOOL_EXPR, booleans::OVERLY_COMPLEX_BOOL_EXPR,
borrow_deref_ref::BORROW_DEREF_REF, borrow_deref_ref::BORROW_DEREF_REF,
box_default::BOX_DEFAULT,
cargo::CARGO_COMMON_METADATA, cargo::CARGO_COMMON_METADATA,
cargo::MULTIPLE_CRATE_VERSIONS, cargo::MULTIPLE_CRATE_VERSIONS,
cargo::NEGATIVE_FEATURE_NAMES, cargo::NEGATIVE_FEATURE_NAMES,
@@ -159,6 +160,7 @@ store.register_lints(&[
format::USELESS_FORMAT, format::USELESS_FORMAT,
format_args::FORMAT_IN_FORMAT_ARGS, format_args::FORMAT_IN_FORMAT_ARGS,
format_args::TO_STRING_IN_FORMAT_ARGS, format_args::TO_STRING_IN_FORMAT_ARGS,
format_args::UNINLINED_FORMAT_ARGS,
format_impl::PRINT_IN_FORMAT_IMPL, format_impl::PRINT_IN_FORMAT_IMPL,
format_impl::RECURSIVE_FORMAT_IMPL, format_impl::RECURSIVE_FORMAT_IMPL,
format_push_string::FORMAT_PUSH_STRING, format_push_string::FORMAT_PUSH_STRING,

View File

@@ -6,6 +6,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR), LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY), LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
LintId::of(copies::BRANCHES_SHARING_CODE), LintId::of(copies::BRANCHES_SHARING_CODE),
LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
LintId::of(equatable_if_let::EQUATABLE_IF_LET), LintId::of(equatable_if_let::EQUATABLE_IF_LET),
LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM), LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS), LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
@@ -30,6 +31,8 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
LintId::of(strings::STRING_LIT_AS_BYTES), LintId::of(strings::STRING_LIT_AS_BYTES),
LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY), LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR), LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR),
LintId::of(unused_peekable::UNUSED_PEEKABLE), LintId::of(unused_peekable::UNUSED_PEEKABLE),
LintId::of(unused_rounding::UNUSED_ROUNDING), LintId::of(unused_rounding::UNUSED_ROUNDING),

View File

@@ -29,6 +29,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS), LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS), LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
LintId::of(format_args::UNINLINED_FORMAT_ARGS),
LintId::of(functions::MUST_USE_CANDIDATE), LintId::of(functions::MUST_USE_CANDIDATE),
LintId::of(functions::TOO_MANY_LINES), LintId::of(functions::TOO_MANY_LINES),
LintId::of(if_not_else::IF_NOT_ELSE), LintId::of(if_not_else::IF_NOT_ELSE),
@@ -88,8 +89,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE), LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
LintId::of(strings::STRING_ADD_ASSIGN), LintId::of(strings::STRING_ADD_ASSIGN),
LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
LintId::of(transmute::TRANSMUTE_PTR_TO_PTR), LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
LintId::of(types::LINKEDLIST), LintId::of(types::LINKEDLIST),
LintId::of(types::OPTION_OPTION), LintId::of(types::OPTION_OPTION),

View File

@@ -3,6 +3,7 @@
// Manual edits will be overwritten. // Manual edits will be overwritten.
store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
LintId::of(box_default::BOX_DEFAULT),
LintId::of(entry::MAP_ENTRY), LintId::of(entry::MAP_ENTRY),
LintId::of(escape::BOXED_LOCAL), LintId::of(escape::BOXED_LOCAL),
LintId::of(format_args::FORMAT_IN_FORMAT_ARGS), LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),

View File

@@ -15,7 +15,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY), LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
LintId::of(dereference::NEEDLESS_BORROW), LintId::of(dereference::NEEDLESS_BORROW),
LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
LintId::of(disallowed_methods::DISALLOWED_METHODS), LintId::of(disallowed_methods::DISALLOWED_METHODS),
LintId::of(disallowed_names::DISALLOWED_NAMES), LintId::of(disallowed_names::DISALLOWED_NAMES),
LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(disallowed_types::DISALLOWED_TYPES),

View File

@@ -31,6 +31,7 @@ extern crate rustc_data_structures;
extern crate rustc_driver; extern crate rustc_driver;
extern crate rustc_errors; extern crate rustc_errors;
extern crate rustc_hir; extern crate rustc_hir;
extern crate rustc_hir_analysis;
extern crate rustc_hir_pretty; extern crate rustc_hir_pretty;
extern crate rustc_index; extern crate rustc_index;
extern crate rustc_infer; extern crate rustc_infer;
@@ -43,7 +44,6 @@ extern crate rustc_session;
extern crate rustc_span; extern crate rustc_span;
extern crate rustc_target; extern crate rustc_target;
extern crate rustc_trait_selection; extern crate rustc_trait_selection;
extern crate rustc_hir_analysis;
#[macro_use] #[macro_use]
extern crate clippy_utils; extern crate clippy_utils;
@@ -180,6 +180,7 @@ mod bool_assert_comparison;
mod bool_to_int_with_if; mod bool_to_int_with_if;
mod booleans; mod booleans;
mod borrow_deref_ref; mod borrow_deref_ref;
mod box_default;
mod cargo; mod cargo;
mod casts; mod casts;
mod checked_conversions; mod checked_conversions;
@@ -416,8 +417,7 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se
let msrv = conf.msrv.as_ref().and_then(|s| { let msrv = conf.msrv.as_ref().and_then(|s| {
parse_msrv(s, None, None).or_else(|| { parse_msrv(s, None, None).or_else(|| {
sess.err(&format!( sess.err(&format!(
"error reading Clippy's configuration file. `{}` is not a valid Rust version", "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
s
)); ));
None None
}) })
@@ -433,8 +433,7 @@ fn read_msrv(conf: &Conf, sess: &Session) -> Option<RustcVersion> {
let clippy_msrv = conf.msrv.as_ref().and_then(|s| { let clippy_msrv = conf.msrv.as_ref().and_then(|s| {
parse_msrv(s, None, None).or_else(|| { parse_msrv(s, None, None).or_else(|| {
sess.err(&format!( sess.err(&format!(
"error reading Clippy's configuration file. `{}` is not a valid Rust version", "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
s
)); ));
None None
}) })
@@ -445,8 +444,7 @@ fn read_msrv(conf: &Conf, sess: &Session) -> Option<RustcVersion> {
// if both files have an msrv, let's compare them and emit a warning if they differ // if both files have an msrv, let's compare them and emit a warning if they differ
if clippy_msrv != cargo_msrv { if clippy_msrv != cargo_msrv {
sess.warn(&format!( sess.warn(&format!(
"the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{}` from `clippy.toml`", "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
clippy_msrv
)); ));
} }
@@ -465,7 +463,7 @@ pub fn read_conf(sess: &Session) -> Conf {
Ok(Some(path)) => path, Ok(Some(path)) => path,
Ok(None) => return Conf::default(), Ok(None) => return Conf::default(),
Err(error) => { Err(error) => {
sess.struct_err(&format!("error finding Clippy's configuration file: {}", error)) sess.struct_err(&format!("error finding Clippy's configuration file: {error}"))
.emit(); .emit();
return Conf::default(); return Conf::default();
}, },
@@ -535,8 +533,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(utils::internal_lints::CompilerLintFunctions::new())); store.register_late_pass(|_| Box::new(utils::internal_lints::CompilerLintFunctions::new()));
store.register_late_pass(|_| Box::new(utils::internal_lints::IfChainStyle)); store.register_late_pass(|_| Box::new(utils::internal_lints::IfChainStyle));
store.register_late_pass(|_| Box::new(utils::internal_lints::InvalidPaths)); store.register_late_pass(|_| Box::new(utils::internal_lints::InvalidPaths));
store.register_late_pass(|_| Box::new(utils::internal_lints::InterningDefinedSymbol::default())); store.register_late_pass(|_| Box::<utils::internal_lints::InterningDefinedSymbol>::default());
store.register_late_pass(|_| Box::new(utils::internal_lints::LintWithoutLintPass::default())); store.register_late_pass(|_| Box::<utils::internal_lints::LintWithoutLintPass>::default());
store.register_late_pass(|_| Box::new(utils::internal_lints::MatchTypeOnDiagItem)); store.register_late_pass(|_| Box::new(utils::internal_lints::MatchTypeOnDiagItem));
store.register_late_pass(|_| Box::new(utils::internal_lints::OuterExpnDataPass)); store.register_late_pass(|_| Box::new(utils::internal_lints::OuterExpnDataPass));
store.register_late_pass(|_| Box::new(utils::internal_lints::MsrvAttrImpl)); store.register_late_pass(|_| Box::new(utils::internal_lints::MsrvAttrImpl));
@@ -629,10 +627,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
msrv, msrv,
)) ))
}); });
store.register_late_pass(|_| Box::new(shadow::Shadow::default())); store.register_late_pass(|_| Box::<shadow::Shadow>::default());
store.register_late_pass(|_| Box::new(unit_types::UnitTypes)); store.register_late_pass(|_| Box::new(unit_types::UnitTypes));
store.register_late_pass(|_| Box::new(loops::Loops)); store.register_late_pass(|_| Box::new(loops::Loops));
store.register_late_pass(|_| Box::new(main_recursion::MainRecursion::default())); store.register_late_pass(|_| Box::<main_recursion::MainRecursion>::default());
store.register_late_pass(|_| Box::new(lifetimes::Lifetimes)); store.register_late_pass(|_| Box::new(lifetimes::Lifetimes));
store.register_late_pass(|_| Box::new(entry::HashMapPass)); store.register_late_pass(|_| Box::new(entry::HashMapPass));
store.register_late_pass(|_| Box::new(minmax::MinMaxPass)); store.register_late_pass(|_| Box::new(minmax::MinMaxPass));
@@ -666,7 +664,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(format::UselessFormat)); store.register_late_pass(|_| Box::new(format::UselessFormat));
store.register_late_pass(|_| Box::new(swap::Swap)); store.register_late_pass(|_| Box::new(swap::Swap));
store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional)); store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional));
store.register_late_pass(|_| Box::new(new_without_default::NewWithoutDefault::default())); store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default());
let disallowed_names = conf.disallowed_names.iter().cloned().collect::<FxHashSet<_>>(); let disallowed_names = conf.disallowed_names.iter().cloned().collect::<FxHashSet<_>>();
store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone()))); store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone())));
let too_many_arguments_threshold = conf.too_many_arguments_threshold; let too_many_arguments_threshold = conf.too_many_arguments_threshold;
@@ -705,7 +703,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(ref_option_ref::RefOptionRef)); store.register_late_pass(|_| Box::new(ref_option_ref::RefOptionRef));
store.register_late_pass(|_| Box::new(infinite_iter::InfiniteIter)); store.register_late_pass(|_| Box::new(infinite_iter::InfiniteIter));
store.register_late_pass(|_| Box::new(inline_fn_without_body::InlineFnWithoutBody)); store.register_late_pass(|_| Box::new(inline_fn_without_body::InlineFnWithoutBody));
store.register_late_pass(|_| Box::new(useless_conversion::UselessConversion::default())); store.register_late_pass(|_| Box::<useless_conversion::UselessConversion>::default());
store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher)); store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom)); store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
store.register_late_pass(|_| Box::new(question_mark::QuestionMark)); store.register_late_pass(|_| Box::new(question_mark::QuestionMark));
@@ -775,7 +773,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
upper_case_acronyms_aggressive, upper_case_acronyms_aggressive,
)) ))
}); });
store.register_late_pass(|_| Box::new(default::Default::default())); store.register_late_pass(|_| Box::<default::Default>::default());
store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api))); store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api)));
store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
store.register_late_pass(|_| Box::new(exit::Exit)); store.register_late_pass(|_| Box::new(exit::Exit));
@@ -798,7 +796,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap)); store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports; let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports))); store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
store.register_late_pass(|_| Box::new(redundant_pub_crate::RedundantPubCrate::default())); store.register_late_pass(|_| Box::<redundant_pub_crate::RedundantPubCrate>::default());
store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress)); store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv))); store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv)));
store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse));
@@ -816,7 +814,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
}); });
let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::<FxHashSet<_>>(); let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::<FxHashSet<_>>();
store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(&macro_matcher))); store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(&macro_matcher)));
store.register_late_pass(|_| Box::new(macro_use::MacroUseImports::default())); store.register_late_pass(|_| Box::<macro_use::MacroUseImports>::default());
store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch)); store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch));
store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult)); store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult));
store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
@@ -829,7 +827,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(strings::StrToString)); store.register_late_pass(|_| Box::new(strings::StrToString));
store.register_late_pass(|_| Box::new(strings::StringToString)); store.register_late_pass(|_| Box::new(strings::StringToString));
store.register_late_pass(|_| Box::new(zero_sized_map_values::ZeroSizedMapValues)); store.register_late_pass(|_| Box::new(zero_sized_map_values::ZeroSizedMapValues));
store.register_late_pass(|_| Box::new(vec_init_then_push::VecInitThenPush::default())); store.register_late_pass(|_| Box::<vec_init_then_push::VecInitThenPush>::default());
store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing)); store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing));
store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10)); store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10));
store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv))); store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv)));
@@ -857,7 +855,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
)) ))
}); });
store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks)); store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
store.register_late_pass(move |_| Box::new(format_args::FormatArgs)); store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv)));
store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray)); store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes)); store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit)); store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit));
@@ -867,7 +865,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv))); store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv)));
store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation)); store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation));
store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes)); store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes));
store.register_late_pass(|_| Box::new(only_used_in_recursion::OnlyUsedInRecursion::default())); store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default());
let allow_dbg_in_tests = conf.allow_dbg_in_tests; let allow_dbg_in_tests = conf.allow_dbg_in_tests;
store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests))); store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
let cargo_ignore_publish = conf.cargo_ignore_publish; let cargo_ignore_publish = conf.cargo_ignore_publish;
@@ -876,7 +874,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
ignore_publish: cargo_ignore_publish, ignore_publish: cargo_ignore_publish,
}) })
}); });
store.register_late_pass(|_| Box::new(write::Write::default())); store.register_late_pass(|_| Box::<write::Write>::default());
store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef)); store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets)); store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets));
store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)); store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
@@ -886,7 +884,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size))); store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace)); store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace));
store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default())); store.register_early_pass(|| Box::<duplicate_mod::DuplicateMod>::default());
store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding)); store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv))); store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv)));
store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef)); store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef));
@@ -898,13 +896,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold))); store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
store.register_late_pass(|_| Box::new(std_instead_of_core::StdReexports::default())); store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
store.register_late_pass(|_| Box::new(manual_instant_elapsed::ManualInstantElapsed)); store.register_late_pass(|_| Box::new(manual_instant_elapsed::ManualInstantElapsed));
store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone)); store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew)); store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew));
store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable)); store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable));
store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments)); store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments));
store.register_late_pass(|_| Box::new(bool_to_int_with_if::BoolToIntWithIf)); store.register_late_pass(|_| Box::new(bool_to_int_with_if::BoolToIntWithIf));
store.register_late_pass(|_| Box::new(box_default::BoxDefault));
// add lints here, do not remove this comment, it's used in `new_lint` // add lints here, do not remove this comment, it's used in `new_lint`
} }

View File

@@ -9,8 +9,8 @@ use rustc_hir::intravisit::{
use rustc_hir::FnRetTy::Return; use rustc_hir::FnRetTy::Return;
use rustc_hir::{ use rustc_hir::{
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem, BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin, ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin, TraitFn,
TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
}; };
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter as middle_nested_filter; use rustc_middle::hir::nested_filter as middle_nested_filter;
@@ -276,7 +276,7 @@ fn could_use_elision<'tcx>(
let mut checker = BodyLifetimeChecker { let mut checker = BodyLifetimeChecker {
lifetimes_used_in_body: false, lifetimes_used_in_body: false,
}; };
checker.visit_expr(&body.value); checker.visit_expr(body.value);
if checker.lifetimes_used_in_body { if checker.lifetimes_used_in_body {
return false; return false;
} }

View File

@@ -478,7 +478,7 @@ impl DecimalLiteralRepresentation {
if num_lit.radix == Radix::Decimal; if num_lit.radix == Radix::Decimal;
if val >= u128::from(self.threshold); if val >= u128::from(self.threshold);
then { then {
let hex = format!("{:#X}", val); let hex = format!("{val:#X}");
let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false); let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| { let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| {
warning_type.display(num_lit.format(), cx, lit.span); warning_type.display(num_lit.format(), cx, lit.span);

View File

@@ -44,11 +44,10 @@ pub(super) fn check<'tcx>(
cx, cx,
EXPLICIT_COUNTER_LOOP, EXPLICIT_COUNTER_LOOP,
span, span,
&format!("the variable `{}` is used as a loop counter", name), &format!("the variable `{name}` is used as a loop counter"),
"consider using", "consider using",
format!( format!(
"for ({}, {}) in {}.enumerate()", "for ({name}, {}) in {}.enumerate()",
name,
snippet_with_applicability(cx, pat.span, "item", &mut applicability), snippet_with_applicability(cx, pat.span, "item", &mut applicability),
make_iterator_snippet(cx, arg, &mut applicability), make_iterator_snippet(cx, arg, &mut applicability),
), ),
@@ -65,24 +64,21 @@ pub(super) fn check<'tcx>(
cx, cx,
EXPLICIT_COUNTER_LOOP, EXPLICIT_COUNTER_LOOP,
span, span,
&format!("the variable `{}` is used as a loop counter", name), &format!("the variable `{name}` is used as a loop counter"),
|diag| { |diag| {
diag.span_suggestion( diag.span_suggestion(
span, span,
"consider using", "consider using",
format!( format!(
"for ({}, {}) in (0_{}..).zip({})", "for ({name}, {}) in (0_{int_name}..).zip({})",
name,
snippet_with_applicability(cx, pat.span, "item", &mut applicability), snippet_with_applicability(cx, pat.span, "item", &mut applicability),
int_name,
make_iterator_snippet(cx, arg, &mut applicability), make_iterator_snippet(cx, arg, &mut applicability),
), ),
applicability, applicability,
); );
diag.note(&format!( diag.note(&format!(
"`{}` is of type `{}`, making it ineligible for `Iterator::enumerate`", "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`"
name, int_name
)); ));
}, },
); );

View File

@@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, m
"it is more concise to loop over references to containers instead of using explicit \ "it is more concise to loop over references to containers instead of using explicit \
iteration methods", iteration methods",
"to write this more concisely, try", "to write this more concisely, try",
format!("&{}{}", muta, object), format!("&{muta}{object}"),
applicability, applicability,
); );
} }

View File

@@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx
cx, cx,
FOR_KV_MAP, FOR_KV_MAP,
arg_span, arg_span,
&format!("you seem to want to iterate on a map's {}s", kind), &format!("you seem to want to iterate on a map's {kind}s"),
|diag| { |diag| {
let map = sugg::Sugg::hir(cx, arg, "map"); let map = sugg::Sugg::hir(cx, arg, "map");
multispan_sugg( multispan_sugg(
@@ -46,7 +46,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx
"use the corresponding method", "use the corresponding method",
vec![ vec![
(pat_span, snippet(cx, new_pat_span, kind).into_owned()), (pat_span, snippet(cx, new_pat_span, kind).into_owned()),
(arg_span, format!("{}.{}s{}()", map.maybe_par(), kind, mutbl)), (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_par())),
], ],
); );
}, },

View File

@@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(
then { then {
let if_let_type = if some_ctor { "Some" } else { "Ok" }; let if_let_type = if some_ctor { "Some" } else { "Ok" };
// Prepare the error message // Prepare the error message
let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type); let msg = format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used");
// Prepare the help message // Prepare the help message
let mut applicability = Applicability::MaybeIncorrect; let mut applicability = Applicability::MaybeIncorrect;

View File

@@ -177,13 +177,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
let dst = if dst_offset == sugg::EMPTY && dst_limit == sugg::EMPTY { let dst = if dst_offset == sugg::EMPTY && dst_limit == sugg::EMPTY {
dst_base_str dst_base_str
} else { } else {
format!( format!("{dst_base_str}[{}..{}]", dst_offset.maybe_par(), dst_limit.maybe_par()).into()
"{}[{}..{}]",
dst_base_str,
dst_offset.maybe_par(),
dst_limit.maybe_par()
)
.into()
}; };
let method_str = if is_copy(cx, elem_ty) { let method_str = if is_copy(cx, elem_ty) {
@@ -193,10 +187,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
}; };
format!( format!(
"{}.{}(&{}[{}..{}]);", "{dst}.{method_str}(&{src_base_str}[{}..{}]);",
dst,
method_str,
src_base_str,
src_offset.maybe_par(), src_offset.maybe_par(),
src_limit.maybe_par() src_limit.maybe_par()
) )

View File

@@ -635,7 +635,7 @@ declare_clippy_lint! {
/// arr.into_iter().find(|&el| el == 1) /// arr.into_iter().find(|&el| el == 1)
/// } /// }
/// ``` /// ```
#[clippy::version = "1.61.0"] #[clippy::version = "1.64.0"]
pub MANUAL_FIND, pub MANUAL_FIND,
complexity, complexity,
"manual implementation of `Iterator::find`" "manual implementation of `Iterator::find`"

View File

@@ -4,11 +4,11 @@ use clippy_utils::{get_enclosing_block, higher, path_to_local};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind}; use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind};
use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::{mir::FakeReadCause, ty}; use rustc_middle::{mir::FakeReadCause, ty};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) { pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
if_chain! { if_chain! {
@@ -114,7 +114,13 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
} }
} }
fn fake_read(&mut self, _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} fn fake_read(
&mut self,
_: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>,
_: FakeReadCause,
_: HirId,
) {
}
} }
impl MutatePairDelegate<'_, '_> { impl MutatePairDelegate<'_, '_> {

View File

@@ -45,7 +45,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
let (arg, pred) = contains_arg let (arg, pred) = contains_arg
.strip_prefix('&') .strip_prefix('&')
.map_or(("&x", &*contains_arg), |s| ("x", s)); .map_or(("&x", &*contains_arg), |s| ("x", s));
format!("any(|{}| x == {})", arg, pred) format!("any(|{arg}| x == {pred})")
} }
_ => return, _ => return,
} }
@@ -141,9 +141,9 @@ impl IterFunction {
IterFunctionKind::Contains(span) => { IterFunctionKind::Contains(span) => {
let s = snippet(cx, *span, ".."); let s = snippet(cx, *span, "..");
if let Some(stripped) = s.strip_prefix('&') { if let Some(stripped) = s.strip_prefix('&') {
format!(".any(|x| x == {})", stripped) format!(".any(|x| x == {stripped})")
} else { } else {
format!(".any(|x| x == *{})", s) format!(".any(|x| x == *{s})")
} }
}, },
} }

View File

@@ -145,7 +145,7 @@ pub(super) fn check<'tcx>(
cx, cx,
NEEDLESS_RANGE_LOOP, NEEDLESS_RANGE_LOOP,
arg.span, arg.span,
&format!("the loop variable `{}` is used to index `{}`", ident.name, indexed), &format!("the loop variable `{}` is used to index `{indexed}`", ident.name),
|diag| { |diag| {
multispan_sugg( multispan_sugg(
diag, diag,
@@ -154,7 +154,7 @@ pub(super) fn check<'tcx>(
(pat.span, format!("({}, <item>)", ident.name)), (pat.span, format!("({}, <item>)", ident.name)),
( (
arg.span, arg.span,
format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2), format!("{indexed}.{method}().enumerate(){method_1}{method_2}"),
), ),
], ],
); );
@@ -162,16 +162,16 @@ pub(super) fn check<'tcx>(
); );
} else { } else {
let repl = if starts_at_zero && take_is_empty { let repl = if starts_at_zero && take_is_empty {
format!("&{}{}", ref_mut, indexed) format!("&{ref_mut}{indexed}")
} else { } else {
format!("{}.{}(){}{}", indexed, method, method_1, method_2) format!("{indexed}.{method}(){method_1}{method_2}")
}; };
span_lint_and_then( span_lint_and_then(
cx, cx,
NEEDLESS_RANGE_LOOP, NEEDLESS_RANGE_LOOP,
arg.span, arg.span,
&format!("the loop variable `{}` is only used to index `{}`", ident.name, indexed), &format!("the loop variable `{}` is only used to index `{indexed}`", ident.name),
|diag| { |diag| {
multispan_sugg( multispan_sugg(
diag, diag,

View File

@@ -42,6 +42,7 @@ pub(super) fn check(
} }
} }
#[derive(Copy, Clone)]
enum NeverLoopResult { enum NeverLoopResult {
// A break/return always get triggered but not necessarily for the main loop. // A break/return always get triggered but not necessarily for the main loop.
AlwaysBreak, AlwaysBreak,
@@ -51,8 +52,8 @@ enum NeverLoopResult {
} }
#[must_use] #[must_use]
fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult { fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
match *arg { match arg {
NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise, NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop, NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
} }
@@ -92,19 +93,29 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
} }
fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult { fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
let mut iter = block.stmts.iter().filter_map(stmt_to_expr).chain(block.expr); let mut iter = block
.stmts
.iter()
.filter_map(stmt_to_expr)
.chain(block.expr.map(|expr| (expr, None)));
never_loop_expr_seq(&mut iter, main_loop_id) never_loop_expr_seq(&mut iter, main_loop_id)
} }
fn never_loop_expr_seq<'a, T: Iterator<Item = &'a Expr<'a>>>(es: &mut T, main_loop_id: HirId) -> NeverLoopResult { fn never_loop_expr_seq<'a, T: Iterator<Item = (&'a Expr<'a>, Option<&'a Block<'a>>)>>(
es.map(|e| never_loop_expr(e, main_loop_id)) es: &mut T,
main_loop_id: HirId,
) -> NeverLoopResult {
es.map(|(e, els)| {
let e = never_loop_expr(e, main_loop_id);
els.map_or(e, |els| combine_branches(e, never_loop_block(els, main_loop_id)))
})
.fold(NeverLoopResult::Otherwise, combine_seq) .fold(NeverLoopResult::Otherwise, combine_seq)
} }
fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> { fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'tcx Block<'tcx>>)> {
match stmt.kind { match stmt.kind {
StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some(e), StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some((e, None)),
StmtKind::Local(local) => local.init, StmtKind::Local(local) => local.init.map(|init| (init, local.els)),
StmtKind::Item(..) => None, StmtKind::Item(..) => None,
} }
} }
@@ -139,7 +150,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
| ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), main_loop_id), | ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), main_loop_id),
ExprKind::Loop(b, _, _, _) => { ExprKind::Loop(b, _, _, _) => {
// Break can come from the inner loop so remove them. // Break can come from the inner loop so remove them.
absorb_break(&never_loop_block(b, main_loop_id)) absorb_break(never_loop_block(b, main_loop_id))
}, },
ExprKind::If(e, e2, e3) => { ExprKind::If(e, e2, e3) => {
let e1 = never_loop_expr(e, main_loop_id); let e1 = never_loop_expr(e, main_loop_id);
@@ -211,9 +222,5 @@ fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>)
let pat_snippet = snippet(cx, pat.span, "_"); let pat_snippet = snippet(cx, pat.span, "_");
let iter_snippet = make_iterator_snippet(cx, iterator, &mut Applicability::Unspecified); let iter_snippet = make_iterator_snippet(cx, iterator, &mut Applicability::Unspecified);
format!( format!("if let Some({pat_snippet}) = {iter_snippet}.next()")
"if let Some({pat}) = {iter}.next()",
pat = pat_snippet,
iter = iter_snippet
)
} }

View File

@@ -30,10 +30,7 @@ pub(super) fn check<'tcx>(
vec.span, vec.span,
"it looks like the same item is being pushed into this Vec", "it looks like the same item is being pushed into this Vec",
None, None,
&format!( &format!("try using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"),
"try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
item_str, vec_str, item_str
),
); );
} }

Some files were not shown because too many files have changed in this diff Show More