Merge remote-tracking branch 'upstream/master' into rustup
This commit is contained in:
commit
82c3064c47
119 changed files with 2718 additions and 834 deletions
97
CHANGELOG.md
97
CHANGELOG.md
|
@ -6,11 +6,101 @@ document.
|
||||||
|
|
||||||
## Unreleased / Beta / In Rust Nightly
|
## Unreleased / Beta / In Rust Nightly
|
||||||
|
|
||||||
[37f4c172...master](https://github.com/rust-lang/rust-clippy/compare/37f4c172...master)
|
[1e8fdf49...master](https://github.com/rust-lang/rust-clippy/compare/1e8fdf49...master)
|
||||||
|
|
||||||
|
## Rust 1.73
|
||||||
|
|
||||||
|
Current stable, released 2023-10-05
|
||||||
|
|
||||||
|
[View all 103 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-07-02T12%3A24%3A40Z..2023-08-11T11%3A09%3A56Z+base%3Amaster)
|
||||||
|
|
||||||
|
### New Lints
|
||||||
|
|
||||||
|
* [`impossible_comparisons`]
|
||||||
|
[#10843](https://github.com/rust-lang/rust-clippy/pull/10843)
|
||||||
|
* [`redundant_comparisons`]
|
||||||
|
[#10843](https://github.com/rust-lang/rust-clippy/pull/10843)
|
||||||
|
* [`ignored_unit_patterns`]
|
||||||
|
[#11242](https://github.com/rust-lang/rust-clippy/pull/11242)
|
||||||
|
* [`readonly_write_lock`]
|
||||||
|
[#11210](https://github.com/rust-lang/rust-clippy/pull/11210)
|
||||||
|
* [`filter_map_bool_then`]
|
||||||
|
[#11115](https://github.com/rust-lang/rust-clippy/pull/11115)
|
||||||
|
* [`needless_return_with_question_mark`]
|
||||||
|
[#11031](https://github.com/rust-lang/rust-clippy/pull/11031)
|
||||||
|
* [`redundant_guards`]
|
||||||
|
[#10955](https://github.com/rust-lang/rust-clippy/pull/10955)
|
||||||
|
* [`redundant_locals`]
|
||||||
|
[#10885](https://github.com/rust-lang/rust-clippy/pull/10885)
|
||||||
|
* [`absolute_paths`]
|
||||||
|
[#11003](https://github.com/rust-lang/rust-clippy/pull/11003)
|
||||||
|
* [`error_impl_error`]
|
||||||
|
[#11107](https://github.com/rust-lang/rust-clippy/pull/11107)
|
||||||
|
* [`iter_skip_zero`]
|
||||||
|
[#11046](https://github.com/rust-lang/rust-clippy/pull/11046)
|
||||||
|
* [`string_lit_chars_any`]
|
||||||
|
[#11052](https://github.com/rust-lang/rust-clippy/pull/11052)
|
||||||
|
* [`four_forward_slashes`]
|
||||||
|
[#11140](https://github.com/rust-lang/rust-clippy/pull/11140)
|
||||||
|
* [`format_collect`]
|
||||||
|
[#11116](https://github.com/rust-lang/rust-clippy/pull/11116)
|
||||||
|
* [`needless_pass_by_ref_mut`]
|
||||||
|
[#10900](https://github.com/rust-lang/rust-clippy/pull/10900)
|
||||||
|
* [`manual_is_infinite`]
|
||||||
|
[#11049](https://github.com/rust-lang/rust-clippy/pull/11049)
|
||||||
|
* [`manual_is_finite`]
|
||||||
|
[#11049](https://github.com/rust-lang/rust-clippy/pull/11049)
|
||||||
|
* [`incorrect_partial_ord_impl_on_ord_type`]
|
||||||
|
[#10788](https://github.com/rust-lang/rust-clippy/pull/10788)
|
||||||
|
* [`read_line_without_trim`]
|
||||||
|
[#10970](https://github.com/rust-lang/rust-clippy/pull/10970)
|
||||||
|
* [`type_id_on_box`]
|
||||||
|
[#10987](https://github.com/rust-lang/rust-clippy/pull/10987)
|
||||||
|
|
||||||
|
### Moves and Deprecations
|
||||||
|
|
||||||
|
* Renamed `unwrap_or_else_default` to [`unwrap_or_default`]
|
||||||
|
[#10120](https://github.com/rust-lang/rust-clippy/pull/10120)
|
||||||
|
* Moved [`tuple_array_conversions`] to `pedantic` (Now allow-by-default)
|
||||||
|
[#11146](https://github.com/rust-lang/rust-clippy/pull/11146)
|
||||||
|
* Moved [`arc_with_non_send_sync`] to `suspicious` (Now warn-by-default)
|
||||||
|
[#11104](https://github.com/rust-lang/rust-clippy/pull/11104)
|
||||||
|
* Moved [`needless_raw_string_hashes`] to `pedantic` (Now allow-by-default)
|
||||||
|
[#11415](https://github.com/rust-lang/rust-clippy/pull/11415)
|
||||||
|
|
||||||
|
### Enhancements
|
||||||
|
|
||||||
|
* [`unwrap_used`]: No longer lints on the never-type or never-like enums
|
||||||
|
[#11252](https://github.com/rust-lang/rust-clippy/pull/11252)
|
||||||
|
* [`expect_used`]: No longer lints on the never-type or never-like enums
|
||||||
|
[#11252](https://github.com/rust-lang/rust-clippy/pull/11252)
|
||||||
|
|
||||||
|
### False Positive Fixes
|
||||||
|
|
||||||
|
* [`panic_in_result_fn`]: No longer triggers on `todo!`, `unimplemented!`, `unreachable!`
|
||||||
|
[#11123](https://github.com/rust-lang/rust-clippy/pull/11123)
|
||||||
|
|
||||||
|
### Suggestion Fixes/Improvements
|
||||||
|
|
||||||
|
* [`semicolon_if_nothing_returned`]: The suggestion is now machine-applicable with rustfix
|
||||||
|
[#11083](https://github.com/rust-lang/rust-clippy/pull/11083)
|
||||||
|
|
||||||
|
### ICE Fixes
|
||||||
|
|
||||||
|
* [`filter_map_bool_then`]: No longer crashes on late-bound regions
|
||||||
|
[#11318](https://github.com/rust-lang/rust-clippy/pull/11318)
|
||||||
|
* [`unwrap_or_default`]: No longer crashes on alias types for local items
|
||||||
|
[#11258](https://github.com/rust-lang/rust-clippy/pull/11258)
|
||||||
|
* [`unnecessary_literal_unwrap`]: No longer crashes on `None.unwrap_or_default()`
|
||||||
|
[#11106](https://github.com/rust-lang/rust-clippy/pull/11106)
|
||||||
|
* Fixed MIR-related ICE
|
||||||
|
[#11130](https://github.com/rust-lang/rust-clippy/pull/11130)
|
||||||
|
* [`missing_fields_in_debug`]: No longer crashes on non-ADT self types
|
||||||
|
[#11069](https://github.com/rust-lang/rust-clippy/pull/11069)
|
||||||
|
|
||||||
## Rust 1.72
|
## Rust 1.72
|
||||||
|
|
||||||
Current stable, released 2023-08-24
|
Released 2023-08-24
|
||||||
|
|
||||||
[View all 131 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-05-22T14%3A53%3A59Z..2023-07-01T22%3A57%3A20Z+base%3Amaster)
|
[View all 131 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-05-22T14%3A53%3A59Z..2023-07-01T22%3A57%3A20Z+base%3Amaster)
|
||||||
|
|
||||||
|
@ -5011,6 +5101,7 @@ Released 2018-09-13
|
||||||
[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
|
[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
|
||||||
[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
|
[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
|
||||||
[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
|
[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
|
||||||
|
[`into_iter_without_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_without_iter
|
||||||
[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering
|
[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering
|
||||||
[`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage
|
[`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage
|
||||||
[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
|
[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
|
||||||
|
@ -5036,6 +5127,7 @@ Released 2018-09-13
|
||||||
[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
|
[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
|
||||||
[`iter_skip_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_zero
|
[`iter_skip_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_zero
|
||||||
[`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain
|
[`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain
|
||||||
|
[`iter_without_into_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_without_into_iter
|
||||||
[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
|
[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
|
||||||
[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
|
[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
|
||||||
[`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays
|
[`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays
|
||||||
|
@ -5072,6 +5164,7 @@ Released 2018-09-13
|
||||||
[`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find
|
[`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find
|
||||||
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
|
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
|
||||||
[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
|
[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
|
||||||
|
[`manual_hash_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one
|
||||||
[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed
|
[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed
|
||||||
[`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check
|
[`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check
|
||||||
[`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite
|
[`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite
|
||||||
|
|
|
@ -25,6 +25,8 @@ clippy_lints = { path = "clippy_lints" }
|
||||||
rustc_tools_util = "0.3.0"
|
rustc_tools_util = "0.3.0"
|
||||||
tempfile = { version = "3.2", optional = true }
|
tempfile = { version = "3.2", optional = true }
|
||||||
termize = "0.1"
|
termize = "0.1"
|
||||||
|
color-print = "0.3.4" # Sync version with Cargo
|
||||||
|
anstream = "0.5.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
ui_test = "0.20"
|
ui_test = "0.20"
|
||||||
|
|
|
@ -261,7 +261,7 @@ impl EarlyLintPass for FooFunctions {}
|
||||||
[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
|
[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
|
||||||
[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
|
[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
|
||||||
[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
|
[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
|
||||||
[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
|
[category_level_mapping]: ../index.html
|
||||||
|
|
||||||
## Lint registration
|
## Lint registration
|
||||||
|
|
||||||
|
|
|
@ -151,6 +151,7 @@ The minimum rust version that the project supports
|
||||||
* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds)
|
* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds)
|
||||||
* [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions)
|
* [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions)
|
||||||
* [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold)
|
* [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold)
|
||||||
|
* [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one)
|
||||||
|
|
||||||
|
|
||||||
## `cognitive-complexity-threshold`
|
## `cognitive-complexity-threshold`
|
||||||
|
|
|
@ -58,7 +58,7 @@ pub fn create(
|
||||||
};
|
};
|
||||||
|
|
||||||
create_lint(&lint, msrv).context("Unable to create lint implementation")?;
|
create_lint(&lint, msrv).context("Unable to create lint implementation")?;
|
||||||
create_test(&lint).context("Unable to create a test for the new lint")?;
|
create_test(&lint, msrv).context("Unable to create a test for the new lint")?;
|
||||||
|
|
||||||
if lint.ty.is_none() {
|
if lint.ty.is_none() {
|
||||||
add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")?;
|
add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")?;
|
||||||
|
@ -88,15 +88,21 @@ fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_test(lint: &LintData<'_>) -> io::Result<()> {
|
fn create_test(lint: &LintData<'_>, msrv: bool) -> io::Result<()> {
|
||||||
fn create_project_layout<P: Into<PathBuf>>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> {
|
fn create_project_layout<P: Into<PathBuf>>(
|
||||||
|
lint_name: &str,
|
||||||
|
location: P,
|
||||||
|
case: &str,
|
||||||
|
hint: &str,
|
||||||
|
msrv: bool,
|
||||||
|
) -> io::Result<()> {
|
||||||
let mut path = location.into().join(case);
|
let mut path = location.into().join(case);
|
||||||
fs::create_dir(&path)?;
|
fs::create_dir(&path)?;
|
||||||
write_file(path.join("Cargo.toml"), get_manifest_contents(lint_name, hint))?;
|
write_file(path.join("Cargo.toml"), get_manifest_contents(lint_name, hint))?;
|
||||||
|
|
||||||
path.push("src");
|
path.push("src");
|
||||||
fs::create_dir(&path)?;
|
fs::create_dir(&path)?;
|
||||||
write_file(path.join("main.rs"), get_test_file_contents(lint_name))?;
|
write_file(path.join("main.rs"), get_test_file_contents(lint_name, msrv))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -106,13 +112,25 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
|
||||||
let test_dir = lint.project_root.join(&relative_test_dir);
|
let test_dir = lint.project_root.join(&relative_test_dir);
|
||||||
fs::create_dir(&test_dir)?;
|
fs::create_dir(&test_dir)?;
|
||||||
|
|
||||||
create_project_layout(lint.name, &test_dir, "fail", "Content that triggers the lint goes here")?;
|
create_project_layout(
|
||||||
create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint")?;
|
lint.name,
|
||||||
|
&test_dir,
|
||||||
|
"fail",
|
||||||
|
"Content that triggers the lint goes here",
|
||||||
|
msrv,
|
||||||
|
)?;
|
||||||
|
create_project_layout(
|
||||||
|
lint.name,
|
||||||
|
&test_dir,
|
||||||
|
"pass",
|
||||||
|
"This file should not trigger the lint",
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
|
||||||
println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`");
|
println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`");
|
||||||
} else {
|
} else {
|
||||||
let test_path = format!("tests/ui/{}.rs", lint.name);
|
let test_path = format!("tests/ui/{}.rs", lint.name);
|
||||||
let test_contents = get_test_file_contents(lint.name);
|
let test_contents = get_test_file_contents(lint.name, msrv);
|
||||||
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}`");
|
||||||
|
@ -194,8 +212,8 @@ pub(crate) fn get_stabilization_version() -> String {
|
||||||
parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
|
parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_test_file_contents(lint_name: &str) -> String {
|
fn get_test_file_contents(lint_name: &str, msrv: bool) -> String {
|
||||||
formatdoc!(
|
let mut test = formatdoc!(
|
||||||
r#"
|
r#"
|
||||||
#![warn(clippy::{lint_name})]
|
#![warn(clippy::{lint_name})]
|
||||||
|
|
||||||
|
@ -203,7 +221,29 @@ fn get_test_file_contents(lint_name: &str) -> String {
|
||||||
// test code goes here
|
// test code goes here
|
||||||
}}
|
}}
|
||||||
"#
|
"#
|
||||||
)
|
);
|
||||||
|
|
||||||
|
if msrv {
|
||||||
|
let _ = writedoc!(
|
||||||
|
test,
|
||||||
|
r#"
|
||||||
|
|
||||||
|
// TODO: set xx to the version one below the MSRV used by the lint, and yy to
|
||||||
|
// the version used by the lint
|
||||||
|
#[clippy::msrv = "1.xx"]
|
||||||
|
fn msrv_1_xx() {{
|
||||||
|
// a simple example that would trigger the lint if the MSRV were met
|
||||||
|
}}
|
||||||
|
|
||||||
|
#[clippy::msrv = "1.yy"]
|
||||||
|
fn msrv_1_yy() {{
|
||||||
|
// the same example as above
|
||||||
|
}}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
|
fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
|
||||||
|
@ -258,7 +298,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let _: fmt::Result = write!(result, "{}", get_lint_declaration(&name_upper, category));
|
let _: fmt::Result = writeln!(result, "{}", get_lint_declaration(&name_upper, category));
|
||||||
|
|
||||||
result.push_str(&if enable_msrv {
|
result.push_str(&if enable_msrv {
|
||||||
formatdoc!(
|
formatdoc!(
|
||||||
|
@ -281,7 +321,6 @@ 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: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
|
// TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
|
||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
|
|
|
@ -28,6 +28,9 @@ semver = "1.0"
|
||||||
rustc-semver = "1.1"
|
rustc-semver = "1.1"
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
walkdir = "2.3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
deny-warnings = ["clippy_utils/deny-warnings"]
|
deny-warnings = ["clippy_utils/deny-warnings"]
|
||||||
# build clippy with internal lints enabled, off by default
|
# build clippy with internal lints enabled, off by default
|
||||||
|
|
|
@ -8,6 +8,7 @@ use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
/// Checks for usage of the `#[allow]` attribute and suggests replacing it with
|
/// Checks for usage of the `#[allow]` attribute and suggests replacing it with
|
||||||
/// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html))
|
/// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html))
|
||||||
///
|
///
|
||||||
|
@ -19,7 +20,6 @@ declare_clippy_lint! {
|
||||||
/// (`#![allow]`) are usually used to enable or disable lints on a global scale.
|
/// (`#![allow]`) are usually used to enable or disable lints on a global scale.
|
||||||
///
|
///
|
||||||
/// ### Why is this bad?
|
/// ### Why is this bad?
|
||||||
///
|
|
||||||
/// `#[expect]` attributes suppress the lint emission, but emit a warning, if
|
/// `#[expect]` attributes suppress the lint emission, but emit a warning, if
|
||||||
/// the expectation is unfulfilled. This can be useful to be notified when the
|
/// the expectation is unfulfilled. This can be useful to be notified when the
|
||||||
/// lint is no longer triggered.
|
/// lint is no longer triggered.
|
||||||
|
|
|
@ -229,6 +229,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO,
|
crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO,
|
||||||
crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO,
|
crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO,
|
||||||
crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO,
|
crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO,
|
||||||
|
crate::iter_without_into_iter::INTO_ITER_WITHOUT_ITER_INFO,
|
||||||
|
crate::iter_without_into_iter::ITER_WITHOUT_INTO_ITER_INFO,
|
||||||
crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO,
|
crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO,
|
||||||
crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO,
|
crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO,
|
||||||
crate::large_futures::LARGE_FUTURES_INFO,
|
crate::large_futures::LARGE_FUTURES_INFO,
|
||||||
|
@ -280,6 +282,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::manual_clamp::MANUAL_CLAMP_INFO,
|
crate::manual_clamp::MANUAL_CLAMP_INFO,
|
||||||
crate::manual_float_methods::MANUAL_IS_FINITE_INFO,
|
crate::manual_float_methods::MANUAL_IS_FINITE_INFO,
|
||||||
crate::manual_float_methods::MANUAL_IS_INFINITE_INFO,
|
crate::manual_float_methods::MANUAL_IS_INFINITE_INFO,
|
||||||
|
crate::manual_hash_one::MANUAL_HASH_ONE_INFO,
|
||||||
crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO,
|
crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO,
|
||||||
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
|
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
|
||||||
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
|
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! lint on C-like enums that are `repr(isize/usize)` and have values that
|
//! lint on C-like enums that are `repr(isize/usize)` and have values that
|
||||||
//! don't fit into an `i32`
|
//! don't fit into an `i32`
|
||||||
|
|
||||||
use clippy_utils::consts::{miri_to_const, Constant};
|
use clippy_utils::consts::{mir_to_const, Constant};
|
||||||
use clippy_utils::diagnostics::span_lint;
|
use clippy_utils::diagnostics::span_lint;
|
||||||
use rustc_hir::{Item, ItemKind};
|
use rustc_hir::{Item, ItemKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
|
||||||
.const_eval_poly(def_id.to_def_id())
|
.const_eval_poly(def_id.to_def_id())
|
||||||
.ok()
|
.ok()
|
||||||
.map(|val| rustc_middle::mir::Const::from_value(val, ty));
|
.map(|val| rustc_middle::mir::Const::from_value(val, ty));
|
||||||
if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) {
|
if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx, c)) {
|
||||||
if let ty::Adt(adt, _) = ty.kind() {
|
if let ty::Adt(adt, _) = ty.kind() {
|
||||||
if adt.is_enum() {
|
if adt.is_enum() {
|
||||||
ty = adt.repr().discr_type().to_ty(cx.tcx);
|
ty = adt.repr().discr_type().to_ty(cx.tcx);
|
||||||
|
|
|
@ -27,7 +27,7 @@ declare_clippy_lint! {
|
||||||
///
|
///
|
||||||
/// impl std::error::Error for Error { ... }
|
/// impl std::error::Error for Error { ... }
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub ERROR_IMPL_ERROR,
|
pub ERROR_IMPL_ERROR,
|
||||||
restriction,
|
restriction,
|
||||||
"exported types named `Error` that implement `Error`"
|
"exported types named `Error` that implement `Error`"
|
||||||
|
|
|
@ -28,7 +28,7 @@ declare_clippy_lint! {
|
||||||
/// // ...
|
/// // ...
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub FOUR_FORWARD_SLASHES,
|
pub FOUR_FORWARD_SLASHES,
|
||||||
suspicious,
|
suspicious,
|
||||||
"comments with 4 forward slashes (`////`) likely intended to be doc comments (`///`)"
|
"comments with 4 forward slashes (`////`) likely intended to be doc comments (`///`)"
|
||||||
|
|
|
@ -37,6 +37,10 @@ declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
|
impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
|
||||||
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
|
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
|
||||||
|
if pat.span.from_expansion() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
match cx.tcx.hir().get_parent(pat.hir_id) {
|
match cx.tcx.hir().get_parent(pat.hir_id) {
|
||||||
Node::Param(param) if matches!(cx.tcx.hir().get_parent(param.hir_id), Node::Item(_)) => {
|
Node::Param(param) if matches!(cx.tcx.hir().get_parent(param.hir_id), Node::Item(_)) => {
|
||||||
// Ignore function parameters
|
// Ignore function parameters
|
||||||
|
|
|
@ -6,9 +6,8 @@ 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_hir_analysis::hir_ty_to_ty;
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::lint::in_external_macro;
|
|
||||||
use rustc_middle::ty::{Ty, TypeckResults};
|
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;
|
||||||
|
@ -162,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
|
||||||
vis.visit_ty(ty);
|
vis.visit_ty(ty);
|
||||||
|
|
||||||
for target in &vis.found {
|
for target in &vis.found {
|
||||||
if in_external_macro(cx.sess(), generics.span) {
|
if generics.span.from_expansion() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let generics_suggestion_span = generics.span.substitute_dummy({
|
let generics_suggestion_span = generics.span.substitute_dummy({
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use clippy_utils::diagnostics::span_lint_and_help;
|
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||||
use clippy_utils::{is_from_proc_macro, is_in_cfg_test};
|
use clippy_utils::source::snippet_opt;
|
||||||
use rustc_hir::{HirId, ItemId, ItemKind, Mod};
|
use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_errors::{Applicability, SuggestionStyle};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_hir::{HirId, Item, ItemKind, Mod};
|
||||||
|
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, Span};
|
use rustc_span::hygiene::AstPass;
|
||||||
|
use rustc_span::{sym, ExpnKind};
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
|
@ -41,46 +43,72 @@ declare_clippy_lint! {
|
||||||
|
|
||||||
declare_lint_pass!(ItemsAfterTestModule => [ITEMS_AFTER_TEST_MODULE]);
|
declare_lint_pass!(ItemsAfterTestModule => [ITEMS_AFTER_TEST_MODULE]);
|
||||||
|
|
||||||
|
fn cfg_test_module<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool {
|
||||||
|
if let ItemKind::Mod(test_mod) = item.kind
|
||||||
|
&& item.span.hi() == test_mod.spans.inner_span.hi()
|
||||||
|
&& is_cfg_test(cx.tcx, item.hir_id())
|
||||||
|
&& !item.span.from_expansion()
|
||||||
|
&& !is_from_proc_macro(cx, item)
|
||||||
|
{
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl LateLintPass<'_> for ItemsAfterTestModule {
|
impl LateLintPass<'_> for ItemsAfterTestModule {
|
||||||
fn check_mod(&mut self, cx: &LateContext<'_>, _: &Mod<'_>, _: HirId) {
|
fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: HirId) {
|
||||||
let mut was_test_mod_visited = false;
|
let mut items = module.item_ids.iter().map(|&id| cx.tcx.hir().item(id));
|
||||||
let mut test_mod_span: Option<Span> = None;
|
|
||||||
|
|
||||||
let hir = cx.tcx.hir();
|
let Some((mod_pos, test_mod)) = items.by_ref().enumerate().find(|(_, item)| cfg_test_module(cx, item)) else {
|
||||||
let items = hir.items().collect::<Vec<ItemId>>();
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
for (i, itid) in items.iter().enumerate() {
|
let after: Vec<_> = items
|
||||||
let item = hir.item(*itid);
|
.filter(|item| {
|
||||||
|
// Ignore the generated test main function
|
||||||
|
!(item.ident.name == sym::main
|
||||||
|
&& item.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::TestHarness))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
if_chain! {
|
if let Some(last) = after.last()
|
||||||
if was_test_mod_visited;
|
&& after.iter().all(|&item| {
|
||||||
if i == (items.len() - 3 /* Weird magic number (HIR-translation behaviour) */);
|
!matches!(item.kind, ItemKind::Mod(_))
|
||||||
if cx.sess().source_map().lookup_char_pos(item.span.lo()).file.name_hash
|
&& !item.span.from_expansion()
|
||||||
== cx.sess().source_map().lookup_char_pos(test_mod_span.unwrap().lo()).file.name_hash; // Will never fail
|
&& !is_from_proc_macro(cx, item)
|
||||||
if !matches!(item.kind, ItemKind::Mod(_));
|
})
|
||||||
if !is_in_cfg_test(cx.tcx, itid.hir_id()); // The item isn't in the testing module itself
|
&& !fulfill_or_allowed(cx, ITEMS_AFTER_TEST_MODULE, after.iter().map(|item| item.hir_id()))
|
||||||
if !in_external_macro(cx.sess(), item.span);
|
{
|
||||||
if !is_from_proc_macro(cx, item);
|
let def_spans: Vec<_> = std::iter::once(test_mod.owner_id)
|
||||||
|
.chain(after.iter().map(|item| item.owner_id))
|
||||||
|
.map(|id| cx.tcx.def_span(id))
|
||||||
|
.collect();
|
||||||
|
|
||||||
then {
|
span_lint_hir_and_then(
|
||||||
span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined");
|
cx,
|
||||||
}};
|
ITEMS_AFTER_TEST_MODULE,
|
||||||
|
test_mod.hir_id(),
|
||||||
if let ItemKind::Mod(module) = item.kind && item.span.hi() == module.spans.inner_span.hi() {
|
def_spans,
|
||||||
// Check that it works the same way, the only I way I've found for #10713
|
"items after a test module",
|
||||||
for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
|
|diag| {
|
||||||
if_chain! {
|
if let Some(prev) = mod_pos.checked_sub(1)
|
||||||
if attr.has_name(sym::cfg);
|
&& let prev = cx.tcx.hir().item(module.item_ids[prev])
|
||||||
if let Some(mitems) = attr.meta_item_list();
|
&& let items_span = last.span.with_lo(test_mod.span.hi())
|
||||||
if let [mitem] = &*mitems;
|
&& let Some(items) = snippet_opt(cx, items_span)
|
||||||
if mitem.has_name(sym::test);
|
{
|
||||||
then {
|
diag.multipart_suggestion_with_style(
|
||||||
was_test_mod_visited = true;
|
"move the items to before the test module was defined",
|
||||||
test_mod_span = Some(item.span);
|
vec![
|
||||||
}
|
(prev.span.shrink_to_hi(), items),
|
||||||
|
(items_span, String::new())
|
||||||
|
],
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
SuggestionStyle::HideCodeAlways,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
249
clippy_lints/src/iter_without_into_iter.rs
Normal file
249
clippy_lints/src/iter_without_into_iter.rs
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
|
use clippy_utils::get_parent_as_impl;
|
||||||
|
use clippy_utils::source::snippet;
|
||||||
|
use clippy_utils::ty::{implements_trait, make_normalized_projection};
|
||||||
|
use rustc_ast::Mutability;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind};
|
||||||
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_middle::ty::{self, Ty};
|
||||||
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
|
use rustc_span::{sym, Symbol};
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Looks for `iter` and `iter_mut` methods without an associated `IntoIterator for (&|&mut) Type` implementation.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// It's not bad, but having them is idiomatic and allows the type to be used in for loops directly
|
||||||
|
/// (`for val in &iter {}`), without having to first call `iter()` or `iter_mut()`.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```rust
|
||||||
|
/// struct MySlice<'a>(&'a [u8]);
|
||||||
|
/// impl<'a> MySlice<'a> {
|
||||||
|
/// pub fn iter(&self) -> std::slice::Iter<'a, u8> {
|
||||||
|
/// self.0.iter()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust
|
||||||
|
/// struct MySlice<'a>(&'a [u8]);
|
||||||
|
/// impl<'a> MySlice<'a> {
|
||||||
|
/// pub fn iter(&self) -> std::slice::Iter<'a, u8> {
|
||||||
|
/// self.0.iter()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// impl<'a> IntoIterator for &MySlice<'a> {
|
||||||
|
/// type Item = &'a u8;
|
||||||
|
/// type IntoIter = std::slice::Iter<'a, u8>;
|
||||||
|
/// fn into_iter(self) -> Self::IntoIter {
|
||||||
|
/// self.iter()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.74.0"]
|
||||||
|
pub ITER_WITHOUT_INTO_ITER,
|
||||||
|
pedantic,
|
||||||
|
"implementing `iter(_mut)` without an associated `IntoIterator for (&|&mut) Type` impl"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// This is the opposite of the `iter_without_into_iter` lint.
|
||||||
|
/// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// It's not bad, but having them is idiomatic and allows the type to be used in iterator chains
|
||||||
|
/// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).iter()` syntax
|
||||||
|
/// in case of ambiguity with another `Intoiterator` impl.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```rust
|
||||||
|
/// struct MySlice<'a>(&'a [u8]);
|
||||||
|
/// impl<'a> IntoIterator for &MySlice<'a> {
|
||||||
|
/// type Item = &'a u8;
|
||||||
|
/// type IntoIter = std::slice::Iter<'a, u8>;
|
||||||
|
/// fn into_iter(self) -> Self::IntoIter {
|
||||||
|
/// self.0.iter()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust
|
||||||
|
/// struct MySlice<'a>(&'a [u8]);
|
||||||
|
/// impl<'a> MySlice<'a> {
|
||||||
|
/// pub fn iter(&self) -> std::slice::Iter<'a, u8> {
|
||||||
|
/// self.into_iter()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// impl<'a> IntoIterator for &MySlice<'a> {
|
||||||
|
/// type Item = &'a u8;
|
||||||
|
/// type IntoIter = std::slice::Iter<'a, u8>;
|
||||||
|
/// fn into_iter(self) -> Self::IntoIter {
|
||||||
|
/// self.0.iter()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.74.0"]
|
||||||
|
pub INTO_ITER_WITHOUT_ITER,
|
||||||
|
pedantic,
|
||||||
|
"implementing `IntoIterator for (&|&mut) Type` without an inherent `iter(_mut)` method"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(IterWithoutIntoIter => [ITER_WITHOUT_INTO_ITER, INTO_ITER_WITHOUT_ITER]);
|
||||||
|
|
||||||
|
/// Checks if a given type is nameable in a trait (impl).
|
||||||
|
/// RPIT is stable, but impl Trait in traits is not (yet), so when we have
|
||||||
|
/// a function such as `fn iter(&self) -> impl IntoIterator`, we can't
|
||||||
|
/// suggest `type IntoIter = impl IntoIterator`.
|
||||||
|
fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool {
|
||||||
|
!matches!(ty.kind, TyKind::OpaqueDef(..))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
|
||||||
|
if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) {
|
||||||
|
cx.tcx.inherent_impls(ty_did).iter().any(|&did| {
|
||||||
|
cx.tcx
|
||||||
|
.associated_items(did)
|
||||||
|
.filter_by_name_unhygienic(method_name)
|
||||||
|
.next()
|
||||||
|
.is_some_and(|item| item.kind == ty::AssocKind::Fn)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LateLintPass<'_> for IterWithoutIntoIter {
|
||||||
|
fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
|
||||||
|
if let ItemKind::Impl(imp) = item.kind
|
||||||
|
&& let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind
|
||||||
|
&& let Some(trait_ref) = imp.of_trait
|
||||||
|
&& trait_ref.trait_def_id().is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did))
|
||||||
|
&& let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind()
|
||||||
|
&& let expected_method_name = match mtbl {
|
||||||
|
Mutability::Mut => sym::iter_mut,
|
||||||
|
Mutability::Not => sym::iter,
|
||||||
|
}
|
||||||
|
&& !type_has_inherent_method(cx, ty, expected_method_name)
|
||||||
|
&& let Some(iter_assoc_span) = imp.items.iter().find_map(|item| {
|
||||||
|
if item.ident.name == sym!(IntoIter) {
|
||||||
|
Some(cx.tcx.hir().impl_item(item.id).expect_type().span)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{
|
||||||
|
span_lint_and_then(
|
||||||
|
cx,
|
||||||
|
INTO_ITER_WITHOUT_ITER,
|
||||||
|
item.span,
|
||||||
|
&format!("`IntoIterator` implemented for a reference type without an `{expected_method_name}` method"),
|
||||||
|
|diag| {
|
||||||
|
// The suggestion forwards to the `IntoIterator` impl and uses a form of UFCS
|
||||||
|
// to avoid name ambiguities, as there might be an inherent into_iter method
|
||||||
|
// that we don't want to call.
|
||||||
|
let sugg = format!(
|
||||||
|
"
|
||||||
|
impl {self_ty_without_ref} {{
|
||||||
|
fn {expected_method_name}({ref_self}self) -> {iter_ty} {{
|
||||||
|
<{ref_self}Self as IntoIterator>::into_iter(self)
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
",
|
||||||
|
self_ty_without_ref = snippet(cx, self_ty_without_ref.ty.span, ".."),
|
||||||
|
ref_self = mtbl.ref_prefix_str(),
|
||||||
|
iter_ty = snippet(cx, iter_assoc_span, ".."),
|
||||||
|
);
|
||||||
|
|
||||||
|
diag.span_suggestion_verbose(
|
||||||
|
item.span.shrink_to_lo(),
|
||||||
|
format!("consider implementing `{expected_method_name}`"),
|
||||||
|
sugg,
|
||||||
|
// Just like iter_without_into_iter, this suggestion is on a best effort basis
|
||||||
|
// and requires potentially adding lifetimes or moving them around.
|
||||||
|
Applicability::Unspecified
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
|
||||||
|
let item_did = item.owner_id.to_def_id();
|
||||||
|
let (borrow_prefix, expected_implicit_self) = match item.ident.name {
|
||||||
|
sym::iter => ("&", ImplicitSelfKind::ImmRef),
|
||||||
|
sym::iter_mut => ("&mut ", ImplicitSelfKind::MutRef),
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let ImplItemKind::Fn(sig, _) = item.kind
|
||||||
|
&& let FnRetTy::Return(ret) = sig.decl.output
|
||||||
|
&& is_nameable_in_impl_trait(ret)
|
||||||
|
&& cx.tcx.generics_of(item_did).params.is_empty()
|
||||||
|
&& sig.decl.implicit_self == expected_implicit_self
|
||||||
|
&& sig.decl.inputs.len() == 1
|
||||||
|
&& let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id())
|
||||||
|
&& imp.of_trait.is_none()
|
||||||
|
&& let sig = cx.tcx.liberate_late_bound_regions(
|
||||||
|
item_did,
|
||||||
|
cx.tcx.fn_sig(item_did).instantiate_identity()
|
||||||
|
)
|
||||||
|
&& let ref_ty = sig.inputs()[0]
|
||||||
|
&& let Some(into_iter_did) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
|
||||||
|
&& let Some(iterator_did) = cx.tcx.get_diagnostic_item(sym::Iterator)
|
||||||
|
&& let ret_ty = sig.output()
|
||||||
|
// Order is important here, we need to check that the `fn iter` return type actually implements `IntoIterator`
|
||||||
|
// *before* normalizing `<_ as IntoIterator>::Item` (otherwise make_normalized_projection ICEs)
|
||||||
|
&& implements_trait(cx, ret_ty, iterator_did, &[])
|
||||||
|
&& let Some(iter_ty) = make_normalized_projection(
|
||||||
|
cx.tcx,
|
||||||
|
cx.param_env,
|
||||||
|
iterator_did,
|
||||||
|
sym!(Item),
|
||||||
|
[ret_ty],
|
||||||
|
)
|
||||||
|
// Only lint if the `IntoIterator` impl doesn't actually exist
|
||||||
|
&& !implements_trait(cx, ref_ty, into_iter_did, &[])
|
||||||
|
{
|
||||||
|
let self_ty_snippet = format!("{borrow_prefix}{}", snippet(cx, imp.self_ty.span, ".."));
|
||||||
|
|
||||||
|
span_lint_and_then(
|
||||||
|
cx,
|
||||||
|
ITER_WITHOUT_INTO_ITER,
|
||||||
|
item.span,
|
||||||
|
&format!("`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`", item.ident),
|
||||||
|
|diag| {
|
||||||
|
// Get the lower span of the `impl` block, and insert the suggestion right before it:
|
||||||
|
// impl X {
|
||||||
|
// ^ fn iter(&self) -> impl IntoIterator { ... }
|
||||||
|
// }
|
||||||
|
let span_behind_impl = cx.tcx
|
||||||
|
.def_span(cx.tcx.hir().parent_id(item.hir_id()).owner.def_id)
|
||||||
|
.shrink_to_lo();
|
||||||
|
|
||||||
|
let sugg = format!(
|
||||||
|
"
|
||||||
|
impl IntoIterator for {self_ty_snippet} {{
|
||||||
|
type IntoIter = {ret_ty};
|
||||||
|
type Iter = {iter_ty};
|
||||||
|
fn into_iter() -> Self::IntoIter {{
|
||||||
|
self.iter()
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
"
|
||||||
|
);
|
||||||
|
diag.span_suggestion_verbose(
|
||||||
|
span_behind_impl,
|
||||||
|
format!("consider implementing `IntoIterator` for `{self_ty_snippet}`"),
|
||||||
|
sugg,
|
||||||
|
// Suggestion is on a best effort basis, might need some adjustments by the user
|
||||||
|
// such as adding some lifetimes in the associated types, or importing types.
|
||||||
|
Applicability::Unspecified,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -169,6 +169,7 @@ mod invalid_upcast_comparisons;
|
||||||
mod items_after_statements;
|
mod items_after_statements;
|
||||||
mod items_after_test_module;
|
mod items_after_test_module;
|
||||||
mod iter_not_returning_iterator;
|
mod iter_not_returning_iterator;
|
||||||
|
mod iter_without_into_iter;
|
||||||
mod large_const_arrays;
|
mod large_const_arrays;
|
||||||
mod large_enum_variant;
|
mod large_enum_variant;
|
||||||
mod large_futures;
|
mod large_futures;
|
||||||
|
@ -190,6 +191,7 @@ mod manual_async_fn;
|
||||||
mod manual_bits;
|
mod manual_bits;
|
||||||
mod manual_clamp;
|
mod manual_clamp;
|
||||||
mod manual_float_methods;
|
mod manual_float_methods;
|
||||||
|
mod manual_hash_one;
|
||||||
mod manual_is_ascii_check;
|
mod manual_is_ascii_check;
|
||||||
mod manual_let_else;
|
mod manual_let_else;
|
||||||
mod manual_main_separator_str;
|
mod manual_main_separator_str;
|
||||||
|
@ -1119,6 +1121,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
msrv(),
|
msrv(),
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
|
store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv())));
|
||||||
|
store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter));
|
||||||
// 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`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,8 @@ struct PathAndSpan {
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `MacroRefData` includes the name of the macro.
|
/// `MacroRefData` includes the name of the macro
|
||||||
|
/// and the path from `SourceMap::span_to_filename`.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MacroRefData {
|
pub struct MacroRefData {
|
||||||
name: String,
|
name: String,
|
||||||
|
|
|
@ -26,7 +26,7 @@ declare_clippy_lint! {
|
||||||
/// # let x = 1.0f32;
|
/// # let x = 1.0f32;
|
||||||
/// if x.is_infinite() {}
|
/// if x.is_infinite() {}
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub MANUAL_IS_INFINITE,
|
pub MANUAL_IS_INFINITE,
|
||||||
style,
|
style,
|
||||||
"use dedicated method to check if a float is infinite"
|
"use dedicated method to check if a float is infinite"
|
||||||
|
@ -51,7 +51,7 @@ declare_clippy_lint! {
|
||||||
/// if x.is_finite() {}
|
/// if x.is_finite() {}
|
||||||
/// if x.is_finite() {}
|
/// if x.is_finite() {}
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub MANUAL_IS_FINITE,
|
pub MANUAL_IS_FINITE,
|
||||||
style,
|
style,
|
||||||
"use dedicated method to check if a float is finite"
|
"use dedicated method to check if a float is finite"
|
||||||
|
|
133
clippy_lints/src/manual_hash_one.rs
Normal file
133
clippy_lints/src/manual_hash_one.rs
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
|
use clippy_utils::source::snippet_opt;
|
||||||
|
use clippy_utils::visitors::{is_local_used, local_used_once};
|
||||||
|
use clippy_utils::{is_trait_method, path_to_local_id};
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind};
|
||||||
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
|
use rustc_span::sym;
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for cases where [`BuildHasher::hash_one`] can be used.
|
||||||
|
///
|
||||||
|
/// [`BuildHasher::hash_one`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html#method.hash_one
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// It is more concise to use the `hash_one` method.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```rust
|
||||||
|
/// use std::hash::{BuildHasher, Hash, Hasher};
|
||||||
|
/// use std::collections::hash_map::RandomState;
|
||||||
|
///
|
||||||
|
/// let s = RandomState::new();
|
||||||
|
/// let value = vec![1, 2, 3];
|
||||||
|
///
|
||||||
|
/// let mut hasher = s.build_hasher();
|
||||||
|
/// value.hash(&mut hasher);
|
||||||
|
/// let hash = hasher.finish();
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust
|
||||||
|
/// use std::hash::BuildHasher;
|
||||||
|
/// use std::collections::hash_map::RandomState;
|
||||||
|
///
|
||||||
|
/// let s = RandomState::new();
|
||||||
|
/// let value = vec![1, 2, 3];
|
||||||
|
///
|
||||||
|
/// let hash = s.hash_one(&value);
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.74.0"]
|
||||||
|
pub MANUAL_HASH_ONE,
|
||||||
|
complexity,
|
||||||
|
"manual implementations of `BuildHasher::hash_one`"
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ManualHashOne {
|
||||||
|
msrv: Msrv,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ManualHashOne {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(msrv: Msrv) -> Self {
|
||||||
|
Self { msrv }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_lint_pass!(ManualHashOne => [MANUAL_HASH_ONE]);
|
||||||
|
|
||||||
|
impl LateLintPass<'_> for ManualHashOne {
|
||||||
|
fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
|
||||||
|
// `let mut hasher = seg.build_hasher();`
|
||||||
|
if let PatKind::Binding(BindingAnnotation::MUT, hasher, _, None) = local.pat.kind
|
||||||
|
&& let Some(init) = local.init
|
||||||
|
&& !init.span.from_expansion()
|
||||||
|
&& let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind
|
||||||
|
&& seg.ident.name == sym!(build_hasher)
|
||||||
|
|
||||||
|
&& let Node::Stmt(local_stmt) = cx.tcx.hir().get_parent(local.hir_id)
|
||||||
|
&& let Node::Block(block) = cx.tcx.hir().get_parent(local_stmt.hir_id)
|
||||||
|
|
||||||
|
&& let mut stmts = block.stmts.iter()
|
||||||
|
.skip_while(|stmt| stmt.hir_id != local_stmt.hir_id)
|
||||||
|
.skip(1)
|
||||||
|
.filter(|&stmt| is_local_used(cx, stmt, hasher))
|
||||||
|
|
||||||
|
// `hashed_value.hash(&mut hasher);`
|
||||||
|
&& let Some(hash_stmt) = stmts.next()
|
||||||
|
&& let StmtKind::Semi(hash_expr) = hash_stmt.kind
|
||||||
|
&& !hash_expr.span.from_expansion()
|
||||||
|
&& let ExprKind::MethodCall(seg, hashed_value, [ref_to_hasher], _) = hash_expr.kind
|
||||||
|
&& seg.ident.name == sym::hash
|
||||||
|
&& is_trait_method(cx, hash_expr, sym::Hash)
|
||||||
|
&& path_to_local_id(ref_to_hasher.peel_borrows(), hasher)
|
||||||
|
|
||||||
|
&& let maybe_finish_stmt = stmts.next()
|
||||||
|
// There should be no more statements referencing `hasher`
|
||||||
|
&& stmts.next().is_none()
|
||||||
|
|
||||||
|
// `hasher.finish()`, may be anywhere in a statement or the trailing expr of the block
|
||||||
|
&& let Some(path_expr) = local_used_once(cx, (maybe_finish_stmt, block.expr), hasher)
|
||||||
|
&& let Node::Expr(finish_expr) = cx.tcx.hir().get_parent(path_expr.hir_id)
|
||||||
|
&& !finish_expr.span.from_expansion()
|
||||||
|
&& let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind
|
||||||
|
&& seg.ident.name == sym!(finish)
|
||||||
|
|
||||||
|
&& self.msrv.meets(msrvs::BUILD_HASHER_HASH_ONE)
|
||||||
|
{
|
||||||
|
span_lint_hir_and_then(
|
||||||
|
cx,
|
||||||
|
MANUAL_HASH_ONE,
|
||||||
|
finish_expr.hir_id,
|
||||||
|
finish_expr.span,
|
||||||
|
"manual implementation of `BuildHasher::hash_one`",
|
||||||
|
|diag| {
|
||||||
|
if let Some(build_hasher) = snippet_opt(cx, build_hasher.span)
|
||||||
|
&& let Some(hashed_value) = snippet_opt(cx, hashed_value.span)
|
||||||
|
{
|
||||||
|
diag.multipart_suggestion(
|
||||||
|
"try",
|
||||||
|
vec![
|
||||||
|
(local_stmt.span, String::new()),
|
||||||
|
(hash_stmt.span, String::new()),
|
||||||
|
(
|
||||||
|
finish_expr.span,
|
||||||
|
// `needless_borrows_for_generic_args` will take care of
|
||||||
|
// removing the `&` when it isn't needed
|
||||||
|
format!("{build_hasher}.hash_one(&{hashed_value})")
|
||||||
|
)
|
||||||
|
],
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_msrv_attr!(LateContext);
|
||||||
|
}
|
|
@ -136,9 +136,9 @@ fn emit_manual_let_else(
|
||||||
// for this to be machine applicable.
|
// for this to be machine applicable.
|
||||||
let mut app = Applicability::HasPlaceholders;
|
let mut app = Applicability::HasPlaceholders;
|
||||||
let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app);
|
let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app);
|
||||||
let (sn_else, _) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app);
|
let (sn_else, else_is_mac_call) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app);
|
||||||
|
|
||||||
let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) {
|
let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) && !else_is_mac_call {
|
||||||
sn_else.into_owned()
|
sn_else.into_owned()
|
||||||
} else {
|
} else {
|
||||||
format!("{{ {sn_else} }}")
|
format!("{{ {sn_else} }}")
|
||||||
|
|
|
@ -3,6 +3,7 @@ use clippy_utils::is_doc_hidden;
|
||||||
use clippy_utils::msrvs::{self, Msrv};
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_opt;
|
use clippy_utils::source::snippet_opt;
|
||||||
use rustc_ast::ast::{self, VisibilityKind};
|
use rustc_ast::ast::{self, VisibilityKind};
|
||||||
|
use rustc_ast::attr;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||||
|
@ -158,7 +159,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
|
||||||
let mut iter = def.variants.iter().filter_map(|v| {
|
let mut iter = def.variants.iter().filter_map(|v| {
|
||||||
(matches!(v.data, hir::VariantData::Unit(_, _))
|
(matches!(v.data, hir::VariantData::Unit(_, _))
|
||||||
&& v.ident.as_str().starts_with('_')
|
&& v.ident.as_str().starts_with('_')
|
||||||
&& is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)))
|
&& is_doc_hidden(cx.tcx.hir().attrs(v.hir_id))
|
||||||
|
&& !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive))
|
||||||
.then_some((v.def_id, v.span))
|
.then_some((v.def_id, v.span))
|
||||||
});
|
});
|
||||||
if let Some((id, span)) = iter.next()
|
if let Some((id, span)) = iter.next()
|
||||||
|
@ -198,16 +200,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
|
||||||
enum_span,
|
enum_span,
|
||||||
"this seems like a manual implementation of the non-exhaustive pattern",
|
"this seems like a manual implementation of the non-exhaustive pattern",
|
||||||
|diag| {
|
|diag| {
|
||||||
if !cx.tcx.adt_def(enum_id).is_variant_list_non_exhaustive()
|
let header_span = cx.sess().source_map().span_until_char(enum_span, '{');
|
||||||
&& let header_span = cx.sess().source_map().span_until_char(enum_span, '{')
|
if let Some(snippet) = snippet_opt(cx, header_span) {
|
||||||
&& let Some(snippet) = snippet_opt(cx, header_span)
|
diag.span_suggestion(
|
||||||
{
|
header_span,
|
||||||
diag.span_suggestion(
|
"add the attribute",
|
||||||
header_span,
|
format!("#[non_exhaustive] {snippet}"),
|
||||||
"add the attribute",
|
Applicability::Unspecified,
|
||||||
format!("#[non_exhaustive] {snippet}"),
|
);
|
||||||
Applicability::Unspecified,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
diag.span_help(variant_span, "remove this variant");
|
diag.span_help(variant_span, "remove this variant");
|
||||||
},
|
},
|
||||||
|
|
|
@ -961,7 +961,7 @@ declare_clippy_lint! {
|
||||||
/// _ => todo!(),
|
/// _ => todo!(),
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub REDUNDANT_GUARDS,
|
pub REDUNDANT_GUARDS,
|
||||||
complexity,
|
complexity,
|
||||||
"checks for unnecessary guards in match expressions"
|
"checks for unnecessary guards in match expressions"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
|
use clippy_utils::consts::{constant, constant_full_int, mir_to_const, FullInt};
|
||||||
use clippy_utils::diagnostics::span_lint_and_note;
|
use clippy_utils::diagnostics::span_lint_and_note;
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use rustc_hir::{Arm, Expr, PatKind, RangeEnd};
|
use rustc_hir::{Arm, Expr, PatKind, RangeEnd};
|
||||||
|
@ -37,14 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
|
||||||
Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
|
Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
|
||||||
None => {
|
None => {
|
||||||
let min_val_const = ty.numeric_min_val(cx.tcx)?;
|
let min_val_const = ty.numeric_min_val(cx.tcx)?;
|
||||||
miri_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))?
|
mir_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))?
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let rhs_const = match rhs {
|
let rhs_const = match rhs {
|
||||||
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
|
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
|
||||||
None => {
|
None => {
|
||||||
let max_val_const = ty.numeric_max_val(cx.tcx)?;
|
let max_val_const = ty.numeric_max_val(cx.tcx)?;
|
||||||
miri_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))?
|
mir_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))?
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let lhs_val = lhs_const.int_value(cx, ty)?;
|
let lhs_val = lhs_const.int_value(cx, ty)?;
|
||||||
|
|
|
@ -2970,7 +2970,7 @@ declare_clippy_lint! {
|
||||||
/// assert_eq!((*any_box).type_id(), TypeId::of::<i32>());
|
/// assert_eq!((*any_box).type_id(), TypeId::of::<i32>());
|
||||||
/// // ^ dereference first, to call `type_id` on `dyn Any`
|
/// // ^ dereference first, to call `type_id` on `dyn Any`
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub TYPE_ID_ON_BOX,
|
pub TYPE_ID_ON_BOX,
|
||||||
suspicious,
|
suspicious,
|
||||||
"calling `.type_id()` on `Box<dyn Any>`"
|
"calling `.type_id()` on `Box<dyn Any>`"
|
||||||
|
@ -3368,6 +3368,7 @@ declare_clippy_lint! {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
/// Looks for calls to [`Stdin::read_line`] to read a line from the standard input
|
/// Looks for calls to [`Stdin::read_line`] to read a line from the standard input
|
||||||
/// into a string, then later attempting to parse this string into a type without first trimming it, which will
|
/// into a string, then later attempting to parse this string into a type without first trimming it, which will
|
||||||
/// always fail because the string has a trailing newline in it.
|
/// always fail because the string has a trailing newline in it.
|
||||||
|
@ -3390,7 +3391,7 @@ declare_clippy_lint! {
|
||||||
/// // ^^^^^^^^^^^ remove the trailing newline
|
/// // ^^^^^^^^^^^ remove the trailing newline
|
||||||
/// assert_eq!(num, 42);
|
/// assert_eq!(num, 42);
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub READ_LINE_WITHOUT_TRIM,
|
pub READ_LINE_WITHOUT_TRIM,
|
||||||
correctness,
|
correctness,
|
||||||
"calling `Stdin::read_line`, then trying to parse it without first trimming"
|
"calling `Stdin::read_line`, then trying to parse it without first trimming"
|
||||||
|
@ -3418,7 +3419,7 @@ declare_clippy_lint! {
|
||||||
/// # let c = 'c';
|
/// # let c = 'c';
|
||||||
/// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
|
/// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub STRING_LIT_CHARS_ANY,
|
pub STRING_LIT_CHARS_ANY,
|
||||||
restriction,
|
restriction,
|
||||||
"checks for `<string_lit>.chars().any(|i| i == c)`"
|
"checks for `<string_lit>.chars().any(|i| i == c)`"
|
||||||
|
@ -3453,7 +3454,7 @@ declare_clippy_lint! {
|
||||||
/// })
|
/// })
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub FORMAT_COLLECT,
|
pub FORMAT_COLLECT,
|
||||||
perf,
|
perf,
|
||||||
"`format!`ing every element in a collection, then collecting the strings into a new `String`"
|
"`format!`ing every element in a collection, then collecting the strings into a new `String`"
|
||||||
|
@ -3474,7 +3475,7 @@ declare_clippy_lint! {
|
||||||
/// let y = v.iter().collect::<Vec<_>>();
|
/// let y = v.iter().collect::<Vec<_>>();
|
||||||
/// assert_eq!(x, y);
|
/// assert_eq!(x, y);
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub ITER_SKIP_ZERO,
|
pub ITER_SKIP_ZERO,
|
||||||
correctness,
|
correctness,
|
||||||
"disallows `.skip(0)`"
|
"disallows `.skip(0)`"
|
||||||
|
@ -3505,7 +3506,7 @@ declare_clippy_lint! {
|
||||||
/// # let v = vec![];
|
/// # let v = vec![];
|
||||||
/// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i));
|
/// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i));
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub FILTER_MAP_BOOL_THEN,
|
pub FILTER_MAP_BOOL_THEN,
|
||||||
style,
|
style,
|
||||||
"checks for usage of `bool::then` in `Iterator::filter_map`"
|
"checks for usage of `bool::then` in `Iterator::filter_map`"
|
||||||
|
|
|
@ -24,7 +24,6 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(clippy::too_many_lines)]
|
|
||||||
pub(super) fn check(
|
pub(super) fn check(
|
||||||
cx: &LateContext<'_>,
|
cx: &LateContext<'_>,
|
||||||
expr: &hir::Expr<'_>,
|
expr: &hir::Expr<'_>,
|
||||||
|
@ -101,11 +100,11 @@ pub(super) fn check(
|
||||||
(expr.span.with_lo(args[0].span.hi()), String::new()),
|
(expr.span.with_lo(args[0].span.hi()), String::new()),
|
||||||
]),
|
]),
|
||||||
("None", "unwrap_or_else", _) => match args[0].kind {
|
("None", "unwrap_or_else", _) => match args[0].kind {
|
||||||
hir::ExprKind::Closure(hir::Closure {
|
hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![
|
||||||
body,
|
(
|
||||||
..
|
expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()),
|
||||||
}) => Some(vec![
|
String::new(),
|
||||||
(expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()), String::new()),
|
),
|
||||||
(expr.span.with_lo(args[0].span.hi()), String::new()),
|
(expr.span.with_lo(args[0].span.hi()), String::new()),
|
||||||
]),
|
]),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
@ -6,7 +6,8 @@ use if_chain::if_chain;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
|
use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::ty::{self, GenericArgKind};
|
use rustc_middle::ty;
|
||||||
|
use rustc_middle::ty::GenericArgKind;
|
||||||
use rustc_span::sym;
|
use rustc_span::sym;
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
|
@ -15,6 +15,10 @@ declare_clippy_lint! {
|
||||||
/// A good custom message should be more about why the failure of the assertion is problematic
|
/// A good custom message should be more about why the failure of the assertion is problematic
|
||||||
/// and not what is failed because the assertion already conveys that.
|
/// and not what is failed because the assertion already conveys that.
|
||||||
///
|
///
|
||||||
|
/// Although the same reasoning applies to testing functions, this lint ignores them as they would be too noisy.
|
||||||
|
/// Also, in most cases understanding the test failure would be easier
|
||||||
|
/// compared to understanding a complex invariant distributed around the codebase.
|
||||||
|
///
|
||||||
/// ### Known problems
|
/// ### Known problems
|
||||||
/// This lint cannot check the quality of the custom panic messages.
|
/// This lint cannot check the quality of the custom panic messages.
|
||||||
/// Hence, you can suppress this lint simply by adding placeholder messages
|
/// Hence, you can suppress this lint simply by adding placeholder messages
|
||||||
|
|
|
@ -135,10 +135,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stmt_might_diverge(stmt: &Stmt<'_>) -> bool {
|
fn stmt_might_diverge(stmt: &Stmt<'_>) -> bool {
|
||||||
match stmt.kind {
|
!matches!(stmt.kind, StmtKind::Item(..))
|
||||||
StmtKind::Item(..) => false,
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
|
||||||
|
@ -148,7 +145,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
|
||||||
ExprKind::Block(block, ..) => match (block.stmts, block.expr) {
|
ExprKind::Block(block, ..) => match (block.stmts, block.expr) {
|
||||||
(stmts, Some(e)) => {
|
(stmts, Some(e)) => {
|
||||||
if stmts.iter().all(|stmt| !stmt_might_diverge(stmt)) {
|
if stmts.iter().all(|stmt| !stmt_might_diverge(stmt)) {
|
||||||
self.visit_expr(e)
|
self.visit_expr(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
([first @ .., stmt], None) => {
|
([first @ .., stmt], None) => {
|
||||||
|
|
|
@ -96,10 +96,6 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
|
||||||
self.found = true;
|
self.found = true;
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
ExprKind::If(..) => {
|
|
||||||
self.found = true;
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
ExprKind::Path(_) => {
|
ExprKind::Path(_) => {
|
||||||
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
|
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
|
||||||
if adj
|
if adj
|
||||||
|
|
|
@ -47,9 +47,9 @@ declare_clippy_lint! {
|
||||||
/// 12 + *y
|
/// 12 + *y
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub NEEDLESS_PASS_BY_REF_MUT,
|
pub NEEDLESS_PASS_BY_REF_MUT,
|
||||||
suspicious,
|
nursery,
|
||||||
"using a `&mut` argument when it's not mutated"
|
"using a `&mut` argument when it's not mutated"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ declare_clippy_lint! {
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub NON_CANONICAL_PARTIAL_ORD_IMPL,
|
pub NON_CANONICAL_PARTIAL_ORD_IMPL,
|
||||||
suspicious,
|
suspicious,
|
||||||
"non-canonical implementation of `PartialOrd` on an `Ord` type"
|
"non-canonical implementation of `PartialOrd` on an `Ord` type"
|
||||||
|
|
|
@ -312,7 +312,7 @@ declare_clippy_lint! {
|
||||||
/// # let status_code = 200;
|
/// # let status_code = 200;
|
||||||
/// if status_code <= 400 && status_code > 500 {}
|
/// if status_code <= 400 && status_code > 500 {}
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.71.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub IMPOSSIBLE_COMPARISONS,
|
pub IMPOSSIBLE_COMPARISONS,
|
||||||
correctness,
|
correctness,
|
||||||
"double comparisons that will never evaluate to `true`"
|
"double comparisons that will never evaluate to `true`"
|
||||||
|
@ -332,7 +332,7 @@ declare_clippy_lint! {
|
||||||
/// # let status_code = 200;
|
/// # let status_code = 200;
|
||||||
/// if status_code <= 400 && status_code < 500 {}
|
/// if status_code <= 400 && status_code < 500 {}
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.71.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub REDUNDANT_COMPARISONS,
|
pub REDUNDANT_COMPARISONS,
|
||||||
correctness,
|
correctness,
|
||||||
"double comparisons where one of them can be removed"
|
"double comparisons where one of them can be removed"
|
||||||
|
|
|
@ -75,6 +75,7 @@ impl EarlyLintPass for RawStrings {
|
||||||
if !snippet(cx, expr.span, prefix).trim().starts_with(prefix) {
|
if !snippet(cx, expr.span, prefix).trim().starts_with(prefix) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let descr = lit.kind.descr();
|
||||||
|
|
||||||
if !str.contains(['\\', '"']) {
|
if !str.contains(['\\', '"']) {
|
||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
|
@ -89,20 +90,17 @@ impl EarlyLintPass for RawStrings {
|
||||||
let r_pos = expr.span.lo() + BytePos::from_usize(prefix.len() - 1);
|
let r_pos = expr.span.lo() + BytePos::from_usize(prefix.len() - 1);
|
||||||
let start = start.with_lo(r_pos);
|
let start = start.with_lo(r_pos);
|
||||||
|
|
||||||
if end.is_empty() {
|
let mut remove = vec![(start, String::new())];
|
||||||
diag.span_suggestion(
|
// avoid debug ICE from empty suggestions
|
||||||
start,
|
if !end.is_empty() {
|
||||||
"use a string literal instead",
|
remove.push((end, String::new()));
|
||||||
format!("\"{str}\""),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
diag.multipart_suggestion(
|
|
||||||
"try",
|
|
||||||
vec![(start, String::new()), (end, String::new())],
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diag.multipart_suggestion_verbose(
|
||||||
|
format!("use a plain {descr} literal instead"),
|
||||||
|
remove,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if !matches!(cx.get_lint_level(NEEDLESS_RAW_STRINGS), rustc_lint::Allow) {
|
if !matches!(cx.get_lint_level(NEEDLESS_RAW_STRINGS), rustc_lint::Allow) {
|
||||||
|
@ -149,9 +147,9 @@ impl EarlyLintPass for RawStrings {
|
||||||
let (start, end) = hash_spans(expr.span, prefix, req, max);
|
let (start, end) = hash_spans(expr.span, prefix, req, max);
|
||||||
|
|
||||||
let message = match max - req {
|
let message = match max - req {
|
||||||
_ if req == 0 => "remove all the hashes around the literal".to_string(),
|
_ if req == 0 => format!("remove all the hashes around the {descr} literal"),
|
||||||
1 => "remove one hash from both sides of the literal".to_string(),
|
1 => format!("remove one hash from both sides of the {descr} literal"),
|
||||||
n => format!("remove {n} hashes from both sides of the literal"),
|
n => format!("remove {n} hashes from both sides of the {descr} literal"),
|
||||||
};
|
};
|
||||||
|
|
||||||
diag.multipart_suggestion(
|
diag.multipart_suggestion(
|
||||||
|
|
|
@ -3,11 +3,9 @@ use clippy_utils::is_from_proc_macro;
|
||||||
use clippy_utils::ty::needs_ordered_drop;
|
use clippy_utils::ty::needs_ordered_drop;
|
||||||
use rustc_ast::Mutability;
|
use rustc_ast::Mutability;
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
use rustc_hir::{
|
use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath};
|
||||||
BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath,
|
|
||||||
};
|
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_middle::lint::{in_external_macro, is_from_async_await};
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::DesugaringKind;
|
use rustc_span::DesugaringKind;
|
||||||
|
@ -39,7 +37,7 @@ declare_clippy_lint! {
|
||||||
/// // no redefinition with the same name
|
/// // no redefinition with the same name
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.73.0"]
|
||||||
pub REDUNDANT_LOCALS,
|
pub REDUNDANT_LOCALS,
|
||||||
correctness,
|
correctness,
|
||||||
"redundant redefinition of a local binding"
|
"redundant redefinition of a local binding"
|
||||||
|
@ -68,21 +66,18 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
|
||||||
// the local does not change the effect of assignments to the binding. see #11290
|
// the local does not change the effect of assignments to the binding. see #11290
|
||||||
if !affects_assignments(cx, mutability, binding_id, local.hir_id);
|
if !affects_assignments(cx, mutability, binding_id, local.hir_id);
|
||||||
// the local does not affect the code's drop behavior
|
// the local does not affect the code's drop behavior
|
||||||
if !affects_drop_behavior(cx, binding_id, local.hir_id, expr);
|
if !needs_ordered_drop(cx, cx.typeck_results().expr_ty(expr));
|
||||||
// the local is user-controlled
|
// the local is user-controlled
|
||||||
if !in_external_macro(cx.sess(), local.span);
|
if !in_external_macro(cx.sess(), local.span);
|
||||||
if !is_from_proc_macro(cx, expr);
|
if !is_from_proc_macro(cx, expr);
|
||||||
// Async function parameters are lowered into the closure body, so we can't lint them.
|
|
||||||
// see `lower_maybe_async_body` in `rust_ast_lowering`
|
|
||||||
if !is_from_async_await(local.span);
|
|
||||||
then {
|
then {
|
||||||
span_lint_and_help(
|
span_lint_and_help(
|
||||||
cx,
|
cx,
|
||||||
REDUNDANT_LOCALS,
|
REDUNDANT_LOCALS,
|
||||||
vec![binding_pat.span, local.span],
|
local.span,
|
||||||
"redundant redefinition of a binding",
|
&format!("redundant redefinition of a binding `{ident}`"),
|
||||||
None,
|
Some(binding_pat.span),
|
||||||
&format!("remove the redefinition of `{ident}`"),
|
&format!("`{ident}` is initially defined here"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,18 +104,3 @@ fn affects_assignments(cx: &LateContext<'_>, mutability: Mutability, bind: HirId
|
||||||
// the binding is mutable and the rebinding is in a different scope than the original binding
|
// the binding is mutable and the rebinding is in a different scope than the original binding
|
||||||
mutability == Mutability::Mut && hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
|
mutability == Mutability::Mut && hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a rebinding of a local affects the code's drop behavior.
|
|
||||||
fn affects_drop_behavior<'tcx>(
|
|
||||||
cx: &LateContext<'tcx>,
|
|
||||||
bind: HirId,
|
|
||||||
rebind: HirId,
|
|
||||||
rebind_expr: &Expr<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
let hir = cx.tcx.hir();
|
|
||||||
|
|
||||||
// the rebinding is in a different scope than the original binding
|
|
||||||
// and the type of the binding cares about drop order
|
|
||||||
hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
|
|
||||||
&& needs_ordered_drop(cx, cx.typeck_results().expr_ty(rebind_expr))
|
|
||||||
}
|
|
||||||
|
|
|
@ -55,11 +55,11 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
|
||||||
if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl { .. })
|
if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl { .. })
|
||||||
&& let item = cx.tcx.hir().item(id)
|
&& let item = cx.tcx.hir().item(id)
|
||||||
&& let ItemKind::Impl(Impl {
|
&& let ItemKind::Impl(Impl {
|
||||||
items,
|
items,
|
||||||
of_trait,
|
of_trait,
|
||||||
self_ty,
|
self_ty,
|
||||||
..
|
..
|
||||||
}) = &item.kind
|
}) = &item.kind
|
||||||
&& let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
|
&& let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
|
||||||
{
|
{
|
||||||
if !map.contains_key(res) {
|
if !map.contains_key(res) {
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::is_from_proc_macro;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{HirId, Path, PathSegment};
|
use rustc_hir::{HirId, Path, PathSegment};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::symbol::kw;
|
use rustc_span::symbol::kw;
|
||||||
use rustc_span::{sym, Span};
|
use rustc_span::{sym, Span};
|
||||||
|
@ -99,6 +101,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
|
||||||
if let Res::Def(_, def_id) = path.res
|
if let Res::Def(_, def_id) = path.res
|
||||||
&& let Some(first_segment) = get_first_segment(path)
|
&& let Some(first_segment) = get_first_segment(path)
|
||||||
&& is_stable(cx, def_id)
|
&& is_stable(cx, def_id)
|
||||||
|
&& !in_external_macro(cx.sess(), path.span)
|
||||||
|
&& !is_from_proc_macro(cx, &first_segment.ident)
|
||||||
{
|
{
|
||||||
let (lint, used_mod, replace_with) = match first_segment.ident.name {
|
let (lint, used_mod, replace_with) = match first_segment.ident.name {
|
||||||
sym::std => match cx.tcx.crate_name(def_id.krate) {
|
sym::std => match cx.tcx.crate_name(def_id.krate) {
|
||||||
|
|
|
@ -294,7 +294,7 @@ define_Conf! {
|
||||||
///
|
///
|
||||||
/// Suppress lints whenever the suggested change would cause breakage for other crates.
|
/// Suppress lints whenever the suggested change would cause breakage for other crates.
|
||||||
(avoid_breaking_exported_api: bool = true),
|
(avoid_breaking_exported_api: bool = true),
|
||||||
/// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD.
|
/// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE.
|
||||||
///
|
///
|
||||||
/// The minimum rust version that the project supports
|
/// The minimum rust version that the project supports
|
||||||
(msrv: Option<String> = None),
|
(msrv: Option<String> = None),
|
||||||
|
@ -744,3 +744,44 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec<usize>) {
|
||||||
|
|
||||||
(rows, column_widths)
|
(rows, column_widths)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
|
use serde::de::IgnoredAny;
|
||||||
|
use std::fs;
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn configs_are_tested() {
|
||||||
|
let mut names: FxHashSet<String> = super::metadata::get_configuration_metadata()
|
||||||
|
.into_iter()
|
||||||
|
.map(|meta| meta.name.replace('_', "-"))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let toml_files = WalkDir::new("../tests")
|
||||||
|
.into_iter()
|
||||||
|
.map(Result::unwrap)
|
||||||
|
.filter(|entry| entry.file_name() == "clippy.toml");
|
||||||
|
|
||||||
|
for entry in toml_files {
|
||||||
|
let file = fs::read_to_string(entry.path()).unwrap();
|
||||||
|
#[allow(clippy::zero_sized_map_values)]
|
||||||
|
if let Ok(map) = toml::from_str::<FxHashMap<String, IgnoredAny>>(&file) {
|
||||||
|
for name in map.keys() {
|
||||||
|
names.remove(name.as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
names.remove("allow-one-hash-in-raw-strings"),
|
||||||
|
"remove this when #11481 is fixed"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
names.is_empty(),
|
||||||
|
"Configuration variable lacks test: {names:?}\nAdd a test to `tests/ui-toml`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -132,6 +132,7 @@ impl LateLintPass<'_> for WildcardImports {
|
||||||
if self.warn_on_all || !self.check_exceptions(item, use_path.segments);
|
if self.warn_on_all || !self.check_exceptions(item, use_path.segments);
|
||||||
let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id);
|
let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id);
|
||||||
if !used_imports.is_empty(); // Already handled by `unused_imports`
|
if !used_imports.is_empty(); // Already handled by `unused_imports`
|
||||||
|
if !used_imports.contains(&kw::Underscore);
|
||||||
then {
|
then {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability);
|
let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability);
|
||||||
|
|
|
@ -3,12 +3,15 @@ use clippy_utils::macros::{find_format_args, format_arg_removal_span, root_macro
|
||||||
use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
|
use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
|
||||||
use clippy_utils::{is_in_cfg_test, is_in_test_function};
|
use clippy_utils::{is_in_cfg_test, is_in_test_function};
|
||||||
use rustc_ast::token::LitKind;
|
use rustc_ast::token::LitKind;
|
||||||
use rustc_ast::{FormatArgPosition, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, FormatTrait};
|
use rustc_ast::{
|
||||||
|
FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder,
|
||||||
|
FormatTrait,
|
||||||
|
};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Expr, Impl, Item, ItemKind};
|
use rustc_hir::{Expr, Impl, Item, ItemKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::{sym, BytePos};
|
use rustc_span::{sym, BytePos, Span};
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
|
@ -450,6 +453,12 @@ fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call
|
||||||
fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
|
fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
|
||||||
let arg_index = |argument: &FormatArgPosition| argument.index.unwrap_or_else(|pos| pos);
|
let arg_index = |argument: &FormatArgPosition| argument.index.unwrap_or_else(|pos| pos);
|
||||||
|
|
||||||
|
let lint_name = if name.starts_with("write") {
|
||||||
|
WRITE_LITERAL
|
||||||
|
} else {
|
||||||
|
PRINT_LITERAL
|
||||||
|
};
|
||||||
|
|
||||||
let mut counts = vec![0u32; format_args.arguments.all_args().len()];
|
let mut counts = vec![0u32; format_args.arguments.all_args().len()];
|
||||||
for piece in &format_args.template {
|
for piece in &format_args.template {
|
||||||
if let FormatArgsPiece::Placeholder(placeholder) = piece {
|
if let FormatArgsPiece::Placeholder(placeholder) = piece {
|
||||||
|
@ -457,6 +466,12 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut suggestion: Vec<(Span, String)> = vec![];
|
||||||
|
// holds index of replaced positional arguments; used to decrement the index of the remaining
|
||||||
|
// positional arguments.
|
||||||
|
let mut replaced_position: Vec<usize> = vec![];
|
||||||
|
let mut sug_span: Option<Span> = None;
|
||||||
|
|
||||||
for piece in &format_args.template {
|
for piece in &format_args.template {
|
||||||
if let FormatArgsPiece::Placeholder(FormatPlaceholder {
|
if let FormatArgsPiece::Placeholder(FormatPlaceholder {
|
||||||
argument,
|
argument,
|
||||||
|
@ -471,9 +486,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
|
||||||
&& let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind
|
&& let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind
|
||||||
&& !arg.expr.span.from_expansion()
|
&& !arg.expr.span.from_expansion()
|
||||||
&& let Some(value_string) = snippet_opt(cx, arg.expr.span)
|
&& let Some(value_string) = snippet_opt(cx, arg.expr.span)
|
||||||
{
|
{
|
||||||
let (replacement, replace_raw) = match lit.kind {
|
let (replacement, replace_raw) = match lit.kind {
|
||||||
LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) {
|
LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) {
|
||||||
Some(extracted) => extracted,
|
Some(extracted) => extracted,
|
||||||
None => return,
|
None => return,
|
||||||
},
|
},
|
||||||
|
@ -493,12 +508,6 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
let lint = if name.starts_with("write") {
|
|
||||||
WRITE_LITERAL
|
|
||||||
} else {
|
|
||||||
PRINT_LITERAL
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { continue };
|
let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { continue };
|
||||||
let format_string_is_raw = format_string_snippet.starts_with('r');
|
let format_string_is_raw = format_string_snippet.starts_with('r');
|
||||||
|
|
||||||
|
@ -519,29 +528,58 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
span_lint_and_then(
|
sug_span = Some(sug_span.unwrap_or(arg.expr.span).to(arg.expr.span));
|
||||||
cx,
|
|
||||||
lint,
|
|
||||||
arg.expr.span,
|
|
||||||
"literal with an empty format string",
|
|
||||||
|diag| {
|
|
||||||
if let Some(replacement) = replacement
|
|
||||||
// `format!("{}", "a")`, `format!("{named}", named = "b")
|
|
||||||
// ~~~~~ ~~~~~~~~~~~~~
|
|
||||||
&& let Some(removal_span) = format_arg_removal_span(format_args, index)
|
|
||||||
{
|
|
||||||
let replacement = replacement.replace('{', "{{").replace('}', "}}");
|
|
||||||
diag.multipart_suggestion(
|
|
||||||
"try",
|
|
||||||
vec![(*placeholder_span, replacement), (removal_span, String::new())],
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
|
if let Some((_, index)) = positional_arg_piece_span(piece) {
|
||||||
|
replaced_position.push(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(replacement) = replacement
|
||||||
|
// `format!("{}", "a")`, `format!("{named}", named = "b")
|
||||||
|
// ~~~~~ ~~~~~~~~~~~~~
|
||||||
|
&& let Some(removal_span) = format_arg_removal_span(format_args, index) {
|
||||||
|
let replacement = escape_braces(&replacement, !format_string_is_raw && !replace_raw);
|
||||||
|
suggestion.push((*placeholder_span, replacement));
|
||||||
|
suggestion.push((removal_span, String::new()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decrement the index of the remaining by the number of replaced positional arguments
|
||||||
|
if !suggestion.is_empty() {
|
||||||
|
for piece in &format_args.template {
|
||||||
|
if let Some((span, index)) = positional_arg_piece_span(piece)
|
||||||
|
&& suggestion.iter().all(|(s, _)| *s != span) {
|
||||||
|
let decrement = replaced_position.iter().filter(|i| **i < index).count();
|
||||||
|
suggestion.push((span, format!("{{{}}}", index.saturating_sub(decrement))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(span) = sug_span {
|
||||||
|
span_lint_and_then(cx, lint_name, span, "literal with an empty format string", |diag| {
|
||||||
|
if !suggestion.is_empty() {
|
||||||
|
diag.multipart_suggestion("try", suggestion, Applicability::MachineApplicable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract Span and its index from the given `piece`, iff it's positional argument.
|
||||||
|
fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> {
|
||||||
|
match piece {
|
||||||
|
FormatArgsPiece::Placeholder(FormatPlaceholder {
|
||||||
|
argument:
|
||||||
|
FormatArgPosition {
|
||||||
|
index: Ok(index),
|
||||||
|
kind: FormatArgPositionKind::Number,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
span: Some(span),
|
||||||
|
..
|
||||||
|
}) => Some((*span, *index)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw
|
/// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw
|
||||||
|
@ -593,3 +631,47 @@ fn conservative_unescape(literal: &str) -> Result<String, UnescapeErr> {
|
||||||
|
|
||||||
if err { Err(UnescapeErr::Lint) } else { Ok(unescaped) }
|
if err { Err(UnescapeErr::Lint) } else { Ok(unescaped) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Replaces `{` with `{{` and `}` with `}}`. If `preserve_unicode_escapes` is `true` the braces in
|
||||||
|
/// `\u{xxxx}` are left unmodified
|
||||||
|
#[expect(clippy::match_same_arms)]
|
||||||
|
fn escape_braces(literal: &str, preserve_unicode_escapes: bool) -> String {
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum State {
|
||||||
|
Normal,
|
||||||
|
Backslash,
|
||||||
|
UnicodeEscape,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut escaped = String::with_capacity(literal.len());
|
||||||
|
let mut state = State::Normal;
|
||||||
|
|
||||||
|
for ch in literal.chars() {
|
||||||
|
state = match (ch, state) {
|
||||||
|
// Escape braces outside of unicode escapes by doubling them up
|
||||||
|
('{' | '}', State::Normal) => {
|
||||||
|
escaped.push(ch);
|
||||||
|
State::Normal
|
||||||
|
},
|
||||||
|
// If `preserve_unicode_escapes` isn't enabled stay in `State::Normal`, otherwise:
|
||||||
|
//
|
||||||
|
// \u{aaaa} \\ \x01
|
||||||
|
// ^ ^ ^
|
||||||
|
('\\', State::Normal) if preserve_unicode_escapes => State::Backslash,
|
||||||
|
// \u{aaaa}
|
||||||
|
// ^
|
||||||
|
('u', State::Backslash) => State::UnicodeEscape,
|
||||||
|
// \xAA \\
|
||||||
|
// ^ ^
|
||||||
|
(_, State::Backslash) => State::Normal,
|
||||||
|
// \u{aaaa}
|
||||||
|
// ^
|
||||||
|
('}', State::UnicodeEscape) => State::Normal,
|
||||||
|
_ => state,
|
||||||
|
};
|
||||||
|
|
||||||
|
escaped.push(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
escaped
|
||||||
|
}
|
||||||
|
|
|
@ -9,11 +9,12 @@ use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
|
use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
|
||||||
use rustc_lexer::tokenize;
|
use rustc_lexer::tokenize;
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::mir::interpret::Scalar;
|
use rustc_middle::mir::interpret::{alloc_range, Scalar};
|
||||||
use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, List, ScalarInt, Ty, TyCtxt};
|
use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, List, ScalarInt, Ty, TyCtxt};
|
||||||
use rustc_middle::{bug, mir, span_bug};
|
use rustc_middle::{bug, mir, span_bug};
|
||||||
use rustc_span::symbol::{Ident, Symbol};
|
use rustc_span::symbol::{Ident, Symbol};
|
||||||
use rustc_span::SyntaxContext;
|
use rustc_span::SyntaxContext;
|
||||||
|
use rustc_target::abi::Size;
|
||||||
use std::cmp::Ordering::{self, Equal};
|
use std::cmp::Ordering::{self, Equal};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
@ -403,7 +404,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||||
&& adt_def.is_struct()
|
&& adt_def.is_struct()
|
||||||
&& let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field)
|
&& let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field)
|
||||||
{
|
{
|
||||||
miri_to_const(self.lcx, desired_field)
|
mir_to_const(self.lcx, desired_field)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result
|
result
|
||||||
|
@ -483,7 +484,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||||
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None)
|
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|val| rustc_middle::mir::Const::from_value(val, ty))?;
|
.map(|val| rustc_middle::mir::Const::from_value(val, ty))?;
|
||||||
let result = miri_to_const(self.lcx, result)?;
|
let result = mir_to_const(self.lcx, result)?;
|
||||||
self.source = ConstantSource::Constant;
|
self.source = ConstantSource::Constant;
|
||||||
Some(result)
|
Some(result)
|
||||||
},
|
},
|
||||||
|
@ -655,10 +656,14 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
|
pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
|
||||||
use rustc_middle::mir::ConstValue;
|
use rustc_middle::mir::ConstValue;
|
||||||
match result {
|
let mir::Const::Val(val, _) = result else {
|
||||||
mir::Const::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
|
// We only work on evaluated consts.
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
match (val, result.ty().kind()) {
|
||||||
|
(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
|
||||||
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
||||||
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
|
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
|
||||||
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
|
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
|
||||||
|
@ -671,42 +676,28 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
|
||||||
ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
|
ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
mir::Const::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) =>
|
(_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => {
|
||||||
{
|
let data = val.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
|
||||||
let data = cv.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
|
|
||||||
String::from_utf8(data.to_owned()).ok().map(Constant::Str)
|
String::from_utf8(data.to_owned()).ok().map(Constant::Str)
|
||||||
},
|
},
|
||||||
mir::Const::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => {
|
(_, ty::Adt(adt_def, _)) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
||||||
let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory();
|
(ConstValue::Indirect { alloc_id, offset }, ty::Array(sub_type, len)) => {
|
||||||
match result.ty().kind() {
|
let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
|
||||||
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
let len = len.try_to_target_usize(lcx.tcx)?;
|
||||||
ty::Array(sub_type, len) => match sub_type.kind() {
|
let ty::Float(flt) = sub_type.kind() else {
|
||||||
ty::Float(FloatTy::F32) => match len.try_to_target_usize(lcx.tcx) {
|
return None;
|
||||||
Some(len) => alloc
|
};
|
||||||
.inner()
|
let size = Size::from_bits(flt.bit_width());
|
||||||
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap()))
|
let mut res = Vec::new();
|
||||||
.to_owned()
|
for idx in 0..len {
|
||||||
.array_chunks::<4>()
|
let range = alloc_range(offset + size * idx, size);
|
||||||
.map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk))))
|
let val = alloc.read_scalar(&lcx.tcx, range, /* read_provenance */ false).ok()?;
|
||||||
.collect::<Option<Vec<Constant<'tcx>>>>()
|
res.push(match flt {
|
||||||
.map(Constant::Vec),
|
FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)),
|
||||||
_ => None,
|
FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().ok()?)),
|
||||||
},
|
});
|
||||||
ty::Float(FloatTy::F64) => match len.try_to_target_usize(lcx.tcx) {
|
|
||||||
Some(len) => alloc
|
|
||||||
.inner()
|
|
||||||
.inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap()))
|
|
||||||
.to_owned()
|
|
||||||
.array_chunks::<8>()
|
|
||||||
.map(|&chunk| Some(Constant::F64(f64::from_le_bytes(chunk))))
|
|
||||||
.collect::<Option<Vec<Constant<'tcx>>>>()
|
|
||||||
.map(Constant::Vec),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
}
|
||||||
|
Some(Constant::Vec(res))
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,9 +83,9 @@ pub fn span_lint_and_help<T: LintContext>(
|
||||||
cx.struct_span_lint(lint, span, msg.to_string(), |diag| {
|
cx.struct_span_lint(lint, span, msg.to_string(), |diag| {
|
||||||
let help = help.to_string();
|
let help = help.to_string();
|
||||||
if let Some(help_span) = help_span {
|
if let Some(help_span) = help_span {
|
||||||
diag.span_help(help_span, help.to_string());
|
diag.span_help(help_span, help);
|
||||||
} else {
|
} else {
|
||||||
diag.help(help.to_string());
|
diag.help(help);
|
||||||
}
|
}
|
||||||
docs_link(diag, lint);
|
docs_link(diag, lint);
|
||||||
diag
|
diag
|
||||||
|
|
|
@ -80,7 +80,6 @@ use std::sync::{Mutex, MutexGuard, OnceLock};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_ast::ast::{self, LitKind, RangeLimits};
|
use rustc_ast::ast::{self, LitKind, RangeLimits};
|
||||||
use rustc_ast::Attribute;
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::unhash::UnhashMap;
|
use rustc_data_structures::unhash::UnhashMap;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
|
@ -113,7 +112,7 @@ use rustc_span::{sym, Span};
|
||||||
use rustc_target::abi::Integer;
|
use rustc_target::abi::Integer;
|
||||||
use visitors::Visitable;
|
use visitors::Visitable;
|
||||||
|
|
||||||
use crate::consts::{constant, miri_to_const, Constant};
|
use crate::consts::{constant, mir_to_const, Constant};
|
||||||
use crate::higher::Range;
|
use crate::higher::Range;
|
||||||
use crate::ty::{
|
use crate::ty::{
|
||||||
adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
|
adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
|
||||||
|
@ -1509,9 +1508,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
|
||||||
if let rustc_ty::Adt(_, subst) = ty.kind()
|
if let rustc_ty::Adt(_, subst) = ty.kind()
|
||||||
&& let bnd_ty = subst.type_at(0)
|
&& let bnd_ty = subst.type_at(0)
|
||||||
&& let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
|
&& let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
|
||||||
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree()))
|
&& let Some(min_const) = mir_to_const(cx, Const::from_ty_const(min_val, cx.tcx))
|
||||||
&& let min_const_kind = Const::from_value(const_val, bnd_ty)
|
|
||||||
&& let Some(min_const) = miri_to_const(cx, min_const_kind)
|
|
||||||
&& let Some(start_const) = constant(cx, cx.typeck_results(), start)
|
&& let Some(start_const) = constant(cx, cx.typeck_results(), start)
|
||||||
{
|
{
|
||||||
start_const == min_const
|
start_const == min_const
|
||||||
|
@ -1525,9 +1522,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
|
||||||
if let rustc_ty::Adt(_, subst) = ty.kind()
|
if let rustc_ty::Adt(_, subst) = ty.kind()
|
||||||
&& let bnd_ty = subst.type_at(0)
|
&& let bnd_ty = subst.type_at(0)
|
||||||
&& let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
|
&& let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
|
||||||
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree()))
|
&& let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, cx.tcx))
|
||||||
&& let max_const_kind = Const::from_value(const_val, bnd_ty)
|
|
||||||
&& let Some(max_const) = miri_to_const(cx, max_const_kind)
|
|
||||||
&& let Some(end_const) = constant(cx, cx.typeck_results(), end)
|
&& let Some(end_const) = constant(cx, cx.typeck_results(), end)
|
||||||
{
|
{
|
||||||
end_const == max_const
|
end_const == max_const
|
||||||
|
@ -2456,11 +2451,12 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the item containing the given `HirId` has `#[cfg(test)]` attribute applied
|
/// Checks if `id` has a `#[cfg(test)]` attribute applied
|
||||||
///
|
///
|
||||||
/// Note: Add `//@compile-flags: --test` to UI tests with a `#[cfg(test)]` function
|
/// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent
|
||||||
pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
/// use [`is_in_cfg_test`]
|
||||||
fn is_cfg_test(attr: &Attribute) -> bool {
|
pub fn is_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
||||||
|
tcx.hir().attrs(id).iter().any(|attr| {
|
||||||
if attr.has_name(sym::cfg)
|
if attr.has_name(sym::cfg)
|
||||||
&& let Some(items) = attr.meta_item_list()
|
&& let Some(items) = attr.meta_item_list()
|
||||||
&& let [item] = &*items
|
&& let [item] = &*items
|
||||||
|
@ -2470,11 +2466,14 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied
|
||||||
|
pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
||||||
tcx.hir()
|
tcx.hir()
|
||||||
.parent_iter(id)
|
.parent_id_iter(id)
|
||||||
.flat_map(|(parent_id, _)| tcx.hir().attrs(parent_id))
|
.any(|parent_id| is_cfg_test(tcx, parent_id))
|
||||||
.any(is_cfg_test)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
|
/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
|
||||||
|
|
|
@ -19,7 +19,7 @@ macro_rules! msrv_aliases {
|
||||||
|
|
||||||
// names may refer to stabilized feature flags or library items
|
// names may refer to stabilized feature flags or library items
|
||||||
msrv_aliases! {
|
msrv_aliases! {
|
||||||
1,71,0 { TUPLE_ARRAY_CONVERSIONS }
|
1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
|
||||||
1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN }
|
1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN }
|
||||||
1,68,0 { PATH_MAIN_SEPARATOR_STR }
|
1,68,0 { PATH_MAIN_SEPARATOR_STR }
|
||||||
1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
|
1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
|
||||||
|
|
|
@ -8,7 +8,7 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
|
||||||
use rustc_lint::{LateContext, LintContext};
|
use rustc_lint::{LateContext, LintContext};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::source_map::{original_sp, SourceMap};
|
use rustc_span::source_map::{original_sp, SourceMap};
|
||||||
use rustc_span::{hygiene, BytePos, SourceFileAndLine, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP};
|
use rustc_span::{hygiene, BytePos, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, DUMMY_SP};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,27 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'tcx, A, B> Visitable<'tcx> for (A, B)
|
||||||
|
where
|
||||||
|
A: Visitable<'tcx>,
|
||||||
|
B: Visitable<'tcx>,
|
||||||
|
{
|
||||||
|
fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
|
||||||
|
let (a, b) = self;
|
||||||
|
a.visit(visitor);
|
||||||
|
b.visit(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'tcx, T> Visitable<'tcx> for Option<T>
|
||||||
|
where
|
||||||
|
T: Visitable<'tcx>,
|
||||||
|
{
|
||||||
|
fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
|
||||||
|
if let Some(x) = self {
|
||||||
|
x.visit(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
macro_rules! visitable_ref {
|
macro_rules! visitable_ref {
|
||||||
($t:ident, $f:ident) => {
|
($t:ident, $f:ident) => {
|
||||||
impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> {
|
impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> {
|
||||||
|
@ -748,3 +769,26 @@ pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool {
|
||||||
})
|
})
|
||||||
.is_some()
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If the local is only used once in `visitable` returns the path expression referencing the given
|
||||||
|
/// local
|
||||||
|
pub fn local_used_once<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
visitable: impl Visitable<'tcx>,
|
||||||
|
id: HirId,
|
||||||
|
) -> Option<&'tcx Expr<'tcx>> {
|
||||||
|
let mut expr = None;
|
||||||
|
|
||||||
|
let cf = for_each_expr_with_closures(cx, visitable, |e| {
|
||||||
|
if path_to_local_id(e, id) && expr.replace(e).is_some() {
|
||||||
|
ControlFlow::Break(())
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if cf.is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ use std::ops::Deref;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
|
use anstream::println;
|
||||||
|
|
||||||
/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
|
/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
|
||||||
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
|
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
|
||||||
fn arg_value<'a, T: Deref<Target = str>>(
|
fn arg_value<'a, T: Deref<Target = str>>(
|
||||||
|
@ -162,39 +164,15 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::ignored_unit_patterns)]
|
||||||
fn display_help() {
|
fn display_help() {
|
||||||
println!(
|
println!("{}", help_message());
|
||||||
"\
|
|
||||||
Checks a package to catch common mistakes and improve your Rust code.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
cargo clippy [options] [--] [<opts>...]
|
|
||||||
|
|
||||||
Common options:
|
|
||||||
-h, --help Print this message
|
|
||||||
--rustc Pass all args to rustc
|
|
||||||
-V, --version Print version info and exit
|
|
||||||
|
|
||||||
For the other options see `cargo check --help`.
|
|
||||||
|
|
||||||
To allow or deny a lint from the command line you can use `cargo clippy --`
|
|
||||||
with:
|
|
||||||
|
|
||||||
-W --warn OPT Set lint warnings
|
|
||||||
-A --allow OPT Set lint allowed
|
|
||||||
-D --deny OPT Set lint denied
|
|
||||||
-F --forbid OPT Set lint forbidden
|
|
||||||
|
|
||||||
You can use tool lints to allow or deny lints from your code, eg.:
|
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
|
||||||
"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml";
|
const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml";
|
||||||
|
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
|
#[allow(clippy::ignored_unit_patterns)]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let handler = EarlyErrorHandler::new(ErrorOutputType::default());
|
let handler = EarlyErrorHandler::new(ErrorOutputType::default());
|
||||||
|
|
||||||
|
@ -236,6 +214,7 @@ pub fn main() {
|
||||||
|
|
||||||
if orig_args.iter().any(|a| a == "--version" || a == "-V") {
|
if orig_args.iter().any(|a| a == "--version" || a == "-V") {
|
||||||
let version_info = rustc_tools_util::get_version_info!();
|
let version_info = rustc_tools_util::get_version_info!();
|
||||||
|
|
||||||
println!("{version_info}");
|
println!("{version_info}");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@ -292,3 +271,25 @@ pub fn main() {
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn help_message() -> &'static str {
|
||||||
|
color_print::cstr!(
|
||||||
|
"Checks a file to catch common mistakes and improve your Rust code.
|
||||||
|
Run <cyan>clippy-driver</> with the same arguments you use for <cyan>rustc</>
|
||||||
|
|
||||||
|
<green,bold>Usage</>:
|
||||||
|
<cyan,bold>clippy-driver</> <cyan>[OPTIONS] INPUT</>
|
||||||
|
|
||||||
|
<green,bold>Common options:</>
|
||||||
|
<cyan,bold>-h</>, <cyan,bold>--help</> Print this message
|
||||||
|
<cyan,bold>-V</>, <cyan,bold>--version</> Print version info and exit
|
||||||
|
<cyan,bold>--rustc</> Pass all arguments to <cyan>rustc</>
|
||||||
|
|
||||||
|
<green,bold>Allowing / Denying lints</>
|
||||||
|
You can use tool lints to allow or deny lints from your code, e.g.:
|
||||||
|
|
||||||
|
<yellow,bold>#[allow(clippy::needless_lifetimes)]</>
|
||||||
|
"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
63
src/main.rs
63
src/main.rs
|
@ -6,37 +6,14 @@ use std::env;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::{self, Command};
|
use std::process::{self, Command};
|
||||||
|
|
||||||
const CARGO_CLIPPY_HELP: &str = "Checks a package to catch common mistakes and improve your Rust code.
|
use anstream::println;
|
||||||
|
|
||||||
Usage:
|
|
||||||
cargo clippy [options] [--] [<opts>...]
|
|
||||||
|
|
||||||
Common options:
|
|
||||||
--no-deps Run Clippy only on the given crate, without linting the dependencies
|
|
||||||
--fix Automatically apply lint suggestions. This flag implies `--no-deps` and `--all-targets`
|
|
||||||
-h, --help Print this message
|
|
||||||
-V, --version Print version info and exit
|
|
||||||
--explain LINT Print the documentation for a given lint
|
|
||||||
|
|
||||||
For the other options see `cargo check --help`.
|
|
||||||
|
|
||||||
To allow or deny a lint from the command line you can use `cargo clippy --`
|
|
||||||
with:
|
|
||||||
|
|
||||||
-W --warn OPT Set lint warnings
|
|
||||||
-A --allow OPT Set lint allowed
|
|
||||||
-D --deny OPT Set lint denied
|
|
||||||
-F --forbid OPT Set lint forbidden
|
|
||||||
|
|
||||||
You can use tool lints to allow or deny lints from your code, e.g.:
|
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
|
||||||
";
|
|
||||||
|
|
||||||
|
#[allow(clippy::ignored_unit_patterns)]
|
||||||
fn show_help() {
|
fn show_help() {
|
||||||
println!("{CARGO_CLIPPY_HELP}");
|
println!("{}", help_message());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::ignored_unit_patterns)]
|
||||||
fn show_version() {
|
fn show_version() {
|
||||||
let version_info = rustc_tools_util::get_version_info!();
|
let version_info = rustc_tools_util::get_version_info!();
|
||||||
println!("{version_info}");
|
println!("{version_info}");
|
||||||
|
@ -168,6 +145,38 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn help_message() -> &'static str {
|
||||||
|
color_print::cstr!(
|
||||||
|
"Checks a package to catch common mistakes and improve your Rust code.
|
||||||
|
|
||||||
|
<green,bold>Usage</>:
|
||||||
|
<cyan,bold>cargo clippy</> <cyan>[OPTIONS] [--] [<<ARGS>>...]</>
|
||||||
|
|
||||||
|
<green,bold>Common options:</>
|
||||||
|
<cyan,bold>--no-deps</> Run Clippy only on the given crate, without linting the dependencies
|
||||||
|
<cyan,bold>--fix</> Automatically apply lint suggestions. This flag implies <cyan>--no-deps</> and <cyan>--all-targets</>
|
||||||
|
<cyan,bold>-h</>, <cyan,bold>--help</> Print this message
|
||||||
|
<cyan,bold>-V</>, <cyan,bold>--version</> Print version info and exit
|
||||||
|
<cyan,bold>--explain [LINT]</> Print the documentation for a given lint
|
||||||
|
|
||||||
|
See all options with <cyan,bold>cargo check --help</>.
|
||||||
|
|
||||||
|
<green,bold>Allowing / Denying lints</>
|
||||||
|
|
||||||
|
To allow or deny a lint from the command line you can use <cyan,bold>cargo clippy --</> with:
|
||||||
|
|
||||||
|
<cyan,bold>-W</> / <cyan,bold>--warn</> <cyan>[LINT]</> Set lint warnings
|
||||||
|
<cyan,bold>-A</> / <cyan,bold>--allow</> <cyan>[LINT]</> Set lint allowed
|
||||||
|
<cyan,bold>-D</> / <cyan,bold>--deny</> <cyan>[LINT]</> Set lint denied
|
||||||
|
<cyan,bold>-F</> / <cyan,bold>--forbid</> <cyan>[LINT]</> Set lint forbidden
|
||||||
|
|
||||||
|
You can use tool lints to allow or deny lints from your code, e.g.:
|
||||||
|
|
||||||
|
<yellow,bold>#[allow(clippy::needless_lifetimes)]</>
|
||||||
|
"
|
||||||
|
)
|
||||||
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::ClippyCmd;
|
use super::ClippyCmd;
|
||||||
|
|
|
@ -21,6 +21,18 @@ pub fn derive(_: TokenStream) -> TokenStream {
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(ImplStructWithStdDisplay)]
|
||||||
|
pub fn derive_std(_: TokenStream) -> TokenStream {
|
||||||
|
quote! {
|
||||||
|
struct A {}
|
||||||
|
impl ::std::fmt::Display for A {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
|
write!(f, "A")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(FieldReassignWithDefault)]
|
#[proc_macro_derive(FieldReassignWithDefault)]
|
||||||
pub fn derive_foo(_input: TokenStream) -> TokenStream {
|
pub fn derive_foo(_input: TokenStream) -> TokenStream {
|
||||||
quote! {
|
quote! {
|
||||||
|
@ -141,3 +153,19 @@ pub fn shadow_derive(_: TokenStream) -> TokenStream {
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(StructIgnoredUnitPattern)]
|
||||||
|
pub fn derive_ignored_unit_pattern(_: TokenStream) -> TokenStream {
|
||||||
|
quote! {
|
||||||
|
struct A;
|
||||||
|
impl A {
|
||||||
|
fn a(&self) -> Result<(), ()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn b(&self) {
|
||||||
|
let _ = self.a().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#![allow(clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, dead_code)]
|
#![allow(clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, dead_code)]
|
||||||
#![warn(clippy::expl_impl_clone_on_copy)]
|
#![warn(clippy::expl_impl_clone_on_copy)]
|
||||||
|
|
||||||
|
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
struct Qux;
|
struct Qux;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: you are implementing `Clone` explicitly on a `Copy` type
|
error: you are implementing `Clone` explicitly on a `Copy` type
|
||||||
--> $DIR/derive.rs:8:1
|
--> $DIR/derive.rs:7:1
|
||||||
|
|
|
|
||||||
LL | / impl Clone for Qux {
|
LL | / impl Clone for Qux {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -10,7 +10,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
note: consider deriving `Clone` or removing `Copy`
|
note: consider deriving `Clone` or removing `Copy`
|
||||||
--> $DIR/derive.rs:8:1
|
--> $DIR/derive.rs:7:1
|
||||||
|
|
|
|
||||||
LL | / impl Clone for Qux {
|
LL | / impl Clone for Qux {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -23,7 +23,7 @@ LL | | }
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]`
|
= help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]`
|
||||||
|
|
||||||
error: you are implementing `Clone` explicitly on a `Copy` type
|
error: you are implementing `Clone` explicitly on a `Copy` type
|
||||||
--> $DIR/derive.rs:33:1
|
--> $DIR/derive.rs:32:1
|
||||||
|
|
|
|
||||||
LL | / impl<'a> Clone for Lt<'a> {
|
LL | / impl<'a> Clone for Lt<'a> {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -34,7 +34,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
note: consider deriving `Clone` or removing `Copy`
|
note: consider deriving `Clone` or removing `Copy`
|
||||||
--> $DIR/derive.rs:33:1
|
--> $DIR/derive.rs:32:1
|
||||||
|
|
|
|
||||||
LL | / impl<'a> Clone for Lt<'a> {
|
LL | / impl<'a> Clone for Lt<'a> {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -45,7 +45,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: you are implementing `Clone` explicitly on a `Copy` type
|
error: you are implementing `Clone` explicitly on a `Copy` type
|
||||||
--> $DIR/derive.rs:45:1
|
--> $DIR/derive.rs:44:1
|
||||||
|
|
|
|
||||||
LL | / impl Clone for BigArray {
|
LL | / impl Clone for BigArray {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -56,7 +56,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
note: consider deriving `Clone` or removing `Copy`
|
note: consider deriving `Clone` or removing `Copy`
|
||||||
--> $DIR/derive.rs:45:1
|
--> $DIR/derive.rs:44:1
|
||||||
|
|
|
|
||||||
LL | / impl Clone for BigArray {
|
LL | / impl Clone for BigArray {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -67,7 +67,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: you are implementing `Clone` explicitly on a `Copy` type
|
error: you are implementing `Clone` explicitly on a `Copy` type
|
||||||
--> $DIR/derive.rs:57:1
|
--> $DIR/derive.rs:56:1
|
||||||
|
|
|
|
||||||
LL | / impl Clone for FnPtr {
|
LL | / impl Clone for FnPtr {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -78,7 +78,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
note: consider deriving `Clone` or removing `Copy`
|
note: consider deriving `Clone` or removing `Copy`
|
||||||
--> $DIR/derive.rs:57:1
|
--> $DIR/derive.rs:56:1
|
||||||
|
|
|
|
||||||
LL | / impl Clone for FnPtr {
|
LL | / impl Clone for FnPtr {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -89,7 +89,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: you are implementing `Clone` explicitly on a `Copy` type
|
error: you are implementing `Clone` explicitly on a `Copy` type
|
||||||
--> $DIR/derive.rs:78:1
|
--> $DIR/derive.rs:77:1
|
||||||
|
|
|
|
||||||
LL | / impl<T: Clone> Clone for Generic2<T> {
|
LL | / impl<T: Clone> Clone for Generic2<T> {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -100,7 +100,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
note: consider deriving `Clone` or removing `Copy`
|
note: consider deriving `Clone` or removing `Copy`
|
||||||
--> $DIR/derive.rs:78:1
|
--> $DIR/derive.rs:77:1
|
||||||
|
|
|
|
||||||
LL | / impl<T: Clone> Clone for Generic2<T> {
|
LL | / impl<T: Clone> Clone for Generic2<T> {
|
||||||
LL | |
|
LL | |
|
||||||
|
|
|
@ -22,9 +22,9 @@ mod rustc_ok {
|
||||||
|
|
||||||
#[expect(illegal_floating_point_literal_pattern)]
|
#[expect(illegal_floating_point_literal_pattern)]
|
||||||
match x {
|
match x {
|
||||||
5.0 => {}
|
5.0 => {},
|
||||||
6.0 => {}
|
6.0 => {},
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,9 +41,9 @@ mod rustc_warn {
|
||||||
#[expect(illegal_floating_point_literal_pattern)]
|
#[expect(illegal_floating_point_literal_pattern)]
|
||||||
//~^ ERROR: this lint expectation is unfulfilled
|
//~^ ERROR: this lint expectation is unfulfilled
|
||||||
match x {
|
match x {
|
||||||
5 => {}
|
5 => {},
|
||||||
6 => {}
|
6 => {},
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@aux-build:proc_macro_derive.rs
|
||||||
#![warn(clippy::ignored_unit_patterns)]
|
#![warn(clippy::ignored_unit_patterns)]
|
||||||
#![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)]
|
#![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)]
|
||||||
|
|
||||||
|
@ -14,8 +15,22 @@ fn main() {
|
||||||
//~^ ERROR: matching over `()` is more explicit
|
//~^ ERROR: matching over `()` is more explicit
|
||||||
let _ = foo().map_err(|()| todo!());
|
let _ = foo().map_err(|()| todo!());
|
||||||
//~^ ERROR: matching over `()` is more explicit
|
//~^ ERROR: matching over `()` is more explicit
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"{:?}",
|
||||||
|
match foo() {
|
||||||
|
Ok(()) => {},
|
||||||
|
//~^ ERROR: matching over `()` is more explicit
|
||||||
|
Err(()) => {},
|
||||||
|
//~^ ERROR: matching over `()` is more explicit
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ignored_unit_patterns in derive macro should be ok
|
||||||
|
#[derive(proc_macro_derive::StructIgnoredUnitPattern)]
|
||||||
|
pub struct B;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn moo(_: ()) {
|
pub fn moo(_: ()) {
|
||||||
let () = foo().unwrap();
|
let () = foo().unwrap();
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@aux-build:proc_macro_derive.rs
|
||||||
#![warn(clippy::ignored_unit_patterns)]
|
#![warn(clippy::ignored_unit_patterns)]
|
||||||
#![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)]
|
#![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)]
|
||||||
|
|
||||||
|
@ -14,8 +15,22 @@ fn main() {
|
||||||
//~^ ERROR: matching over `()` is more explicit
|
//~^ ERROR: matching over `()` is more explicit
|
||||||
let _ = foo().map_err(|_| todo!());
|
let _ = foo().map_err(|_| todo!());
|
||||||
//~^ ERROR: matching over `()` is more explicit
|
//~^ ERROR: matching over `()` is more explicit
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"{:?}",
|
||||||
|
match foo() {
|
||||||
|
Ok(_) => {},
|
||||||
|
//~^ ERROR: matching over `()` is more explicit
|
||||||
|
Err(_) => {},
|
||||||
|
//~^ ERROR: matching over `()` is more explicit
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ignored_unit_patterns in derive macro should be ok
|
||||||
|
#[derive(proc_macro_derive::StructIgnoredUnitPattern)]
|
||||||
|
pub struct B;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn moo(_: ()) {
|
pub fn moo(_: ()) {
|
||||||
let _ = foo().unwrap();
|
let _ = foo().unwrap();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: matching over `()` is more explicit
|
error: matching over `()` is more explicit
|
||||||
--> $DIR/ignored_unit_patterns.rs:10:12
|
--> $DIR/ignored_unit_patterns.rs:11:12
|
||||||
|
|
|
|
||||||
LL | Ok(_) => {},
|
LL | Ok(_) => {},
|
||||||
| ^ help: use `()` instead of `_`: `()`
|
| ^ help: use `()` instead of `_`: `()`
|
||||||
|
@ -8,28 +8,40 @@ LL | Ok(_) => {},
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::ignored_unit_patterns)]`
|
= help: to override `-D warnings` add `#[allow(clippy::ignored_unit_patterns)]`
|
||||||
|
|
||||||
error: matching over `()` is more explicit
|
error: matching over `()` is more explicit
|
||||||
--> $DIR/ignored_unit_patterns.rs:11:13
|
--> $DIR/ignored_unit_patterns.rs:12:13
|
||||||
|
|
|
|
||||||
LL | Err(_) => {},
|
LL | Err(_) => {},
|
||||||
| ^ help: use `()` instead of `_`: `()`
|
| ^ help: use `()` instead of `_`: `()`
|
||||||
|
|
||||||
error: matching over `()` is more explicit
|
error: matching over `()` is more explicit
|
||||||
--> $DIR/ignored_unit_patterns.rs:13:15
|
--> $DIR/ignored_unit_patterns.rs:14:15
|
||||||
|
|
|
|
||||||
LL | if let Ok(_) = foo() {}
|
LL | if let Ok(_) = foo() {}
|
||||||
| ^ help: use `()` instead of `_`: `()`
|
| ^ help: use `()` instead of `_`: `()`
|
||||||
|
|
||||||
error: matching over `()` is more explicit
|
error: matching over `()` is more explicit
|
||||||
--> $DIR/ignored_unit_patterns.rs:15:28
|
--> $DIR/ignored_unit_patterns.rs:16:28
|
||||||
|
|
|
|
||||||
LL | let _ = foo().map_err(|_| todo!());
|
LL | let _ = foo().map_err(|_| todo!());
|
||||||
| ^ help: use `()` instead of `_`: `()`
|
| ^ help: use `()` instead of `_`: `()`
|
||||||
|
|
||||||
error: matching over `()` is more explicit
|
error: matching over `()` is more explicit
|
||||||
--> $DIR/ignored_unit_patterns.rs:21:9
|
--> $DIR/ignored_unit_patterns.rs:22:16
|
||||||
|
|
|
||||||
|
LL | Ok(_) => {},
|
||||||
|
| ^ help: use `()` instead of `_`: `()`
|
||||||
|
|
||||||
|
error: matching over `()` is more explicit
|
||||||
|
--> $DIR/ignored_unit_patterns.rs:24:17
|
||||||
|
|
|
||||||
|
LL | Err(_) => {},
|
||||||
|
| ^ help: use `()` instead of `_`: `()`
|
||||||
|
|
||||||
|
error: matching over `()` is more explicit
|
||||||
|
--> $DIR/ignored_unit_patterns.rs:36:9
|
||||||
|
|
|
|
||||||
LL | let _ = foo().unwrap();
|
LL | let _ = foo().unwrap();
|
||||||
| ^ help: use `()` instead of `_`: `()`
|
| ^ help: use `()` instead of `_`: `()`
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,6 @@ fn fn_constref(i: &i32) -> i32 {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn fn_mutref(i: &mut i32) {
|
fn fn_mutref(i: &mut i32) {
|
||||||
//~^ ERROR: this argument is a mutable reference, but not used mutably
|
|
||||||
//~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn fooi() -> i32 {
|
fn fooi() -> i32 {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: variables in the condition are not mutated in the loop body
|
error: variables in the condition are not mutated in the loop body
|
||||||
--> $DIR/infinite_loop.rs:24:11
|
--> $DIR/infinite_loop.rs:22:11
|
||||||
|
|
|
|
||||||
LL | while y < 10 {
|
LL | while y < 10 {
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -8,7 +8,7 @@ LL | while y < 10 {
|
||||||
= note: `#[deny(clippy::while_immutable_condition)]` on by default
|
= note: `#[deny(clippy::while_immutable_condition)]` on by default
|
||||||
|
|
||||||
error: variables in the condition are not mutated in the loop body
|
error: variables in the condition are not mutated in the loop body
|
||||||
--> $DIR/infinite_loop.rs:31:11
|
--> $DIR/infinite_loop.rs:29:11
|
||||||
|
|
|
|
||||||
LL | while y < 10 && x < 3 {
|
LL | while y < 10 && x < 3 {
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
@ -16,7 +16,7 @@ LL | while y < 10 && x < 3 {
|
||||||
= note: this may lead to an infinite or to a never running loop
|
= note: this may lead to an infinite or to a never running loop
|
||||||
|
|
||||||
error: variables in the condition are not mutated in the loop body
|
error: variables in the condition are not mutated in the loop body
|
||||||
--> $DIR/infinite_loop.rs:40:11
|
--> $DIR/infinite_loop.rs:38:11
|
||||||
|
|
|
|
||||||
LL | while !cond {
|
LL | while !cond {
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -24,7 +24,7 @@ LL | while !cond {
|
||||||
= note: this may lead to an infinite or to a never running loop
|
= note: this may lead to an infinite or to a never running loop
|
||||||
|
|
||||||
error: variables in the condition are not mutated in the loop body
|
error: variables in the condition are not mutated in the loop body
|
||||||
--> $DIR/infinite_loop.rs:86:11
|
--> $DIR/infinite_loop.rs:84:11
|
||||||
|
|
|
|
||||||
LL | while i < 3 {
|
LL | while i < 3 {
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -32,7 +32,7 @@ LL | while i < 3 {
|
||||||
= note: this may lead to an infinite or to a never running loop
|
= note: this may lead to an infinite or to a never running loop
|
||||||
|
|
||||||
error: variables in the condition are not mutated in the loop body
|
error: variables in the condition are not mutated in the loop body
|
||||||
--> $DIR/infinite_loop.rs:93:11
|
--> $DIR/infinite_loop.rs:91:11
|
||||||
|
|
|
|
||||||
LL | while i < 3 && j > 0 {
|
LL | while i < 3 && j > 0 {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
@ -40,7 +40,7 @@ LL | while i < 3 && j > 0 {
|
||||||
= note: this may lead to an infinite or to a never running loop
|
= note: this may lead to an infinite or to a never running loop
|
||||||
|
|
||||||
error: variables in the condition are not mutated in the loop body
|
error: variables in the condition are not mutated in the loop body
|
||||||
--> $DIR/infinite_loop.rs:99:11
|
--> $DIR/infinite_loop.rs:97:11
|
||||||
|
|
|
|
||||||
LL | while i < 3 {
|
LL | while i < 3 {
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -48,7 +48,7 @@ LL | while i < 3 {
|
||||||
= note: this may lead to an infinite or to a never running loop
|
= note: this may lead to an infinite or to a never running loop
|
||||||
|
|
||||||
error: variables in the condition are not mutated in the loop body
|
error: variables in the condition are not mutated in the loop body
|
||||||
--> $DIR/infinite_loop.rs:116:11
|
--> $DIR/infinite_loop.rs:114:11
|
||||||
|
|
|
|
||||||
LL | while i < 3 {
|
LL | while i < 3 {
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -56,7 +56,7 @@ LL | while i < 3 {
|
||||||
= note: this may lead to an infinite or to a never running loop
|
= note: this may lead to an infinite or to a never running loop
|
||||||
|
|
||||||
error: variables in the condition are not mutated in the loop body
|
error: variables in the condition are not mutated in the loop body
|
||||||
--> $DIR/infinite_loop.rs:123:11
|
--> $DIR/infinite_loop.rs:121:11
|
||||||
|
|
|
|
||||||
LL | while i < 3 {
|
LL | while i < 3 {
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -64,7 +64,7 @@ LL | while i < 3 {
|
||||||
= note: this may lead to an infinite or to a never running loop
|
= note: this may lead to an infinite or to a never running loop
|
||||||
|
|
||||||
error: variables in the condition are not mutated in the loop body
|
error: variables in the condition are not mutated in the loop body
|
||||||
--> $DIR/infinite_loop.rs:191:15
|
--> $DIR/infinite_loop.rs:189:15
|
||||||
|
|
|
|
||||||
LL | while self.count < n {
|
LL | while self.count < n {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
@ -72,7 +72,7 @@ LL | while self.count < n {
|
||||||
= note: this may lead to an infinite or to a never running loop
|
= note: this may lead to an infinite or to a never running loop
|
||||||
|
|
||||||
error: variables in the condition are not mutated in the loop body
|
error: variables in the condition are not mutated in the loop body
|
||||||
--> $DIR/infinite_loop.rs:201:11
|
--> $DIR/infinite_loop.rs:199:11
|
||||||
|
|
|
|
||||||
LL | while y < 10 {
|
LL | while y < 10 {
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -82,7 +82,7 @@ LL | while y < 10 {
|
||||||
= help: rewrite it as `if cond { loop { } }`
|
= help: rewrite it as `if cond { loop { } }`
|
||||||
|
|
||||||
error: variables in the condition are not mutated in the loop body
|
error: variables in the condition are not mutated in the loop body
|
||||||
--> $DIR/infinite_loop.rs:210:11
|
--> $DIR/infinite_loop.rs:208:11
|
||||||
|
|
|
|
||||||
LL | while y < 10 {
|
LL | while y < 10 {
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -91,14 +91,5 @@ LL | while y < 10 {
|
||||||
= note: this loop contains `return`s or `break`s
|
= note: this loop contains `return`s or `break`s
|
||||||
= help: rewrite it as `if cond { loop { } }`
|
= help: rewrite it as `if cond { loop { } }`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: aborting due to 11 previous errors
|
||||||
--> $DIR/infinite_loop.rs:9:17
|
|
||||||
|
|
|
||||||
LL | fn fn_mutref(i: &mut i32) {
|
|
||||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
|
||||||
|
|
|
||||||
= note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
|
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
|
|
||||||
|
|
||||||
error: aborting due to 12 previous errors
|
|
||||||
|
|
||||||
|
|
124
tests/ui/into_iter_without_iter.rs
Normal file
124
tests/ui/into_iter_without_iter.rs
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
//@no-rustfix
|
||||||
|
#![warn(clippy::into_iter_without_iter)]
|
||||||
|
|
||||||
|
use std::iter::IntoIterator;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
{
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for &'a S {
|
||||||
|
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method
|
||||||
|
type IntoIter = std::slice::Iter<'a, u8>;
|
||||||
|
type Item = &'a u8;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> IntoIterator for &'a mut S {
|
||||||
|
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method
|
||||||
|
type IntoIter = std::slice::IterMut<'a, u8>;
|
||||||
|
type Item = &'a mut u8;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct S<T>(T);
|
||||||
|
impl<'a, T> IntoIterator for &'a S<T> {
|
||||||
|
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method
|
||||||
|
type IntoIter = std::slice::Iter<'a, T>;
|
||||||
|
type Item = &'a T;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, T> IntoIterator for &'a mut S<T> {
|
||||||
|
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method
|
||||||
|
type IntoIter = std::slice::IterMut<'a, T>;
|
||||||
|
type Item = &'a mut T;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Both iter and iter_mut methods exist, don't lint
|
||||||
|
struct S<'a, T>(&'a T);
|
||||||
|
|
||||||
|
impl<'a, T> S<'a, T> {
|
||||||
|
fn iter(&self) -> std::slice::Iter<'a, T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> IntoIterator for &S<'a, T> {
|
||||||
|
type IntoIter = std::slice::Iter<'a, T>;
|
||||||
|
type Item = &'a T;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> IntoIterator for &mut S<'a, T> {
|
||||||
|
type IntoIter = std::slice::IterMut<'a, T>;
|
||||||
|
type Item = &'a mut T;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Only `iter` exists, no `iter_mut`
|
||||||
|
struct S<'a, T>(&'a T);
|
||||||
|
|
||||||
|
impl<'a, T> S<'a, T> {
|
||||||
|
fn iter(&self) -> std::slice::Iter<'a, T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> IntoIterator for &S<'a, T> {
|
||||||
|
type IntoIter = std::slice::Iter<'a, T>;
|
||||||
|
type Item = &'a T;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> IntoIterator for &mut S<'a, T> {
|
||||||
|
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method
|
||||||
|
type IntoIter = std::slice::IterMut<'a, T>;
|
||||||
|
type Item = &'a mut T;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// `iter` exists, but `IntoIterator` is implemented for an alias. inherent_impls doesn't "normalize"
|
||||||
|
// aliases so that `inherent_impls(Alias)` where `type Alias = S` returns nothing, so this can lead
|
||||||
|
// to fun FPs. Make sure it doesn't happen here (we're using type_of, which should skip the alias).
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl S {
|
||||||
|
fn iter(&self) -> std::slice::Iter<'static, u8> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Alias = S;
|
||||||
|
|
||||||
|
impl IntoIterator for &Alias {
|
||||||
|
type IntoIter = std::slice::Iter<'static, u8>;
|
||||||
|
type Item = &'static u8;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
114
tests/ui/into_iter_without_iter.stderr
Normal file
114
tests/ui/into_iter_without_iter.stderr
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
error: `IntoIterator` implemented for a reference type without an `iter` method
|
||||||
|
--> $DIR/into_iter_without_iter.rs:10:9
|
||||||
|
|
|
||||||
|
LL | / impl<'a> IntoIterator for &'a S {
|
||||||
|
LL | |
|
||||||
|
LL | | type IntoIter = std::slice::Iter<'a, u8>;
|
||||||
|
LL | | type Item = &'a u8;
|
||||||
|
... |
|
||||||
|
LL | | }
|
||||||
|
LL | | }
|
||||||
|
| |_________^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::into-iter-without-iter` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::into_iter_without_iter)]`
|
||||||
|
help: consider implementing `iter`
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL + impl S {
|
||||||
|
LL + fn iter(&self) -> std::slice::Iter<'a, u8> {
|
||||||
|
LL + <&Self as IntoIterator>::into_iter(self)
|
||||||
|
LL + }
|
||||||
|
LL + }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `IntoIterator` implemented for a reference type without an `iter_mut` method
|
||||||
|
--> $DIR/into_iter_without_iter.rs:18:9
|
||||||
|
|
|
||||||
|
LL | / impl<'a> IntoIterator for &'a mut S {
|
||||||
|
LL | |
|
||||||
|
LL | | type IntoIter = std::slice::IterMut<'a, u8>;
|
||||||
|
LL | | type Item = &'a mut u8;
|
||||||
|
... |
|
||||||
|
LL | | }
|
||||||
|
LL | | }
|
||||||
|
| |_________^
|
||||||
|
|
|
||||||
|
help: consider implementing `iter_mut`
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL + impl S {
|
||||||
|
LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, u8> {
|
||||||
|
LL + <&mut Self as IntoIterator>::into_iter(self)
|
||||||
|
LL + }
|
||||||
|
LL + }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `IntoIterator` implemented for a reference type without an `iter` method
|
||||||
|
--> $DIR/into_iter_without_iter.rs:29:9
|
||||||
|
|
|
||||||
|
LL | / impl<'a, T> IntoIterator for &'a S<T> {
|
||||||
|
LL | |
|
||||||
|
LL | | type IntoIter = std::slice::Iter<'a, T>;
|
||||||
|
LL | | type Item = &'a T;
|
||||||
|
... |
|
||||||
|
LL | | }
|
||||||
|
LL | | }
|
||||||
|
| |_________^
|
||||||
|
|
|
||||||
|
help: consider implementing `iter`
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL + impl S<T> {
|
||||||
|
LL + fn iter(&self) -> std::slice::Iter<'a, T> {
|
||||||
|
LL + <&Self as IntoIterator>::into_iter(self)
|
||||||
|
LL + }
|
||||||
|
LL + }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `IntoIterator` implemented for a reference type without an `iter_mut` method
|
||||||
|
--> $DIR/into_iter_without_iter.rs:37:9
|
||||||
|
|
|
||||||
|
LL | / impl<'a, T> IntoIterator for &'a mut S<T> {
|
||||||
|
LL | |
|
||||||
|
LL | | type IntoIter = std::slice::IterMut<'a, T>;
|
||||||
|
LL | | type Item = &'a mut T;
|
||||||
|
... |
|
||||||
|
LL | | }
|
||||||
|
LL | | }
|
||||||
|
| |_________^
|
||||||
|
|
|
||||||
|
help: consider implementing `iter_mut`
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL + impl S<T> {
|
||||||
|
LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> {
|
||||||
|
LL + <&mut Self as IntoIterator>::into_iter(self)
|
||||||
|
LL + }
|
||||||
|
LL + }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `IntoIterator` implemented for a reference type without an `iter_mut` method
|
||||||
|
--> $DIR/into_iter_without_iter.rs:93:9
|
||||||
|
|
|
||||||
|
LL | / impl<'a, T> IntoIterator for &mut S<'a, T> {
|
||||||
|
LL | |
|
||||||
|
LL | | type IntoIter = std::slice::IterMut<'a, T>;
|
||||||
|
LL | | type Item = &'a mut T;
|
||||||
|
... |
|
||||||
|
LL | | }
|
||||||
|
LL | | }
|
||||||
|
| |_________^
|
||||||
|
|
|
||||||
|
help: consider implementing `iter_mut`
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL + impl S<'a, T> {
|
||||||
|
LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> {
|
||||||
|
LL + <&mut Self as IntoIterator>::into_iter(self)
|
||||||
|
LL + }
|
||||||
|
LL + }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
11
tests/ui/items_after_test_module/after_proc_macros.rs
Normal file
11
tests/ui/items_after_test_module/after_proc_macros.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
//@aux-build:../auxiliary/proc_macros.rs
|
||||||
|
extern crate proc_macros;
|
||||||
|
|
||||||
|
proc_macros::with_span! {
|
||||||
|
span
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn f() {}
|
4
tests/ui/items_after_test_module/auxiliary/submodule.rs
Normal file
4
tests/ui/items_after_test_module/auxiliary/submodule.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {}
|
||||||
|
|
||||||
|
fn in_submodule() {}
|
|
@ -1,2 +0,0 @@
|
||||||
error: Option 'test' given more than once
|
|
||||||
|
|
8
tests/ui/items_after_test_module/in_submodule.rs
Normal file
8
tests/ui/items_after_test_module/in_submodule.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#[path = "auxiliary/submodule.rs"]
|
||||||
|
mod submodule;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn t() {}
|
||||||
|
}
|
14
tests/ui/items_after_test_module/in_submodule.stderr
Normal file
14
tests/ui/items_after_test_module/in_submodule.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error: items after a test module
|
||||||
|
--> $DIR/auxiliary/submodule.rs:2:1
|
||||||
|
|
|
||||||
|
LL | mod tests {}
|
||||||
|
| ^^^^^^^^^
|
||||||
|
LL |
|
||||||
|
LL | fn in_submodule() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::items-after-test-module` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::items_after_test_module)]`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
11
tests/ui/items_after_test_module/multiple_modules.rs
Normal file
11
tests/ui/items_after_test_module/multiple_modules.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn f() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod more_tests {
|
||||||
|
#[test]
|
||||||
|
fn g() {}
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
//@compile-flags: --test
|
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
#![warn(clippy::items_after_test_module)]
|
#![warn(clippy::items_after_test_module)]
|
||||||
|
|
||||||
|
@ -6,6 +5,13 @@ fn main() {}
|
||||||
|
|
||||||
fn should_not_lint() {}
|
fn should_not_lint() {}
|
||||||
|
|
||||||
|
fn should_lint() {}
|
||||||
|
|
||||||
|
const SHOULD_ALSO_LINT: usize = 1;
|
||||||
|
macro_rules! should_lint {
|
||||||
|
() => {};
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(unused)] // Some attributes to check that span replacement is good enough
|
#[allow(unused)] // Some attributes to check that span replacement is good enough
|
||||||
#[allow(clippy::allow_attributes)]
|
#[allow(clippy::allow_attributes)]
|
||||||
|
@ -14,10 +20,3 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn hi() {}
|
fn hi() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_lint() {}
|
|
||||||
|
|
||||||
const SHOULD_ALSO_LINT: usize = 1;
|
|
||||||
macro_rules! should_not_lint {
|
|
||||||
() => {};
|
|
||||||
}
|
|
22
tests/ui/items_after_test_module/root_module.rs
Normal file
22
tests/ui/items_after_test_module/root_module.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#![allow(unused)]
|
||||||
|
#![warn(clippy::items_after_test_module)]
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
fn should_not_lint() {}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[allow(unused)] // Some attributes to check that span replacement is good enough
|
||||||
|
#[allow(clippy::allow_attributes)]
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn hi() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_lint() {}
|
||||||
|
|
||||||
|
const SHOULD_ALSO_LINT: usize = 1;
|
||||||
|
macro_rules! should_lint {
|
||||||
|
() => {};
|
||||||
|
}
|
20
tests/ui/items_after_test_module/root_module.stderr
Normal file
20
tests/ui/items_after_test_module/root_module.stderr
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
error: items after a test module
|
||||||
|
--> $DIR/root_module.rs:12:1
|
||||||
|
|
|
||||||
|
LL | mod tests {
|
||||||
|
| ^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | fn should_lint() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
LL |
|
||||||
|
LL | const SHOULD_ALSO_LINT: usize = 1;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | macro_rules! should_lint {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::items-after-test-module` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::items_after_test_module)]`
|
||||||
|
= help: move the items to before the test module was defined
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
120
tests/ui/iter_without_into_iter.rs
Normal file
120
tests/ui/iter_without_into_iter.rs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
//@no-rustfix
|
||||||
|
#![warn(clippy::iter_without_into_iter)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
{
|
||||||
|
struct S;
|
||||||
|
impl S {
|
||||||
|
pub fn iter(&self) -> std::slice::Iter<'_, u8> {
|
||||||
|
//~^ ERROR: `iter` method without an `IntoIterator` impl
|
||||||
|
[].iter()
|
||||||
|
}
|
||||||
|
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
|
||||||
|
//~^ ERROR: `iter_mut` method without an `IntoIterator` impl
|
||||||
|
[].iter_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct S;
|
||||||
|
impl S {
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = &u8> {
|
||||||
|
// RPITIT is not stable, so we can't generally suggest it here yet
|
||||||
|
[].iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct S<'a>(&'a mut [u8]);
|
||||||
|
impl<'a> S<'a> {
|
||||||
|
pub fn iter(&self) -> std::slice::Iter<'_, u8> {
|
||||||
|
//~^ ERROR: `iter` method without an `IntoIterator` impl
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
|
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
|
||||||
|
//~^ ERROR: `iter_mut` method without an `IntoIterator` impl
|
||||||
|
self.0.iter_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Incompatible signatures
|
||||||
|
struct S;
|
||||||
|
impl S {
|
||||||
|
pub fn iter(self) -> std::slice::Iter<'static, u8> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct S2;
|
||||||
|
impl S2 {
|
||||||
|
pub async fn iter(&self) -> std::slice::Iter<'static, u8> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct S3;
|
||||||
|
impl S3 {
|
||||||
|
pub fn iter(&self, _additional_param: ()) -> std::slice::Iter<'static, u8> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct S4<T>(T);
|
||||||
|
impl<T> S4<T> {
|
||||||
|
pub fn iter<U>(&self) -> std::slice::Iter<'static, (T, U)> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct S5<T>(T);
|
||||||
|
impl<T> S5<T> {
|
||||||
|
pub fn iter(&self) -> std::slice::Iter<'static, T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct S<T>(T);
|
||||||
|
impl<T> S<T> {
|
||||||
|
pub fn iter(&self) -> std::slice::Iter<'_, T> {
|
||||||
|
//~^ ERROR: `iter` method without an `IntoIterator` impl
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
|
||||||
|
//~^ ERROR: `iter_mut` method without an `IntoIterator` impl
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct S<T>(T);
|
||||||
|
impl<T> S<T> {
|
||||||
|
pub fn iter(&self) -> std::slice::Iter<'_, T> {
|
||||||
|
// Don't lint, there's an existing (wrong) IntoIterator impl
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> IntoIterator for &'a S<T> {
|
||||||
|
type Item = &'a String;
|
||||||
|
type IntoIter = std::slice::Iter<'a, String>;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct S<T>(T);
|
||||||
|
impl<T> S<T> {
|
||||||
|
pub fn iter_mut(&self) -> std::slice::IterMut<'_, T> {
|
||||||
|
// Don't lint, there's an existing (wrong) IntoIterator impl
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> IntoIterator for &'a mut S<T> {
|
||||||
|
type Item = &'a mut String;
|
||||||
|
type IntoIter = std::slice::IterMut<'a, String>;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
150
tests/ui/iter_without_into_iter.stderr
Normal file
150
tests/ui/iter_without_into_iter.stderr
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
error: `iter` method without an `IntoIterator` impl for `&S`
|
||||||
|
--> $DIR/iter_without_into_iter.rs:8:13
|
||||||
|
|
|
||||||
|
LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> {
|
||||||
|
LL | |
|
||||||
|
LL | | [].iter()
|
||||||
|
LL | | }
|
||||||
|
| |_____________^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::iter-without-into-iter` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::iter_without_into_iter)]`
|
||||||
|
help: consider implementing `IntoIterator` for `&S`
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL + impl IntoIterator for &S {
|
||||||
|
LL + type IntoIter = std::slice::Iter<'_, u8>;
|
||||||
|
LL + type Iter = &u8;
|
||||||
|
LL + fn into_iter() -> Self::IntoIter {
|
||||||
|
LL + self.iter()
|
||||||
|
LL + }
|
||||||
|
LL + }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `iter_mut` method without an `IntoIterator` impl for `&mut S`
|
||||||
|
--> $DIR/iter_without_into_iter.rs:12:13
|
||||||
|
|
|
||||||
|
LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
|
||||||
|
LL | |
|
||||||
|
LL | | [].iter_mut()
|
||||||
|
LL | | }
|
||||||
|
| |_____________^
|
||||||
|
|
|
||||||
|
help: consider implementing `IntoIterator` for `&mut S`
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL + impl IntoIterator for &mut S {
|
||||||
|
LL + type IntoIter = std::slice::IterMut<'_, u8>;
|
||||||
|
LL + type Iter = &mut u8;
|
||||||
|
LL + fn into_iter() -> Self::IntoIter {
|
||||||
|
LL + self.iter()
|
||||||
|
LL + }
|
||||||
|
LL + }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `iter` method without an `IntoIterator` impl for `&S<'a>`
|
||||||
|
--> $DIR/iter_without_into_iter.rs:30:13
|
||||||
|
|
|
||||||
|
LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> {
|
||||||
|
LL | |
|
||||||
|
LL | | self.0.iter()
|
||||||
|
LL | | }
|
||||||
|
| |_____________^
|
||||||
|
|
|
||||||
|
help: consider implementing `IntoIterator` for `&S<'a>`
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL + impl IntoIterator for &S<'a> {
|
||||||
|
LL + type IntoIter = std::slice::Iter<'_, u8>;
|
||||||
|
LL + type Iter = &u8;
|
||||||
|
LL + fn into_iter() -> Self::IntoIter {
|
||||||
|
LL + self.iter()
|
||||||
|
LL + }
|
||||||
|
LL + }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `iter_mut` method without an `IntoIterator` impl for `&mut S<'a>`
|
||||||
|
--> $DIR/iter_without_into_iter.rs:34:13
|
||||||
|
|
|
||||||
|
LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
|
||||||
|
LL | |
|
||||||
|
LL | | self.0.iter_mut()
|
||||||
|
LL | | }
|
||||||
|
| |_____________^
|
||||||
|
|
|
||||||
|
help: consider implementing `IntoIterator` for `&mut S<'a>`
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL + impl IntoIterator for &mut S<'a> {
|
||||||
|
LL + type IntoIter = std::slice::IterMut<'_, u8>;
|
||||||
|
LL + type Iter = &mut u8;
|
||||||
|
LL + fn into_iter() -> Self::IntoIter {
|
||||||
|
LL + self.iter()
|
||||||
|
LL + }
|
||||||
|
LL + }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `iter` method without an `IntoIterator` impl for `&S5<T>`
|
||||||
|
--> $DIR/iter_without_into_iter.rs:68:13
|
||||||
|
|
|
||||||
|
LL | / pub fn iter(&self) -> std::slice::Iter<'static, T> {
|
||||||
|
LL | | todo!()
|
||||||
|
LL | | }
|
||||||
|
| |_____________^
|
||||||
|
|
|
||||||
|
help: consider implementing `IntoIterator` for `&S5<T>`
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL + impl IntoIterator for &S5<T> {
|
||||||
|
LL + type IntoIter = std::slice::Iter<'static, T>;
|
||||||
|
LL + type Iter = &T;
|
||||||
|
LL + fn into_iter() -> Self::IntoIter {
|
||||||
|
LL + self.iter()
|
||||||
|
LL + }
|
||||||
|
LL + }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `iter` method without an `IntoIterator` impl for `&S<T>`
|
||||||
|
--> $DIR/iter_without_into_iter.rs:76:13
|
||||||
|
|
|
||||||
|
LL | / pub fn iter(&self) -> std::slice::Iter<'_, T> {
|
||||||
|
LL | |
|
||||||
|
LL | | todo!()
|
||||||
|
LL | | }
|
||||||
|
| |_____________^
|
||||||
|
|
|
||||||
|
help: consider implementing `IntoIterator` for `&S<T>`
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL + impl IntoIterator for &S<T> {
|
||||||
|
LL + type IntoIter = std::slice::Iter<'_, T>;
|
||||||
|
LL + type Iter = &T;
|
||||||
|
LL + fn into_iter() -> Self::IntoIter {
|
||||||
|
LL + self.iter()
|
||||||
|
LL + }
|
||||||
|
LL + }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `iter_mut` method without an `IntoIterator` impl for `&mut S<T>`
|
||||||
|
--> $DIR/iter_without_into_iter.rs:80:13
|
||||||
|
|
|
||||||
|
LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
|
||||||
|
LL | |
|
||||||
|
LL | | todo!()
|
||||||
|
LL | | }
|
||||||
|
| |_____________^
|
||||||
|
|
|
||||||
|
help: consider implementing `IntoIterator` for `&mut S<T>`
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL + impl IntoIterator for &mut S<T> {
|
||||||
|
LL + type IntoIter = std::slice::IterMut<'_, T>;
|
||||||
|
LL + type Iter = &mut T;
|
||||||
|
LL + fn into_iter() -> Self::IntoIter {
|
||||||
|
LL + self.iter()
|
||||||
|
LL + }
|
||||||
|
LL + }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
|
@ -9,8 +9,6 @@ fn custom() -> impl Future<Output = ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_something_to_future(future: &mut impl Future<Output = ()>) {}
|
fn do_something_to_future(future: &mut impl Future<Output = ()>) {}
|
||||||
//~^ ERROR: this argument is a mutable reference, but not used mutably
|
|
||||||
//~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ = some_async_fn();
|
let _ = some_async_fn();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: non-binding `let` on a future
|
error: non-binding `let` on a future
|
||||||
--> $DIR/let_underscore_future.rs:16:5
|
--> $DIR/let_underscore_future.rs:14:5
|
||||||
|
|
|
|
||||||
LL | let _ = some_async_fn();
|
LL | let _ = some_async_fn();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -9,7 +9,7 @@ LL | let _ = some_async_fn();
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::let_underscore_future)]`
|
= help: to override `-D warnings` add `#[allow(clippy::let_underscore_future)]`
|
||||||
|
|
||||||
error: non-binding `let` on a future
|
error: non-binding `let` on a future
|
||||||
--> $DIR/let_underscore_future.rs:18:5
|
--> $DIR/let_underscore_future.rs:16:5
|
||||||
|
|
|
|
||||||
LL | let _ = custom();
|
LL | let _ = custom();
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
@ -17,21 +17,12 @@ LL | let _ = custom();
|
||||||
= help: consider awaiting the future or dropping explicitly with `std::mem::drop`
|
= help: consider awaiting the future or dropping explicitly with `std::mem::drop`
|
||||||
|
|
||||||
error: non-binding `let` on a future
|
error: non-binding `let` on a future
|
||||||
--> $DIR/let_underscore_future.rs:23:5
|
--> $DIR/let_underscore_future.rs:21:5
|
||||||
|
|
|
|
||||||
LL | let _ = future;
|
LL | let _ = future;
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: consider awaiting the future or dropping explicitly with `std::mem::drop`
|
= help: consider awaiting the future or dropping explicitly with `std::mem::drop`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: aborting due to 3 previous errors
|
||||||
--> $DIR/let_underscore_future.rs:11:35
|
|
||||||
|
|
|
||||||
LL | fn do_something_to_future(future: &mut impl Future<Output = ()>) {}
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&impl Future<Output = ()>`
|
|
||||||
|
|
|
||||||
= note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
|
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
|
||||||
|
|
||||||
|
|
89
tests/ui/manual_hash_one.fixed
Normal file
89
tests/ui/manual_hash_one.fixed
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#![warn(clippy::manual_hash_one)]
|
||||||
|
#![allow(clippy::needless_borrows_for_generic_args)]
|
||||||
|
|
||||||
|
use std::hash::{BuildHasher, Hash, Hasher};
|
||||||
|
|
||||||
|
fn returned(b: impl BuildHasher) -> u64 {
|
||||||
|
|
||||||
|
|
||||||
|
b.hash_one(&true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unsized_receiver(b: impl BuildHasher, s: &str) {
|
||||||
|
|
||||||
|
|
||||||
|
let _ = b.hash_one(&s[4..10]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn owned_value(b: impl BuildHasher, v: Vec<u32>) -> Vec<u32> {
|
||||||
|
|
||||||
|
|
||||||
|
let _ = b.hash_one(&v);
|
||||||
|
v
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reused_hasher(b: impl BuildHasher) {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
true.hash(&mut hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reused_hasher_in_return(b: impl BuildHasher) -> u64 {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
true.hash(&mut hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
hasher.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn no_hash(b: impl BuildHasher) {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_twice(b: impl BuildHasher) {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
true.hash(&mut hasher);
|
||||||
|
true.hash(&mut hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn other_hasher(b: impl BuildHasher) {
|
||||||
|
let mut other_hasher = b.build_hasher();
|
||||||
|
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
true.hash(&mut other_hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_then_hash(b: impl BuildHasher) {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
let _ = hasher.finish();
|
||||||
|
true.hash(&mut hasher);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn in_macro(b: impl BuildHasher) {
|
||||||
|
macro_rules! m {
|
||||||
|
($b:expr) => {{
|
||||||
|
let mut hasher = $b.build_hasher();
|
||||||
|
true.hash(&mut hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
m!(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[clippy::msrv = "1.70"]
|
||||||
|
fn msrv_1_70(b: impl BuildHasher, v: impl Hash) {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
v.hash(&mut hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[clippy::msrv = "1.71"]
|
||||||
|
fn msrv_1_71(b: impl BuildHasher, v: impl Hash) {
|
||||||
|
|
||||||
|
|
||||||
|
let _ = b.hash_one(&v);
|
||||||
|
}
|
89
tests/ui/manual_hash_one.rs
Normal file
89
tests/ui/manual_hash_one.rs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#![warn(clippy::manual_hash_one)]
|
||||||
|
#![allow(clippy::needless_borrows_for_generic_args)]
|
||||||
|
|
||||||
|
use std::hash::{BuildHasher, Hash, Hasher};
|
||||||
|
|
||||||
|
fn returned(b: impl BuildHasher) -> u64 {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
true.hash(&mut hasher);
|
||||||
|
hasher.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unsized_receiver(b: impl BuildHasher, s: &str) {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
s[4..10].hash(&mut hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn owned_value(b: impl BuildHasher, v: Vec<u32>) -> Vec<u32> {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
v.hash(&mut hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
v
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reused_hasher(b: impl BuildHasher) {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
true.hash(&mut hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reused_hasher_in_return(b: impl BuildHasher) -> u64 {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
true.hash(&mut hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
hasher.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn no_hash(b: impl BuildHasher) {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_twice(b: impl BuildHasher) {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
true.hash(&mut hasher);
|
||||||
|
true.hash(&mut hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn other_hasher(b: impl BuildHasher) {
|
||||||
|
let mut other_hasher = b.build_hasher();
|
||||||
|
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
true.hash(&mut other_hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_then_hash(b: impl BuildHasher) {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
let _ = hasher.finish();
|
||||||
|
true.hash(&mut hasher);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn in_macro(b: impl BuildHasher) {
|
||||||
|
macro_rules! m {
|
||||||
|
($b:expr) => {{
|
||||||
|
let mut hasher = $b.build_hasher();
|
||||||
|
true.hash(&mut hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
m!(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[clippy::msrv = "1.70"]
|
||||||
|
fn msrv_1_70(b: impl BuildHasher, v: impl Hash) {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
v.hash(&mut hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[clippy::msrv = "1.71"]
|
||||||
|
fn msrv_1_71(b: impl BuildHasher, v: impl Hash) {
|
||||||
|
let mut hasher = b.build_hasher();
|
||||||
|
v.hash(&mut hasher);
|
||||||
|
let _ = hasher.finish();
|
||||||
|
}
|
56
tests/ui/manual_hash_one.stderr
Normal file
56
tests/ui/manual_hash_one.stderr
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
error: manual implementation of `BuildHasher::hash_one`
|
||||||
|
--> $DIR/manual_hash_one.rs:9:5
|
||||||
|
|
|
||||||
|
LL | hasher.finish()
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::manual-hash-one` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::manual_hash_one)]`
|
||||||
|
help: try
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL ~
|
||||||
|
LL ~ b.hash_one(&true)
|
||||||
|
|
|
||||||
|
|
||||||
|
error: manual implementation of `BuildHasher::hash_one`
|
||||||
|
--> $DIR/manual_hash_one.rs:15:13
|
||||||
|
|
|
||||||
|
LL | let _ = hasher.finish();
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: try
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL ~
|
||||||
|
LL ~ let _ = b.hash_one(&s[4..10]);
|
||||||
|
|
|
||||||
|
|
||||||
|
error: manual implementation of `BuildHasher::hash_one`
|
||||||
|
--> $DIR/manual_hash_one.rs:21:13
|
||||||
|
|
|
||||||
|
LL | let _ = hasher.finish();
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: try
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL ~
|
||||||
|
LL ~ let _ = b.hash_one(&v);
|
||||||
|
|
|
||||||
|
|
||||||
|
error: manual implementation of `BuildHasher::hash_one`
|
||||||
|
--> $DIR/manual_hash_one.rs:88:13
|
||||||
|
|
|
||||||
|
LL | let _ = hasher.finish();
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: try
|
||||||
|
|
|
||||||
|
LL ~
|
||||||
|
LL ~
|
||||||
|
LL ~ let _ = b.hash_one(&v);
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
|
@ -133,3 +133,7 @@ fn not_fire() {
|
||||||
[data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data,
|
[data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn issue11579() {
|
||||||
|
let Some(msg) = Some("hi") else { unreachable!("can't happen") };
|
||||||
|
}
|
||||||
|
|
|
@ -170,3 +170,11 @@ fn not_fire() {
|
||||||
[data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data,
|
[data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn issue11579() {
|
||||||
|
let msg = match Some("hi") {
|
||||||
|
//~^ ERROR: this could be rewritten as `let...else`
|
||||||
|
Some(m) => m,
|
||||||
|
_ => unreachable!("can't happen"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -92,5 +92,15 @@ LL | | _ => return,
|
||||||
LL | | };
|
LL | | };
|
||||||
| |______^ help: consider writing: `let ([data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0]) = data.as_slice() else { return };`
|
| |______^ help: consider writing: `let ([data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0]) = data.as_slice() else { return };`
|
||||||
|
|
||||||
error: aborting due to 9 previous errors
|
error: this could be rewritten as `let...else`
|
||||||
|
--> $DIR/manual_let_else_match.rs:175:5
|
||||||
|
|
|
||||||
|
LL | / let msg = match Some("hi") {
|
||||||
|
LL | |
|
||||||
|
LL | | Some(m) => m,
|
||||||
|
LL | | _ => unreachable!("can't happen"),
|
||||||
|
LL | | };
|
||||||
|
| |______^ help: consider writing: `let Some(msg) = Some("hi") else { unreachable!("can't happen") };`
|
||||||
|
|
||||||
|
error: aborting due to 10 previous errors
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,9 @@ enum E {
|
||||||
_C,
|
_C,
|
||||||
}
|
}
|
||||||
|
|
||||||
// user forgot to remove the marker
|
// if the user explicitly marks as nonexhaustive we shouldn't warn them
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
enum Ep {
|
enum Ep {
|
||||||
//~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern
|
|
||||||
A,
|
A,
|
||||||
B,
|
B,
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|
|
@ -22,23 +22,5 @@ LL | _C,
|
||||||
= note: `-D clippy::manual-non-exhaustive` implied by `-D warnings`
|
= note: `-D clippy::manual-non-exhaustive` implied by `-D warnings`
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]`
|
= help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]`
|
||||||
|
|
||||||
error: this seems like a manual implementation of the non-exhaustive pattern
|
error: aborting due to previous error
|
||||||
--> $DIR/manual_non_exhaustive_enum.rs:15:1
|
|
||||||
|
|
|
||||||
LL | / enum Ep {
|
|
||||||
LL | |
|
|
||||||
LL | | A,
|
|
||||||
LL | | B,
|
|
||||||
LL | | #[doc(hidden)]
|
|
||||||
LL | | _C,
|
|
||||||
LL | | }
|
|
||||||
| |_^
|
|
||||||
|
|
|
||||||
help: remove this variant
|
|
||||||
--> $DIR/manual_non_exhaustive_enum.rs:20:5
|
|
||||||
|
|
|
||||||
LL | _C,
|
|
||||||
| ^^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,6 @@ fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<K
|
||||||
//~^ ERROR: mutable key type
|
//~^ ERROR: mutable key type
|
||||||
//~| NOTE: `-D clippy::mutable-key-type` implied by `-D warnings`
|
//~| NOTE: `-D clippy::mutable-key-type` implied by `-D warnings`
|
||||||
//~| ERROR: mutable key type
|
//~| ERROR: mutable key type
|
||||||
//~| ERROR: this argument is a mutable reference, but not used mutably
|
|
||||||
//~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
|
|
||||||
let _other: HashMap<Key, bool> = HashMap::new();
|
let _other: HashMap<Key, bool> = HashMap::new();
|
||||||
//~^ ERROR: mutable key type
|
//~^ ERROR: mutable key type
|
||||||
m.keys().cloned().collect()
|
m.keys().cloned().collect()
|
||||||
|
|
|
@ -14,103 +14,94 @@ LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> Hash
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:37:5
|
--> $DIR/mut_key.rs:35:5
|
||||||
|
|
|
|
||||||
LL | let _other: HashMap<Key, bool> = HashMap::new();
|
LL | let _other: HashMap<Key, bool> = HashMap::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:65:22
|
--> $DIR/mut_key.rs:63:22
|
||||||
|
|
|
|
||||||
LL | fn tuples_bad<U>(_m: &mut HashMap<(Key, U), bool>) {}
|
LL | fn tuples_bad<U>(_m: &mut HashMap<(Key, U), bool>) {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:78:5
|
--> $DIR/mut_key.rs:76:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Cell<usize>, usize>::new();
|
LL | let _map = HashMap::<Cell<usize>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:80:5
|
--> $DIR/mut_key.rs:78:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<&mut Cell<usize>, usize>::new();
|
LL | let _map = HashMap::<&mut Cell<usize>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:82:5
|
--> $DIR/mut_key.rs:80:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<&mut usize, usize>::new();
|
LL | let _map = HashMap::<&mut usize, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:85:5
|
--> $DIR/mut_key.rs:83:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Vec<Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<Vec<Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:87:5
|
--> $DIR/mut_key.rs:85:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<BTreeMap<Cell<usize>, ()>, usize>::new();
|
LL | let _map = HashMap::<BTreeMap<Cell<usize>, ()>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:89:5
|
--> $DIR/mut_key.rs:87:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<BTreeMap<(), Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<BTreeMap<(), Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:91:5
|
--> $DIR/mut_key.rs:89:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<BTreeSet<Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<BTreeSet<Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:93:5
|
--> $DIR/mut_key.rs:91:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Option<Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<Option<Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:95:5
|
--> $DIR/mut_key.rs:93:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Option<Vec<Cell<usize>>>, usize>::new();
|
LL | let _map = HashMap::<Option<Vec<Cell<usize>>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:97:5
|
--> $DIR/mut_key.rs:95:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Result<&mut usize, ()>, usize>::new();
|
LL | let _map = HashMap::<Result<&mut usize, ()>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:100:5
|
--> $DIR/mut_key.rs:98:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Box<Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<Box<Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:102:5
|
--> $DIR/mut_key.rs:100:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Rc<Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<Rc<Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:104:5
|
--> $DIR/mut_key.rs:102:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Arc<Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<Arc<Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: aborting due to 17 previous errors
|
||||||
--> $DIR/mut_key.rs:31:32
|
|
||||||
|
|
|
||||||
LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&HashMap<Key, usize>`
|
|
||||||
|
|
|
||||||
= note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
|
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
|
|
||||||
|
|
||||||
error: aborting due to 18 previous errors
|
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,6 @@ impl MyStruct {
|
||||||
fn takes_an_immutable_reference(&self, a: &i32) {}
|
fn takes_an_immutable_reference(&self, a: &i32) {}
|
||||||
|
|
||||||
fn takes_a_mutable_reference(&self, a: &mut i32) {}
|
fn takes_a_mutable_reference(&self, a: &mut i32) {}
|
||||||
//~^ ERROR: this argument is a mutable reference, but not used mutably
|
|
||||||
//~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[warn(clippy::unnecessary_mut_passed)]
|
#[warn(clippy::unnecessary_mut_passed)]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: the function `takes_an_immutable_reference` doesn't need a mutable reference
|
error: the function `takes_an_immutable_reference` doesn't need a mutable reference
|
||||||
--> $DIR/mut_reference.rs:32:34
|
--> $DIR/mut_reference.rs:30:34
|
||||||
|
|
|
|
||||||
LL | takes_an_immutable_reference(&mut 42);
|
LL | takes_an_immutable_reference(&mut 42);
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
@ -8,25 +8,16 @@ LL | takes_an_immutable_reference(&mut 42);
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]`
|
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]`
|
||||||
|
|
||||||
error: the function `as_ptr` doesn't need a mutable reference
|
error: the function `as_ptr` doesn't need a mutable reference
|
||||||
--> $DIR/mut_reference.rs:36:12
|
--> $DIR/mut_reference.rs:34:12
|
||||||
|
|
|
|
||||||
LL | as_ptr(&mut 42);
|
LL | as_ptr(&mut 42);
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: the method `takes_an_immutable_reference` doesn't need a mutable reference
|
error: the method `takes_an_immutable_reference` doesn't need a mutable reference
|
||||||
--> $DIR/mut_reference.rs:41:44
|
--> $DIR/mut_reference.rs:39:44
|
||||||
|
|
|
|
||||||
LL | my_struct.takes_an_immutable_reference(&mut 42);
|
LL | my_struct.takes_an_immutable_reference(&mut 42);
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: aborting due to 3 previous errors
|
||||||
--> $DIR/mut_reference.rs:24:44
|
|
||||||
|
|
|
||||||
LL | fn takes_a_mutable_reference(&self, a: &mut i32) {}
|
|
||||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
|
||||||
|
|
|
||||||
= note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
|
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
/// unimplemented!();
|
/// unimplemented!();
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// With an explicit return type it should lint too
|
/// With an explicit return type it should lint too
|
||||||
/// ```edition2015
|
/// ```edition2015
|
||||||
/// fn main() -> () {
|
/// fn main() -> () {
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
/// unimplemented!();
|
/// unimplemented!();
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// This should, too.
|
/// This should, too.
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
/// unimplemented!();
|
/// unimplemented!();
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// This one too.
|
/// This one too.
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// // the fn is not always the first line
|
/// // the fn is not always the first line
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#![allow(clippy::if_same_then_else, clippy::no_effect, clippy::redundant_closure_call)]
|
#![allow(clippy::if_same_then_else, clippy::no_effect, clippy::redundant_closure_call)]
|
||||||
|
#![warn(clippy::needless_pass_by_ref_mut)]
|
||||||
#![feature(lint_reasons)]
|
#![feature(lint_reasons)]
|
||||||
//@no-rustfix
|
//@no-rustfix
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:6:11
|
--> $DIR/needless_pass_by_ref_mut.rs:7:11
|
||||||
|
|
|
|
||||||
LL | fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
|
LL | fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
|
||||||
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
|
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
|
||||||
|
@ -8,79 +8,79 @@ LL | fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
|
= help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:31:12
|
--> $DIR/needless_pass_by_ref_mut.rs:32:12
|
||||||
|
|
|
|
||||||
LL | fn foo6(s: &mut Vec<u32>) {
|
LL | fn foo6(s: &mut Vec<u32>) {
|
||||||
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
|
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:44:29
|
--> $DIR/needless_pass_by_ref_mut.rs:45:29
|
||||||
|
|
|
|
||||||
LL | fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
|
LL | fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
|
||||||
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
|
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:49:31
|
--> $DIR/needless_pass_by_ref_mut.rs:50:31
|
||||||
|
|
|
|
||||||
LL | fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
|
LL | fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
|
||||||
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
|
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:126:16
|
--> $DIR/needless_pass_by_ref_mut.rs:127:16
|
||||||
|
|
|
|
||||||
LL | async fn a1(x: &mut i32) {
|
LL | async fn a1(x: &mut i32) {
|
||||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:130:16
|
--> $DIR/needless_pass_by_ref_mut.rs:131:16
|
||||||
|
|
|
|
||||||
LL | async fn a2(x: &mut i32, y: String) {
|
LL | async fn a2(x: &mut i32, y: String) {
|
||||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:134:16
|
--> $DIR/needless_pass_by_ref_mut.rs:135:16
|
||||||
|
|
|
|
||||||
LL | async fn a3(x: &mut i32, y: String, z: String) {
|
LL | async fn a3(x: &mut i32, y: String, z: String) {
|
||||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:138:16
|
--> $DIR/needless_pass_by_ref_mut.rs:139:16
|
||||||
|
|
|
|
||||||
LL | async fn a4(x: &mut i32, y: i32) {
|
LL | async fn a4(x: &mut i32, y: i32) {
|
||||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:142:24
|
--> $DIR/needless_pass_by_ref_mut.rs:143:24
|
||||||
|
|
|
|
||||||
LL | async fn a5(x: i32, y: &mut i32) {
|
LL | async fn a5(x: i32, y: &mut i32) {
|
||||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:146:24
|
--> $DIR/needless_pass_by_ref_mut.rs:147:24
|
||||||
|
|
|
|
||||||
LL | async fn a6(x: i32, y: &mut i32) {
|
LL | async fn a6(x: i32, y: &mut i32) {
|
||||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:150:32
|
--> $DIR/needless_pass_by_ref_mut.rs:151:32
|
||||||
|
|
|
|
||||||
LL | async fn a7(x: i32, y: i32, z: &mut i32) {
|
LL | async fn a7(x: i32, y: i32, z: &mut i32) {
|
||||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:154:24
|
--> $DIR/needless_pass_by_ref_mut.rs:155:24
|
||||||
|
|
|
|
||||||
LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
|
LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
|
||||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:154:45
|
--> $DIR/needless_pass_by_ref_mut.rs:155:45
|
||||||
|
|
|
|
||||||
LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
|
LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
|
||||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:188:16
|
--> $DIR/needless_pass_by_ref_mut.rs:189:16
|
||||||
|
|
|
|
||||||
LL | fn cfg_warn(s: &mut u32) {}
|
LL | fn cfg_warn(s: &mut u32) {}
|
||||||
| ^^^^^^^^ help: consider changing to: `&u32`
|
| ^^^^^^^^ help: consider changing to: `&u32`
|
||||||
|
@ -88,7 +88,7 @@ LL | fn cfg_warn(s: &mut u32) {}
|
||||||
= note: this is cfg-gated and may require further changes
|
= note: this is cfg-gated and may require further changes
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:194:20
|
--> $DIR/needless_pass_by_ref_mut.rs:195:20
|
||||||
|
|
|
|
||||||
LL | fn cfg_warn(s: &mut u32) {}
|
LL | fn cfg_warn(s: &mut u32) {}
|
||||||
| ^^^^^^^^ help: consider changing to: `&u32`
|
| ^^^^^^^^ help: consider changing to: `&u32`
|
||||||
|
@ -96,19 +96,19 @@ LL | fn cfg_warn(s: &mut u32) {}
|
||||||
= note: this is cfg-gated and may require further changes
|
= note: this is cfg-gated and may require further changes
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:208:39
|
--> $DIR/needless_pass_by_ref_mut.rs:209:39
|
||||||
|
|
|
|
||||||
LL | async fn inner_async2(x: &mut i32, y: &mut u32) {
|
LL | async fn inner_async2(x: &mut i32, y: &mut u32) {
|
||||||
| ^^^^^^^^ help: consider changing to: `&u32`
|
| ^^^^^^^^ help: consider changing to: `&u32`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:216:26
|
--> $DIR/needless_pass_by_ref_mut.rs:217:26
|
||||||
|
|
|
|
||||||
LL | async fn inner_async3(x: &mut i32, y: &mut u32) {
|
LL | async fn inner_async3(x: &mut i32, y: &mut u32) {
|
||||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:235:34
|
--> $DIR/needless_pass_by_ref_mut.rs:236:34
|
||||||
|
|
|
|
||||||
LL | pub async fn call_in_closure1(n: &mut str) {
|
LL | pub async fn call_in_closure1(n: &mut str) {
|
||||||
| ^^^^^^^^ help: consider changing to: `&str`
|
| ^^^^^^^^ help: consider changing to: `&str`
|
||||||
|
@ -116,7 +116,7 @@ LL | pub async fn call_in_closure1(n: &mut str) {
|
||||||
= warning: changing this function will impact semver compatibility
|
= warning: changing this function will impact semver compatibility
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:247:25
|
--> $DIR/needless_pass_by_ref_mut.rs:248:25
|
||||||
|
|
|
|
||||||
LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() {
|
LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() {
|
||||||
| ^^^^^^^^^^ help: consider changing to: `&usize`
|
| ^^^^^^^^^^ help: consider changing to: `&usize`
|
||||||
|
@ -124,7 +124,7 @@ LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() {
|
||||||
= warning: changing this function will impact semver compatibility
|
= warning: changing this function will impact semver compatibility
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:254:20
|
--> $DIR/needless_pass_by_ref_mut.rs:255:20
|
||||||
|
|
|
|
||||||
LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
|
LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
|
||||||
| ^^^^^^^^^^ help: consider changing to: `&usize`
|
| ^^^^^^^^^^ help: consider changing to: `&usize`
|
||||||
|
@ -132,7 +132,7 @@ LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
|
||||||
= warning: changing this function will impact semver compatibility
|
= warning: changing this function will impact semver compatibility
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: this argument is a mutable reference, but not used mutably
|
||||||
--> $DIR/needless_pass_by_ref_mut.rs:265:26
|
--> $DIR/needless_pass_by_ref_mut.rs:266:26
|
||||||
|
|
|
|
||||||
LL | pub async fn closure4(n: &mut usize) {
|
LL | pub async fn closure4(n: &mut usize) {
|
||||||
| ^^^^^^^^^^ help: consider changing to: `&usize`
|
| ^^^^^^^^^^ help: consider changing to: `&usize`
|
||||||
|
|
|
@ -18,4 +18,8 @@ fn main() {
|
||||||
multiline
|
multiline
|
||||||
string
|
string
|
||||||
";
|
";
|
||||||
|
|
||||||
|
"no hashes";
|
||||||
|
b"no hashes";
|
||||||
|
c"no hashes";
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,4 +18,8 @@ fn main() {
|
||||||
multiline
|
multiline
|
||||||
string
|
string
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
r"no hashes";
|
||||||
|
br"no hashes";
|
||||||
|
cr"no hashes";
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ LL | r#"aaa"#;
|
||||||
|
|
|
|
||||||
= note: `-D clippy::needless-raw-strings` implied by `-D warnings`
|
= note: `-D clippy::needless-raw-strings` implied by `-D warnings`
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::needless_raw_strings)]`
|
= help: to override `-D warnings` add `#[allow(clippy::needless_raw_strings)]`
|
||||||
help: try
|
help: use a plain string literal instead
|
||||||
|
|
|
|
||||||
LL - r#"aaa"#;
|
LL - r#"aaa"#;
|
||||||
LL + "aaa";
|
LL + "aaa";
|
||||||
|
@ -18,7 +18,7 @@ error: unnecessary raw string literal
|
||||||
LL | br#"aaa"#;
|
LL | br#"aaa"#;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: try
|
help: use a plain byte string literal instead
|
||||||
|
|
|
|
||||||
LL - br#"aaa"#;
|
LL - br#"aaa"#;
|
||||||
LL + b"aaa";
|
LL + b"aaa";
|
||||||
|
@ -30,7 +30,7 @@ error: unnecessary raw string literal
|
||||||
LL | cr#"aaa"#;
|
LL | cr#"aaa"#;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: try
|
help: use a plain C string literal instead
|
||||||
|
|
|
|
||||||
LL - cr#"aaa"#;
|
LL - cr#"aaa"#;
|
||||||
LL + c"aaa";
|
LL + c"aaa";
|
||||||
|
@ -46,7 +46,7 @@ LL | | string
|
||||||
LL | | "#;
|
LL | | "#;
|
||||||
| |______^
|
| |______^
|
||||||
|
|
|
|
||||||
help: try
|
help: use a plain string literal instead
|
||||||
|
|
|
|
||||||
LL ~ "
|
LL ~ "
|
||||||
LL | a
|
LL | a
|
||||||
|
@ -55,5 +55,41 @@ LL | string
|
||||||
LL ~ ";
|
LL ~ ";
|
||||||
|
|
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: unnecessary raw string literal
|
||||||
|
--> $DIR/needless_raw_string.rs:22:5
|
||||||
|
|
|
||||||
|
LL | r"no hashes";
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use a plain string literal instead
|
||||||
|
|
|
||||||
|
LL - r"no hashes";
|
||||||
|
LL + "no hashes";
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unnecessary raw string literal
|
||||||
|
--> $DIR/needless_raw_string.rs:23:5
|
||||||
|
|
|
||||||
|
LL | br"no hashes";
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use a plain byte string literal instead
|
||||||
|
|
|
||||||
|
LL - br"no hashes";
|
||||||
|
LL + b"no hashes";
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unnecessary raw string literal
|
||||||
|
--> $DIR/needless_raw_string.rs:24:5
|
||||||
|
|
|
||||||
|
LL | cr"no hashes";
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use a plain C string literal instead
|
||||||
|
|
|
||||||
|
LL - cr"no hashes";
|
||||||
|
LL + c"no hashes";
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ LL | r#"\aaa"#;
|
||||||
|
|
|
|
||||||
= note: `-D clippy::needless-raw-string-hashes` implied by `-D warnings`
|
= note: `-D clippy::needless-raw-string-hashes` implied by `-D warnings`
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::needless_raw_string_hashes)]`
|
= help: to override `-D warnings` add `#[allow(clippy::needless_raw_string_hashes)]`
|
||||||
help: remove all the hashes around the literal
|
help: remove all the hashes around the string literal
|
||||||
|
|
|
|
||||||
LL - r#"\aaa"#;
|
LL - r#"\aaa"#;
|
||||||
LL + r"\aaa";
|
LL + r"\aaa";
|
||||||
|
@ -18,7 +18,7 @@ error: unnecessary hashes around raw string literal
|
||||||
LL | r##"Hello "world"!"##;
|
LL | r##"Hello "world"!"##;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: remove one hash from both sides of the literal
|
help: remove one hash from both sides of the string literal
|
||||||
|
|
|
|
||||||
LL - r##"Hello "world"!"##;
|
LL - r##"Hello "world"!"##;
|
||||||
LL + r#"Hello "world"!"#;
|
LL + r#"Hello "world"!"#;
|
||||||
|
@ -30,7 +30,7 @@ error: unnecessary hashes around raw string literal
|
||||||
LL | r######" "### "## "# "######;
|
LL | r######" "### "## "# "######;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: remove 2 hashes from both sides of the literal
|
help: remove 2 hashes from both sides of the string literal
|
||||||
|
|
|
|
||||||
LL - r######" "### "## "# "######;
|
LL - r######" "### "## "# "######;
|
||||||
LL + r####" "### "## "# "####;
|
LL + r####" "### "## "# "####;
|
||||||
|
@ -42,7 +42,7 @@ error: unnecessary hashes around raw string literal
|
||||||
LL | r######" "aa" "# "## "######;
|
LL | r######" "aa" "# "## "######;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: remove 3 hashes from both sides of the literal
|
help: remove 3 hashes from both sides of the string literal
|
||||||
|
|
|
|
||||||
LL - r######" "aa" "# "## "######;
|
LL - r######" "aa" "# "## "######;
|
||||||
LL + r###" "aa" "# "## "###;
|
LL + r###" "aa" "# "## "###;
|
||||||
|
@ -54,7 +54,7 @@ error: unnecessary hashes around raw string literal
|
||||||
LL | br#"\aaa"#;
|
LL | br#"\aaa"#;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: remove all the hashes around the literal
|
help: remove all the hashes around the byte string literal
|
||||||
|
|
|
|
||||||
LL - br#"\aaa"#;
|
LL - br#"\aaa"#;
|
||||||
LL + br"\aaa";
|
LL + br"\aaa";
|
||||||
|
@ -66,7 +66,7 @@ error: unnecessary hashes around raw string literal
|
||||||
LL | br##"Hello "world"!"##;
|
LL | br##"Hello "world"!"##;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: remove one hash from both sides of the literal
|
help: remove one hash from both sides of the byte string literal
|
||||||
|
|
|
|
||||||
LL - br##"Hello "world"!"##;
|
LL - br##"Hello "world"!"##;
|
||||||
LL + br#"Hello "world"!"#;
|
LL + br#"Hello "world"!"#;
|
||||||
|
@ -78,7 +78,7 @@ error: unnecessary hashes around raw string literal
|
||||||
LL | br######" "### "## "# "######;
|
LL | br######" "### "## "# "######;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: remove 2 hashes from both sides of the literal
|
help: remove 2 hashes from both sides of the byte string literal
|
||||||
|
|
|
|
||||||
LL - br######" "### "## "# "######;
|
LL - br######" "### "## "# "######;
|
||||||
LL + br####" "### "## "# "####;
|
LL + br####" "### "## "# "####;
|
||||||
|
@ -90,7 +90,7 @@ error: unnecessary hashes around raw string literal
|
||||||
LL | br######" "aa" "# "## "######;
|
LL | br######" "aa" "# "## "######;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: remove 3 hashes from both sides of the literal
|
help: remove 3 hashes from both sides of the byte string literal
|
||||||
|
|
|
|
||||||
LL - br######" "aa" "# "## "######;
|
LL - br######" "aa" "# "## "######;
|
||||||
LL + br###" "aa" "# "## "###;
|
LL + br###" "aa" "# "## "###;
|
||||||
|
@ -102,7 +102,7 @@ error: unnecessary hashes around raw string literal
|
||||||
LL | cr#"\aaa"#;
|
LL | cr#"\aaa"#;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: remove all the hashes around the literal
|
help: remove all the hashes around the C string literal
|
||||||
|
|
|
|
||||||
LL - cr#"\aaa"#;
|
LL - cr#"\aaa"#;
|
||||||
LL + cr"\aaa";
|
LL + cr"\aaa";
|
||||||
|
@ -114,7 +114,7 @@ error: unnecessary hashes around raw string literal
|
||||||
LL | cr##"Hello "world"!"##;
|
LL | cr##"Hello "world"!"##;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: remove one hash from both sides of the literal
|
help: remove one hash from both sides of the C string literal
|
||||||
|
|
|
|
||||||
LL - cr##"Hello "world"!"##;
|
LL - cr##"Hello "world"!"##;
|
||||||
LL + cr#"Hello "world"!"#;
|
LL + cr#"Hello "world"!"#;
|
||||||
|
@ -126,7 +126,7 @@ error: unnecessary hashes around raw string literal
|
||||||
LL | cr######" "### "## "# "######;
|
LL | cr######" "### "## "# "######;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: remove 2 hashes from both sides of the literal
|
help: remove 2 hashes from both sides of the C string literal
|
||||||
|
|
|
|
||||||
LL - cr######" "### "## "# "######;
|
LL - cr######" "### "## "# "######;
|
||||||
LL + cr####" "### "## "# "####;
|
LL + cr####" "### "## "# "####;
|
||||||
|
@ -138,7 +138,7 @@ error: unnecessary hashes around raw string literal
|
||||||
LL | cr######" "aa" "# "## "######;
|
LL | cr######" "aa" "# "## "######;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: remove 3 hashes from both sides of the literal
|
help: remove 3 hashes from both sides of the C string literal
|
||||||
|
|
|
|
||||||
LL - cr######" "aa" "# "## "######;
|
LL - cr######" "aa" "# "## "######;
|
||||||
LL + cr###" "aa" "# "## "###;
|
LL + cr###" "aa" "# "## "###;
|
||||||
|
@ -154,7 +154,7 @@ LL | | string
|
||||||
LL | | "#;
|
LL | | "#;
|
||||||
| |______^
|
| |______^
|
||||||
|
|
|
|
||||||
help: remove all the hashes around the literal
|
help: remove all the hashes around the string literal
|
||||||
|
|
|
|
||||||
LL ~ r"
|
LL ~ r"
|
||||||
LL | \a
|
LL | \a
|
||||||
|
@ -169,7 +169,7 @@ error: unnecessary hashes around raw string literal
|
||||||
LL | r###"rust"###;
|
LL | r###"rust"###;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: remove all the hashes around the literal
|
help: remove all the hashes around the string literal
|
||||||
|
|
|
|
||||||
LL - r###"rust"###;
|
LL - r###"rust"###;
|
||||||
LL + r"rust";
|
LL + r"rust";
|
||||||
|
@ -181,7 +181,7 @@ error: unnecessary hashes around raw string literal
|
||||||
LL | r#"hello world"#;
|
LL | r#"hello world"#;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: remove all the hashes around the literal
|
help: remove all the hashes around the string literal
|
||||||
|
|
|
|
||||||
LL - r#"hello world"#;
|
LL - r#"hello world"#;
|
||||||
LL + r"hello world";
|
LL + r"hello world";
|
||||||
|
|
|
@ -39,20 +39,30 @@ fn main() {
|
||||||
// throw a warning
|
// throw a warning
|
||||||
println!("hello world");
|
println!("hello world");
|
||||||
//~^ ERROR: literal with an empty format string
|
//~^ ERROR: literal with an empty format string
|
||||||
//~| ERROR: literal with an empty format string
|
|
||||||
println!("world hello");
|
println!("world hello");
|
||||||
//~^ ERROR: literal with an empty format string
|
//~^ ERROR: literal with an empty format string
|
||||||
//~| ERROR: literal with an empty format string
|
|
||||||
|
|
||||||
// named args shouldn't change anything either
|
// named args shouldn't change anything either
|
||||||
println!("hello world");
|
println!("hello world");
|
||||||
//~^ ERROR: literal with an empty format string
|
//~^ ERROR: literal with an empty format string
|
||||||
//~| ERROR: literal with an empty format string
|
|
||||||
println!("world hello");
|
println!("world hello");
|
||||||
//~^ ERROR: literal with an empty format string
|
//~^ ERROR: literal with an empty format string
|
||||||
//~| ERROR: literal with an empty format string
|
|
||||||
|
|
||||||
// The string literal from `file!()` has a callsite span that isn't marked as coming from an
|
// The string literal from `file!()` has a callsite span that isn't marked as coming from an
|
||||||
// expansion
|
// expansion
|
||||||
println!("file: {}", file!());
|
println!("file: {}", file!());
|
||||||
|
|
||||||
|
// Braces in unicode escapes should not be escaped
|
||||||
|
println!("{{}} \x00 \u{ab123} \\\u{ab123} {{:?}}");
|
||||||
|
println!("\\\u{1234}");
|
||||||
|
// This does not lint because it would have to suggest unescaping the character
|
||||||
|
println!(r"{}", "\u{ab123}");
|
||||||
|
// These are not unicode escapes
|
||||||
|
println!("\\u{{ab123}} \\u{{{{");
|
||||||
|
println!(r"\u{{ab123}} \u{{{{");
|
||||||
|
println!("\\{{ab123}} \\u{{{{");
|
||||||
|
println!("\\u{{ab123}}");
|
||||||
|
println!("\\\\u{{1234}}");
|
||||||
|
|
||||||
|
println!("mixed: {{hello}} {world}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,20 +39,30 @@ fn main() {
|
||||||
// throw a warning
|
// throw a warning
|
||||||
println!("{0} {1}", "hello", "world");
|
println!("{0} {1}", "hello", "world");
|
||||||
//~^ ERROR: literal with an empty format string
|
//~^ ERROR: literal with an empty format string
|
||||||
//~| ERROR: literal with an empty format string
|
|
||||||
println!("{1} {0}", "hello", "world");
|
println!("{1} {0}", "hello", "world");
|
||||||
//~^ ERROR: literal with an empty format string
|
//~^ ERROR: literal with an empty format string
|
||||||
//~| ERROR: literal with an empty format string
|
|
||||||
|
|
||||||
// named args shouldn't change anything either
|
// named args shouldn't change anything either
|
||||||
println!("{foo} {bar}", foo = "hello", bar = "world");
|
println!("{foo} {bar}", foo = "hello", bar = "world");
|
||||||
//~^ ERROR: literal with an empty format string
|
//~^ ERROR: literal with an empty format string
|
||||||
//~| ERROR: literal with an empty format string
|
|
||||||
println!("{bar} {foo}", foo = "hello", bar = "world");
|
println!("{bar} {foo}", foo = "hello", bar = "world");
|
||||||
//~^ ERROR: literal with an empty format string
|
//~^ ERROR: literal with an empty format string
|
||||||
//~| ERROR: literal with an empty format string
|
|
||||||
|
|
||||||
// The string literal from `file!()` has a callsite span that isn't marked as coming from an
|
// The string literal from `file!()` has a callsite span that isn't marked as coming from an
|
||||||
// expansion
|
// expansion
|
||||||
println!("file: {}", file!());
|
println!("file: {}", file!());
|
||||||
|
|
||||||
|
// Braces in unicode escapes should not be escaped
|
||||||
|
println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}");
|
||||||
|
println!("{}", "\\\u{1234}");
|
||||||
|
// This does not lint because it would have to suggest unescaping the character
|
||||||
|
println!(r"{}", "\u{ab123}");
|
||||||
|
// These are not unicode escapes
|
||||||
|
println!("{}", r"\u{ab123} \u{{");
|
||||||
|
println!(r"{}", r"\u{ab123} \u{{");
|
||||||
|
println!("{}", r"\{ab123} \u{{");
|
||||||
|
println!("{}", "\\u{ab123}");
|
||||||
|
println!("{}", "\\\\u{1234}");
|
||||||
|
|
||||||
|
println!("mixed: {} {world}", "{hello}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,97 +52,145 @@ error: literal with an empty format string
|
||||||
--> $DIR/print_literal.rs:40:25
|
--> $DIR/print_literal.rs:40:25
|
||||||
|
|
|
|
||||||
LL | println!("{0} {1}", "hello", "world");
|
LL | println!("{0} {1}", "hello", "world");
|
||||||
| ^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: try
|
help: try
|
||||||
|
|
|
|
||||||
LL - println!("{0} {1}", "hello", "world");
|
LL - println!("{0} {1}", "hello", "world");
|
||||||
LL + println!("hello {1}", "world");
|
LL + println!("hello world");
|
||||||
|
|
|
|
||||||
|
|
||||||
error: literal with an empty format string
|
error: literal with an empty format string
|
||||||
--> $DIR/print_literal.rs:40:34
|
--> $DIR/print_literal.rs:42:25
|
||||||
|
|
|
||||||
LL | println!("{0} {1}", "hello", "world");
|
|
||||||
| ^^^^^^^
|
|
||||||
|
|
|
||||||
help: try
|
|
||||||
|
|
|
||||||
LL - println!("{0} {1}", "hello", "world");
|
|
||||||
LL + println!("{0} world", "hello");
|
|
||||||
|
|
|
||||||
|
|
||||||
error: literal with an empty format string
|
|
||||||
--> $DIR/print_literal.rs:43:34
|
|
||||||
|
|
|
|
||||||
LL | println!("{1} {0}", "hello", "world");
|
LL | println!("{1} {0}", "hello", "world");
|
||||||
| ^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: try
|
help: try
|
||||||
|
|
|
|
||||||
LL - println!("{1} {0}", "hello", "world");
|
LL - println!("{1} {0}", "hello", "world");
|
||||||
LL + println!("world {0}", "hello");
|
LL + println!("world hello");
|
||||||
|
|
|
|
||||||
|
|
||||||
error: literal with an empty format string
|
error: literal with an empty format string
|
||||||
--> $DIR/print_literal.rs:43:25
|
--> $DIR/print_literal.rs:46:35
|
||||||
|
|
|
|
||||||
LL | println!("{1} {0}", "hello", "world");
|
LL | println!("{foo} {bar}", foo = "hello", bar = "world");
|
||||||
| ^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: try
|
help: try
|
||||||
|
|
|
|
||||||
LL - println!("{1} {0}", "hello", "world");
|
LL - println!("{foo} {bar}", foo = "hello", bar = "world");
|
||||||
LL + println!("{1} hello", "world");
|
LL + println!("hello world");
|
||||||
|
|
|
|
||||||
|
|
||||||
error: literal with an empty format string
|
error: literal with an empty format string
|
||||||
--> $DIR/print_literal.rs:48:35
|
--> $DIR/print_literal.rs:48:35
|
||||||
|
|
|
|
||||||
LL | println!("{foo} {bar}", foo = "hello", bar = "world");
|
|
||||||
| ^^^^^^^
|
|
||||||
|
|
|
||||||
help: try
|
|
||||||
|
|
|
||||||
LL - println!("{foo} {bar}", foo = "hello", bar = "world");
|
|
||||||
LL + println!("hello {bar}", bar = "world");
|
|
||||||
|
|
|
||||||
|
|
||||||
error: literal with an empty format string
|
|
||||||
--> $DIR/print_literal.rs:48:50
|
|
||||||
|
|
|
||||||
LL | println!("{foo} {bar}", foo = "hello", bar = "world");
|
|
||||||
| ^^^^^^^
|
|
||||||
|
|
|
||||||
help: try
|
|
||||||
|
|
|
||||||
LL - println!("{foo} {bar}", foo = "hello", bar = "world");
|
|
||||||
LL + println!("{foo} world", foo = "hello");
|
|
||||||
|
|
|
||||||
|
|
||||||
error: literal with an empty format string
|
|
||||||
--> $DIR/print_literal.rs:51:50
|
|
||||||
|
|
|
||||||
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
|
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
|
||||||
| ^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: try
|
help: try
|
||||||
|
|
|
|
||||||
LL - println!("{bar} {foo}", foo = "hello", bar = "world");
|
LL - println!("{bar} {foo}", foo = "hello", bar = "world");
|
||||||
LL + println!("world {foo}", foo = "hello");
|
LL + println!("world hello");
|
||||||
|
|
|
|
||||||
|
|
||||||
error: literal with an empty format string
|
error: literal with an empty format string
|
||||||
--> $DIR/print_literal.rs:51:35
|
--> $DIR/print_literal.rs:56:20
|
||||||
|
|
|
|
||||||
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
|
LL | println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}");
|
||||||
| ^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: try
|
help: try
|
||||||
|
|
|
|
||||||
LL - println!("{bar} {foo}", foo = "hello", bar = "world");
|
LL - println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}");
|
||||||
LL + println!("{bar} hello", bar = "world");
|
LL + println!("{{}} \x00 \u{ab123} \\\u{ab123} {{:?}}");
|
||||||
|
|
|
|
||||||
|
|
||||||
error: aborting due to 12 previous errors
|
error: literal with an empty format string
|
||||||
|
--> $DIR/print_literal.rs:57:20
|
||||||
|
|
|
||||||
|
LL | println!("{}", "\\\u{1234}");
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: try
|
||||||
|
|
|
||||||
|
LL - println!("{}", "\\\u{1234}");
|
||||||
|
LL + println!("\\\u{1234}");
|
||||||
|
|
|
||||||
|
|
||||||
|
error: literal with an empty format string
|
||||||
|
--> $DIR/print_literal.rs:61:20
|
||||||
|
|
|
||||||
|
LL | println!("{}", r"\u{ab123} \u{{");
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: try
|
||||||
|
|
|
||||||
|
LL - println!("{}", r"\u{ab123} \u{{");
|
||||||
|
LL + println!("\\u{{ab123}} \\u{{{{");
|
||||||
|
|
|
||||||
|
|
||||||
|
error: literal with an empty format string
|
||||||
|
--> $DIR/print_literal.rs:62:21
|
||||||
|
|
|
||||||
|
LL | println!(r"{}", r"\u{ab123} \u{{");
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: try
|
||||||
|
|
|
||||||
|
LL - println!(r"{}", r"\u{ab123} \u{{");
|
||||||
|
LL + println!(r"\u{{ab123}} \u{{{{");
|
||||||
|
|
|
||||||
|
|
||||||
|
error: literal with an empty format string
|
||||||
|
--> $DIR/print_literal.rs:63:20
|
||||||
|
|
|
||||||
|
LL | println!("{}", r"\{ab123} \u{{");
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: try
|
||||||
|
|
|
||||||
|
LL - println!("{}", r"\{ab123} \u{{");
|
||||||
|
LL + println!("\\{{ab123}} \\u{{{{");
|
||||||
|
|
|
||||||
|
|
||||||
|
error: literal with an empty format string
|
||||||
|
--> $DIR/print_literal.rs:64:20
|
||||||
|
|
|
||||||
|
LL | println!("{}", "\\u{ab123}");
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: try
|
||||||
|
|
|
||||||
|
LL - println!("{}", "\\u{ab123}");
|
||||||
|
LL + println!("\\u{{ab123}}");
|
||||||
|
|
|
||||||
|
|
||||||
|
error: literal with an empty format string
|
||||||
|
--> $DIR/print_literal.rs:65:20
|
||||||
|
|
|
||||||
|
LL | println!("{}", "\\\\u{1234}");
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: try
|
||||||
|
|
|
||||||
|
LL - println!("{}", "\\\\u{1234}");
|
||||||
|
LL + println!("\\\\u{{1234}}");
|
||||||
|
|
|
||||||
|
|
||||||
|
error: literal with an empty format string
|
||||||
|
--> $DIR/print_literal.rs:67:35
|
||||||
|
|
|
||||||
|
LL | println!("mixed: {} {world}", "{hello}");
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: try
|
||||||
|
|
|
||||||
|
LL - println!("mixed: {} {world}", "{hello}");
|
||||||
|
LL + println!("mixed: {{hello}} {world}");
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 16 previous errors
|
||||||
|
|
||||||
|
|
|
@ -118,3 +118,40 @@ fn macros() {
|
||||||
let x = x;
|
let x = x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct WithDrop(usize);
|
||||||
|
impl Drop for WithDrop {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InnerDrop(WithDrop);
|
||||||
|
|
||||||
|
struct ComposeDrop {
|
||||||
|
d: WithDrop,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WithoutDrop(usize);
|
||||||
|
|
||||||
|
fn drop_trait() {
|
||||||
|
let a = WithDrop(1);
|
||||||
|
let b = WithDrop(2);
|
||||||
|
let a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn without_drop() {
|
||||||
|
let a = WithoutDrop(1);
|
||||||
|
let b = WithoutDrop(2);
|
||||||
|
let a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drop_inner() {
|
||||||
|
let a = InnerDrop(WithDrop(1));
|
||||||
|
let b = InnerDrop(WithDrop(2));
|
||||||
|
let a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drop_compose() {
|
||||||
|
let a = ComposeDrop { d: WithDrop(1) };
|
||||||
|
let b = ComposeDrop { d: WithDrop(1) };
|
||||||
|
let a = a;
|
||||||
|
}
|
||||||
|
|
|
@ -1,137 +1,172 @@
|
||||||
error: redundant redefinition of a binding
|
error: redundant redefinition of a binding `x`
|
||||||
|
--> $DIR/redundant_locals.rs:12:5
|
||||||
|
|
|
||||||
|
LL | let x = x;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: `x` is initially defined here
|
||||||
--> $DIR/redundant_locals.rs:11:9
|
--> $DIR/redundant_locals.rs:11:9
|
||||||
|
|
|
|
||||||
LL | let x = 1;
|
LL | let x = 1;
|
||||||
| ^
|
| ^
|
||||||
LL | let x = x;
|
|
||||||
| ^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= help: remove the redefinition of `x`
|
|
||||||
= note: `-D clippy::redundant-locals` implied by `-D warnings`
|
= note: `-D clippy::redundant-locals` implied by `-D warnings`
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::redundant_locals)]`
|
= help: to override `-D warnings` add `#[allow(clippy::redundant_locals)]`
|
||||||
|
|
||||||
error: redundant redefinition of a binding
|
error: redundant redefinition of a binding `x`
|
||||||
|
--> $DIR/redundant_locals.rs:17:5
|
||||||
|
|
|
||||||
|
LL | let mut x = x;
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: `x` is initially defined here
|
||||||
--> $DIR/redundant_locals.rs:16:9
|
--> $DIR/redundant_locals.rs:16:9
|
||||||
|
|
|
|
||||||
LL | let mut x = 1;
|
LL | let mut x = 1;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
LL | let mut x = x;
|
|
||||||
| ^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= help: remove the redefinition of `x`
|
|
||||||
|
|
||||||
error: redundant redefinition of a binding
|
error: redundant redefinition of a binding `x`
|
||||||
|
--> $DIR/redundant_locals.rs:47:5
|
||||||
|
|
|
||||||
|
LL | let x = x;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: `x` is initially defined here
|
||||||
--> $DIR/redundant_locals.rs:46:14
|
--> $DIR/redundant_locals.rs:46:14
|
||||||
|
|
|
|
||||||
LL | fn parameter(x: i32) {
|
LL | fn parameter(x: i32) {
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
|
error: redundant redefinition of a binding `x`
|
||||||
|
--> $DIR/redundant_locals.rs:52:5
|
||||||
|
|
|
||||||
LL | let x = x;
|
LL | let x = x;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: remove the redefinition of `x`
|
help: `x` is initially defined here
|
||||||
|
|
||||||
error: redundant redefinition of a binding
|
|
||||||
--> $DIR/redundant_locals.rs:51:9
|
--> $DIR/redundant_locals.rs:51:9
|
||||||
|
|
|
|
||||||
LL | let x = 1;
|
LL | let x = 1;
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
|
error: redundant redefinition of a binding `x`
|
||||||
|
--> $DIR/redundant_locals.rs:53:5
|
||||||
|
|
|
||||||
LL | let x = x;
|
LL | let x = x;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: remove the redefinition of `x`
|
help: `x` is initially defined here
|
||||||
|
|
||||||
error: redundant redefinition of a binding
|
|
||||||
--> $DIR/redundant_locals.rs:52:9
|
--> $DIR/redundant_locals.rs:52:9
|
||||||
|
|
|
|
||||||
LL | let x = x;
|
LL | let x = x;
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
|
error: redundant redefinition of a binding `x`
|
||||||
|
--> $DIR/redundant_locals.rs:54:5
|
||||||
|
|
|
||||||
LL | let x = x;
|
LL | let x = x;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: remove the redefinition of `x`
|
help: `x` is initially defined here
|
||||||
|
|
||||||
error: redundant redefinition of a binding
|
|
||||||
--> $DIR/redundant_locals.rs:53:9
|
--> $DIR/redundant_locals.rs:53:9
|
||||||
|
|
|
|
||||||
LL | let x = x;
|
LL | let x = x;
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
|
error: redundant redefinition of a binding `x`
|
||||||
|
--> $DIR/redundant_locals.rs:55:5
|
||||||
|
|
|
||||||
LL | let x = x;
|
LL | let x = x;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: remove the redefinition of `x`
|
help: `x` is initially defined here
|
||||||
|
|
||||||
error: redundant redefinition of a binding
|
|
||||||
--> $DIR/redundant_locals.rs:54:9
|
--> $DIR/redundant_locals.rs:54:9
|
||||||
|
|
|
|
||||||
LL | let x = x;
|
LL | let x = x;
|
||||||
| ^
|
| ^
|
||||||
LL | let x = x;
|
|
||||||
|
error: redundant redefinition of a binding `a`
|
||||||
|
--> $DIR/redundant_locals.rs:61:5
|
||||||
|
|
|
||||||
|
LL | let a = a;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: remove the redefinition of `x`
|
help: `a` is initially defined here
|
||||||
|
|
||||||
error: redundant redefinition of a binding
|
|
||||||
--> $DIR/redundant_locals.rs:59:9
|
--> $DIR/redundant_locals.rs:59:9
|
||||||
|
|
|
|
||||||
LL | let a = 1;
|
LL | let a = 1;
|
||||||
| ^
|
| ^
|
||||||
LL | let b = 2;
|
|
||||||
LL | let a = a;
|
error: redundant redefinition of a binding `b`
|
||||||
|
--> $DIR/redundant_locals.rs:62:5
|
||||||
|
|
|
||||||
|
LL | let b = b;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: remove the redefinition of `a`
|
help: `b` is initially defined here
|
||||||
|
|
||||||
error: redundant redefinition of a binding
|
|
||||||
--> $DIR/redundant_locals.rs:60:9
|
--> $DIR/redundant_locals.rs:60:9
|
||||||
|
|
|
|
||||||
LL | let b = 2;
|
LL | let b = 2;
|
||||||
| ^
|
| ^
|
||||||
LL | let a = a;
|
|
||||||
LL | let b = b;
|
|
||||||
| ^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= help: remove the redefinition of `b`
|
|
||||||
|
|
||||||
error: redundant redefinition of a binding
|
error: redundant redefinition of a binding `x`
|
||||||
|
--> $DIR/redundant_locals.rs:68:9
|
||||||
|
|
|
||||||
|
LL | let x = x;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: `x` is initially defined here
|
||||||
--> $DIR/redundant_locals.rs:67:13
|
--> $DIR/redundant_locals.rs:67:13
|
||||||
|
|
|
|
||||||
LL | let x = 1;
|
LL | let x = 1;
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
|
error: redundant redefinition of a binding `x`
|
||||||
|
--> $DIR/redundant_locals.rs:75:9
|
||||||
|
|
|
||||||
LL | let x = x;
|
LL | let x = x;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: remove the redefinition of `x`
|
help: `x` is initially defined here
|
||||||
|
|
||||||
error: redundant redefinition of a binding
|
|
||||||
--> $DIR/redundant_locals.rs:74:13
|
--> $DIR/redundant_locals.rs:74:13
|
||||||
|
|
|
|
||||||
LL | let x = 1;
|
LL | let x = 1;
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
|
error: redundant redefinition of a binding `x`
|
||||||
|
--> $DIR/redundant_locals.rs:78:9
|
||||||
|
|
|
||||||
LL | let x = x;
|
LL | let x = x;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: remove the redefinition of `x`
|
help: `x` is initially defined here
|
||||||
|
|
||||||
error: redundant redefinition of a binding
|
|
||||||
--> $DIR/redundant_locals.rs:77:6
|
--> $DIR/redundant_locals.rs:77:6
|
||||||
|
|
|
|
||||||
LL | |x: i32| {
|
LL | |x: i32| {
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
|
error: redundant redefinition of a binding `x`
|
||||||
|
--> $DIR/redundant_locals.rs:97:9
|
||||||
|
|
|
||||||
LL | let x = x;
|
LL | let x = x;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: remove the redefinition of `x`
|
help: `x` is initially defined here
|
||||||
|
|
||||||
error: redundant redefinition of a binding
|
|
||||||
--> $DIR/redundant_locals.rs:94:9
|
--> $DIR/redundant_locals.rs:94:9
|
||||||
|
|
|
|
||||||
LL | let x = 1;
|
LL | let x = 1;
|
||||||
| ^
|
| ^
|
||||||
...
|
|
||||||
LL | let x = x;
|
error: redundant redefinition of a binding `a`
|
||||||
| ^^^^^^^^^^
|
--> $DIR/redundant_locals.rs:144:5
|
||||||
|
|
|
|
||||||
= help: remove the redefinition of `x`
|
LL | let a = a;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: `a` is initially defined here
|
||||||
|
--> $DIR/redundant_locals.rs:142:9
|
||||||
|
|
|
||||||
|
LL | let a = WithoutDrop(1);
|
||||||
|
| ^
|
||||||
|
|
||||||
error: aborting due to 13 previous errors
|
error: aborting due to 14 previous errors
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,6 @@ impl T {
|
||||||
|
|
||||||
pub fn hash(&self, state: &mut T) {
|
pub fn hash(&self, state: &mut T) {
|
||||||
//~^ ERROR: method `hash` can be confused for the standard trait method `std::hash::Ha
|
//~^ ERROR: method `hash` can be confused for the standard trait method `std::hash::Ha
|
||||||
//~| ERROR: this argument is a mutable reference, but not used mutably
|
|
||||||
//~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,6 @@ error: method `hash` can be confused for the standard trait method `std::hash::H
|
||||||
|
|
|
|
||||||
LL | / pub fn hash(&self, state: &mut T) {
|
LL | / pub fn hash(&self, state: &mut T) {
|
||||||
LL | |
|
LL | |
|
||||||
LL | |
|
|
||||||
LL | |
|
|
||||||
LL | | unimplemented!()
|
LL | | unimplemented!()
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
@ -47,7 +45,7 @@ LL | | }
|
||||||
= help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
|
= help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
|
||||||
|
|
||||||
error: method `index` can be confused for the standard trait method `std::ops::Index::index`
|
error: method `index` can be confused for the standard trait method `std::ops::Index::index`
|
||||||
--> $DIR/method_list_2.rs:48:5
|
--> $DIR/method_list_2.rs:46:5
|
||||||
|
|
|
|
||||||
LL | / pub fn index(&self, index: usize) -> &Self {
|
LL | / pub fn index(&self, index: usize) -> &Self {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -58,7 +56,7 @@ LL | | }
|
||||||
= help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
|
= help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
|
||||||
|
|
||||||
error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
|
error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
|
||||||
--> $DIR/method_list_2.rs:53:5
|
--> $DIR/method_list_2.rs:51:5
|
||||||
|
|
|
|
||||||
LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self {
|
LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -69,7 +67,7 @@ LL | | }
|
||||||
= help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
|
= help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
|
||||||
|
|
||||||
error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
|
error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
|
||||||
--> $DIR/method_list_2.rs:58:5
|
--> $DIR/method_list_2.rs:56:5
|
||||||
|
|
|
|
||||||
LL | / pub fn into_iter(self) -> Self {
|
LL | / pub fn into_iter(self) -> Self {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -80,7 +78,7 @@ LL | | }
|
||||||
= help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
|
= help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
|
||||||
|
|
||||||
error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
|
error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
|
||||||
--> $DIR/method_list_2.rs:63:5
|
--> $DIR/method_list_2.rs:61:5
|
||||||
|
|
|
|
||||||
LL | / pub fn mul(self, rhs: Self) -> Self {
|
LL | / pub fn mul(self, rhs: Self) -> Self {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -91,7 +89,7 @@ LL | | }
|
||||||
= help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
|
= help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
|
||||||
|
|
||||||
error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
|
error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
|
||||||
--> $DIR/method_list_2.rs:68:5
|
--> $DIR/method_list_2.rs:66:5
|
||||||
|
|
|
|
||||||
LL | / pub fn neg(self) -> Self {
|
LL | / pub fn neg(self) -> Self {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -102,7 +100,7 @@ LL | | }
|
||||||
= help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
|
= help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
|
||||||
|
|
||||||
error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
|
error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
|
||||||
--> $DIR/method_list_2.rs:73:5
|
--> $DIR/method_list_2.rs:71:5
|
||||||
|
|
|
|
||||||
LL | / pub fn next(&mut self) -> Option<Self> {
|
LL | / pub fn next(&mut self) -> Option<Self> {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -113,7 +111,7 @@ LL | | }
|
||||||
= help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
|
= help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
|
||||||
|
|
||||||
error: method `not` can be confused for the standard trait method `std::ops::Not::not`
|
error: method `not` can be confused for the standard trait method `std::ops::Not::not`
|
||||||
--> $DIR/method_list_2.rs:78:5
|
--> $DIR/method_list_2.rs:76:5
|
||||||
|
|
|
|
||||||
LL | / pub fn not(self) -> Self {
|
LL | / pub fn not(self) -> Self {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -124,7 +122,7 @@ LL | | }
|
||||||
= help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
|
= help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
|
||||||
|
|
||||||
error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
|
error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
|
||||||
--> $DIR/method_list_2.rs:83:5
|
--> $DIR/method_list_2.rs:81:5
|
||||||
|
|
|
|
||||||
LL | / pub fn rem(self, rhs: Self) -> Self {
|
LL | / pub fn rem(self, rhs: Self) -> Self {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -135,7 +133,7 @@ LL | | }
|
||||||
= help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
|
= help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
|
||||||
|
|
||||||
error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
|
error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
|
||||||
--> $DIR/method_list_2.rs:88:5
|
--> $DIR/method_list_2.rs:86:5
|
||||||
|
|
|
|
||||||
LL | / pub fn shl(self, rhs: Self) -> Self {
|
LL | / pub fn shl(self, rhs: Self) -> Self {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -146,7 +144,7 @@ LL | | }
|
||||||
= help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
|
= help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
|
||||||
|
|
||||||
error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
|
error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
|
||||||
--> $DIR/method_list_2.rs:93:5
|
--> $DIR/method_list_2.rs:91:5
|
||||||
|
|
|
|
||||||
LL | / pub fn shr(self, rhs: Self) -> Self {
|
LL | / pub fn shr(self, rhs: Self) -> Self {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -157,7 +155,7 @@ LL | | }
|
||||||
= help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
|
= help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
|
||||||
|
|
||||||
error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
|
error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
|
||||||
--> $DIR/method_list_2.rs:98:5
|
--> $DIR/method_list_2.rs:96:5
|
||||||
|
|
|
|
||||||
LL | / pub fn sub(self, rhs: Self) -> Self {
|
LL | / pub fn sub(self, rhs: Self) -> Self {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -167,15 +165,5 @@ LL | | }
|
||||||
|
|
|
|
||||||
= help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name
|
= help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: aborting due to 15 previous errors
|
||||||
--> $DIR/method_list_2.rs:41:31
|
|
||||||
|
|
|
||||||
LL | pub fn hash(&self, state: &mut T) {
|
|
||||||
| ^^^^^^ help: consider changing to: `&T`
|
|
||||||
|
|
|
||||||
= warning: changing this function will impact semver compatibility
|
|
||||||
= note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
|
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
|
|
||||||
|
|
||||||
error: aborting due to 16 previous errors
|
|
||||||
|
|
||||||
|
|
|
@ -103,8 +103,6 @@ fn from_empty_vec() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_stuff(vec: &mut [u8]) {}
|
fn do_stuff(vec: &mut [u8]) {}
|
||||||
//~^ ERROR: this argument is a mutable reference, but not used mutably
|
|
||||||
//~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
|
|
||||||
|
|
||||||
fn extend_vector_with_manipulations_between() {
|
fn extend_vector_with_manipulations_between() {
|
||||||
let len = 300;
|
let len = 300;
|
||||||
|
|
|
@ -105,14 +105,5 @@ LL | vec1 = vec![];
|
||||||
LL | vec1.resize(10, 0);
|
LL | vec1.resize(10, 0);
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: this argument is a mutable reference, but not used mutably
|
error: aborting due to 13 previous errors
|
||||||
--> $DIR/slow_vector_initialization.rs:105:18
|
|
||||||
|
|
|
||||||
LL | fn do_stuff(vec: &mut [u8]) {}
|
|
||||||
| ^^^^^^^^^ help: consider changing to: `&[u8]`
|
|
||||||
|
|
|
||||||
= note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
|
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
|
|
||||||
|
|
||||||
error: aborting due to 14 previous errors
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
|
//@aux-build:proc_macro_derive.rs
|
||||||
#![warn(clippy::std_instead_of_core)]
|
#![warn(clippy::std_instead_of_core)]
|
||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate proc_macro_derive;
|
||||||
|
|
||||||
#[warn(clippy::std_instead_of_core)]
|
#[warn(clippy::std_instead_of_core)]
|
||||||
fn std_instead_of_core() {
|
fn std_instead_of_core() {
|
||||||
// Regular import
|
// Regular import
|
||||||
|
@ -55,6 +59,13 @@ fn alloc_instead_of_core() {
|
||||||
//~^ ERROR: used import from `alloc` instead of `core`
|
//~^ ERROR: used import from `alloc` instead of `core`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod std_in_proc_macro_derive {
|
||||||
|
#[warn(clippy::alloc_instead_of_core)]
|
||||||
|
#[allow(unused)]
|
||||||
|
#[derive(ImplStructWithStdDisplay)]
|
||||||
|
struct B {}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
std_instead_of_core();
|
std_instead_of_core();
|
||||||
std_instead_of_alloc();
|
std_instead_of_alloc();
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue