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
|
||||
|
||||
[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
|
||||
|
||||
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)
|
||||
|
||||
|
@ -5011,6 +5101,7 @@ Released 2018-09-13
|
|||
[`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_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_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
|
||||
|
@ -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_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_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
|
||||
[`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
|
||||
|
@ -5072,6 +5164,7 @@ Released 2018-09-13
|
|||
[`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_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_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
|
||||
|
|
|
@ -25,6 +25,8 @@ clippy_lints = { path = "clippy_lints" }
|
|||
rustc_tools_util = "0.3.0"
|
||||
tempfile = { version = "3.2", optional = true }
|
||||
termize = "0.1"
|
||||
color-print = "0.3.4" # Sync version with Cargo
|
||||
anstream = "0.5.0"
|
||||
|
||||
[dev-dependencies]
|
||||
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
|
||||
[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
|
||||
[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
|
||||
|
||||
|
|
|
@ -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)
|
||||
* [`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_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one)
|
||||
|
||||
|
||||
## `cognitive-complexity-threshold`
|
||||
|
|
|
@ -58,7 +58,7 @@ pub fn create(
|
|||
};
|
||||
|
||||
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() {
|
||||
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_project_layout<P: Into<PathBuf>>(lint_name: &str, location: P, case: &str, hint: &str) -> 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,
|
||||
msrv: bool,
|
||||
) -> io::Result<()> {
|
||||
let mut path = location.into().join(case);
|
||||
fs::create_dir(&path)?;
|
||||
write_file(path.join("Cargo.toml"), get_manifest_contents(lint_name, hint))?;
|
||||
|
||||
path.push("src");
|
||||
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(())
|
||||
}
|
||||
|
@ -106,13 +112,25 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
|
|||
let test_dir = lint.project_root.join(&relative_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(lint.name, &test_dir, "pass", "This file should not trigger the lint")?;
|
||||
create_project_layout(
|
||||
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`");
|
||||
} else {
|
||||
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)?;
|
||||
|
||||
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`")
|
||||
}
|
||||
|
||||
fn get_test_file_contents(lint_name: &str) -> String {
|
||||
formatdoc!(
|
||||
fn get_test_file_contents(lint_name: &str, msrv: bool) -> String {
|
||||
let mut test = formatdoc!(
|
||||
r#"
|
||||
#![warn(clippy::{lint_name})]
|
||||
|
||||
|
@ -203,7 +221,29 @@ fn get_test_file_contents(lint_name: &str) -> String {
|
|||
// 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 {
|
||||
|
@ -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 {
|
||||
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 test to `tests/ui/min_rust_version_attr.rs`.
|
||||
// TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
|
||||
"#
|
||||
)
|
||||
|
|
|
@ -28,6 +28,9 @@ semver = "1.0"
|
|||
rustc-semver = "1.1"
|
||||
url = "2.2"
|
||||
|
||||
[dev-dependencies]
|
||||
walkdir = "2.3"
|
||||
|
||||
[features]
|
||||
deny-warnings = ["clippy_utils/deny-warnings"]
|
||||
# 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};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// 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))
|
||||
///
|
||||
|
@ -19,7 +20,6 @@ declare_clippy_lint! {
|
|||
/// (`#![allow]`) are usually used to enable or disable lints on a global scale.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// `#[expect]` attributes suppress the lint emission, but emit a warning, if
|
||||
/// the expectation is unfulfilled. This can be useful to be notified when the
|
||||
/// 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_test_module::ITEMS_AFTER_TEST_MODULE_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_enum_variant::LARGE_ENUM_VARIANT_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_float_methods::MANUAL_IS_FINITE_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_let_else::MANUAL_LET_ELSE_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
|
||||
//! 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 rustc_hir::{Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
|
|||
.const_eval_poly(def_id.to_def_id())
|
||||
.ok()
|
||||
.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 adt.is_enum() {
|
||||
ty = adt.repr().discr_type().to_ty(cx.tcx);
|
||||
|
|
|
@ -27,7 +27,7 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// impl std::error::Error for Error { ... }
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub ERROR_IMPL_ERROR,
|
||||
restriction,
|
||||
"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,
|
||||
suspicious,
|
||||
"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 {
|
||||
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) {
|
||||
Node::Param(param) if matches!(cx.tcx.hir().get_parent(param.hir_id), Node::Item(_)) => {
|
||||
// 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::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
|
||||
use rustc_hir_analysis::hir_ty_to_ty;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{Ty, TypeckResults};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
|
@ -162,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
|
|||
vis.visit_ty(ty);
|
||||
|
||||
for target in &vis.found {
|
||||
if in_external_macro(cx.sess(), generics.span) {
|
||||
if generics.span.from_expansion() {
|
||||
continue;
|
||||
}
|
||||
let generics_suggestion_span = generics.span.substitute_dummy({
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::{is_from_proc_macro, is_in_cfg_test};
|
||||
use rustc_hir::{HirId, ItemId, ItemKind, Mod};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro};
|
||||
use rustc_errors::{Applicability, SuggestionStyle};
|
||||
use rustc_hir::{HirId, Item, ItemKind, Mod};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
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! {
|
||||
/// ### What it does
|
||||
|
@ -41,46 +43,72 @@ declare_clippy_lint! {
|
|||
|
||||
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 {
|
||||
fn check_mod(&mut self, cx: &LateContext<'_>, _: &Mod<'_>, _: HirId) {
|
||||
let mut was_test_mod_visited = false;
|
||||
let mut test_mod_span: Option<Span> = None;
|
||||
fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: HirId) {
|
||||
let mut items = module.item_ids.iter().map(|&id| cx.tcx.hir().item(id));
|
||||
|
||||
let hir = cx.tcx.hir();
|
||||
let items = hir.items().collect::<Vec<ItemId>>();
|
||||
let Some((mod_pos, test_mod)) = items.by_ref().enumerate().find(|(_, item)| cfg_test_module(cx, item)) else {
|
||||
return;
|
||||
};
|
||||
|
||||
for (i, itid) in items.iter().enumerate() {
|
||||
let item = hir.item(*itid);
|
||||
let after: Vec<_> = items
|
||||
.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 was_test_mod_visited;
|
||||
if i == (items.len() - 3 /* Weird magic number (HIR-translation behaviour) */);
|
||||
if cx.sess().source_map().lookup_char_pos(item.span.lo()).file.name_hash
|
||||
== cx.sess().source_map().lookup_char_pos(test_mod_span.unwrap().lo()).file.name_hash; // Will never fail
|
||||
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
|
||||
if !in_external_macro(cx.sess(), item.span);
|
||||
if !is_from_proc_macro(cx, item);
|
||||
if let Some(last) = after.last()
|
||||
&& after.iter().all(|&item| {
|
||||
!matches!(item.kind, ItemKind::Mod(_))
|
||||
&& !item.span.from_expansion()
|
||||
&& !is_from_proc_macro(cx, item)
|
||||
})
|
||||
&& !fulfill_or_allowed(cx, ITEMS_AFTER_TEST_MODULE, after.iter().map(|item| item.hir_id()))
|
||||
{
|
||||
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_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");
|
||||
}};
|
||||
|
||||
if let ItemKind::Mod(module) = item.kind && item.span.hi() == module.spans.inner_span.hi() {
|
||||
// Check that it works the same way, the only I way I've found for #10713
|
||||
for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
|
||||
if_chain! {
|
||||
if attr.has_name(sym::cfg);
|
||||
if let Some(mitems) = attr.meta_item_list();
|
||||
if let [mitem] = &*mitems;
|
||||
if mitem.has_name(sym::test);
|
||||
then {
|
||||
was_test_mod_visited = true;
|
||||
test_mod_span = Some(item.span);
|
||||
}
|
||||
span_lint_hir_and_then(
|
||||
cx,
|
||||
ITEMS_AFTER_TEST_MODULE,
|
||||
test_mod.hir_id(),
|
||||
def_spans,
|
||||
"items after a test module",
|
||||
|diag| {
|
||||
if let Some(prev) = mod_pos.checked_sub(1)
|
||||
&& let prev = cx.tcx.hir().item(module.item_ids[prev])
|
||||
&& let items_span = last.span.with_lo(test_mod.span.hi())
|
||||
&& let Some(items) = snippet_opt(cx, items_span)
|
||||
{
|
||||
diag.multipart_suggestion_with_style(
|
||||
"move the items to before the test module was defined",
|
||||
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_test_module;
|
||||
mod iter_not_returning_iterator;
|
||||
mod iter_without_into_iter;
|
||||
mod large_const_arrays;
|
||||
mod large_enum_variant;
|
||||
mod large_futures;
|
||||
|
@ -190,6 +191,7 @@ mod manual_async_fn;
|
|||
mod manual_bits;
|
||||
mod manual_clamp;
|
||||
mod manual_float_methods;
|
||||
mod manual_hash_one;
|
||||
mod manual_is_ascii_check;
|
||||
mod manual_let_else;
|
||||
mod manual_main_separator_str;
|
||||
|
@ -1119,6 +1121,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
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`
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,8 @@ struct PathAndSpan {
|
|||
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)]
|
||||
pub struct MacroRefData {
|
||||
name: String,
|
||||
|
|
|
@ -26,7 +26,7 @@ declare_clippy_lint! {
|
|||
/// # let x = 1.0f32;
|
||||
/// if x.is_infinite() {}
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub MANUAL_IS_INFINITE,
|
||||
style,
|
||||
"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() {}
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub MANUAL_IS_FINITE,
|
||||
style,
|
||||
"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.
|
||||
let mut app = Applicability::HasPlaceholders;
|
||||
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()
|
||||
} else {
|
||||
format!("{{ {sn_else} }}")
|
||||
|
|
|
@ -3,6 +3,7 @@ use clippy_utils::is_doc_hidden;
|
|||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::ast::{self, VisibilityKind};
|
||||
use rustc_ast::attr;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
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| {
|
||||
(matches!(v.data, hir::VariantData::Unit(_, _))
|
||||
&& 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))
|
||||
});
|
||||
if let Some((id, span)) = iter.next()
|
||||
|
@ -198,16 +200,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
|
|||
enum_span,
|
||||
"this seems like a manual implementation of the non-exhaustive pattern",
|
||||
|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 Some(snippet) = snippet_opt(cx, header_span)
|
||||
{
|
||||
diag.span_suggestion(
|
||||
header_span,
|
||||
"add the attribute",
|
||||
format!("#[non_exhaustive] {snippet}"),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
let header_span = cx.sess().source_map().span_until_char(enum_span, '{');
|
||||
if let Some(snippet) = snippet_opt(cx, header_span) {
|
||||
diag.span_suggestion(
|
||||
header_span,
|
||||
"add the attribute",
|
||||
format!("#[non_exhaustive] {snippet}"),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
diag.span_help(variant_span, "remove this variant");
|
||||
},
|
||||
|
|
|
@ -961,7 +961,7 @@ declare_clippy_lint! {
|
|||
/// _ => todo!(),
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub REDUNDANT_GUARDS,
|
||||
complexity,
|
||||
"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 core::cmp::Ordering;
|
||||
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)?,
|
||||
None => {
|
||||
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 {
|
||||
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
|
||||
None => {
|
||||
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)?;
|
||||
|
|
|
@ -2970,7 +2970,7 @@ declare_clippy_lint! {
|
|||
/// assert_eq!((*any_box).type_id(), TypeId::of::<i32>());
|
||||
/// // ^ dereference first, to call `type_id` on `dyn Any`
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub TYPE_ID_ON_BOX,
|
||||
suspicious,
|
||||
"calling `.type_id()` on `Box<dyn Any>`"
|
||||
|
@ -3368,6 +3368,7 @@ declare_clippy_lint! {
|
|||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// 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
|
||||
/// always fail because the string has a trailing newline in it.
|
||||
|
@ -3390,7 +3391,7 @@ declare_clippy_lint! {
|
|||
/// // ^^^^^^^^^^^ remove the trailing newline
|
||||
/// assert_eq!(num, 42);
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub READ_LINE_WITHOUT_TRIM,
|
||||
correctness,
|
||||
"calling `Stdin::read_line`, then trying to parse it without first trimming"
|
||||
|
@ -3418,7 +3419,7 @@ declare_clippy_lint! {
|
|||
/// # let c = 'c';
|
||||
/// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub STRING_LIT_CHARS_ANY,
|
||||
restriction,
|
||||
"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,
|
||||
perf,
|
||||
"`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<_>>();
|
||||
/// assert_eq!(x, y);
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub ITER_SKIP_ZERO,
|
||||
correctness,
|
||||
"disallows `.skip(0)`"
|
||||
|
@ -3505,7 +3506,7 @@ declare_clippy_lint! {
|
|||
/// # let v = vec![];
|
||||
/// _ = 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,
|
||||
style,
|
||||
"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(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
|
@ -101,11 +100,11 @@ pub(super) fn check(
|
|||
(expr.span.with_lo(args[0].span.hi()), String::new()),
|
||||
]),
|
||||
("None", "unwrap_or_else", _) => match args[0].kind {
|
||||
hir::ExprKind::Closure(hir::Closure {
|
||||
body,
|
||||
..
|
||||
}) => Some(vec![
|
||||
(expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()), String::new()),
|
||||
hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![
|
||||
(
|
||||
expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()),
|
||||
String::new(),
|
||||
),
|
||||
(expr.span.with_lo(args[0].span.hi()), String::new()),
|
||||
]),
|
||||
_ => None,
|
||||
|
|
|
@ -6,7 +6,8 @@ use if_chain::if_chain;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
|
||||
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::symbol::Ident;
|
||||
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
|
||||
/// 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
|
||||
/// This lint cannot check the quality of the custom panic 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 {
|
||||
match stmt.kind {
|
||||
StmtKind::Item(..) => false,
|
||||
_ => true,
|
||||
}
|
||||
!matches!(stmt.kind, StmtKind::Item(..))
|
||||
}
|
||||
|
||||
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) {
|
||||
(stmts, Some(e)) => {
|
||||
if stmts.iter().all(|stmt| !stmt_might_diverge(stmt)) {
|
||||
self.visit_expr(e)
|
||||
self.visit_expr(e);
|
||||
}
|
||||
},
|
||||
([first @ .., stmt], None) => {
|
||||
|
|
|
@ -96,10 +96,6 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
|
|||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::If(..) => {
|
||||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::Path(_) => {
|
||||
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
|
||||
if adj
|
||||
|
|
|
@ -47,9 +47,9 @@ declare_clippy_lint! {
|
|||
/// 12 + *y
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub NEEDLESS_PASS_BY_REF_MUT,
|
||||
suspicious,
|
||||
nursery,
|
||||
"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,
|
||||
suspicious,
|
||||
"non-canonical implementation of `PartialOrd` on an `Ord` type"
|
||||
|
|
|
@ -312,7 +312,7 @@ declare_clippy_lint! {
|
|||
/// # let status_code = 200;
|
||||
/// if status_code <= 400 && status_code > 500 {}
|
||||
/// ```
|
||||
#[clippy::version = "1.71.0"]
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub IMPOSSIBLE_COMPARISONS,
|
||||
correctness,
|
||||
"double comparisons that will never evaluate to `true`"
|
||||
|
@ -332,7 +332,7 @@ declare_clippy_lint! {
|
|||
/// # let status_code = 200;
|
||||
/// if status_code <= 400 && status_code < 500 {}
|
||||
/// ```
|
||||
#[clippy::version = "1.71.0"]
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub REDUNDANT_COMPARISONS,
|
||||
correctness,
|
||||
"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) {
|
||||
return;
|
||||
}
|
||||
let descr = lit.kind.descr();
|
||||
|
||||
if !str.contains(['\\', '"']) {
|
||||
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 start = start.with_lo(r_pos);
|
||||
|
||||
if end.is_empty() {
|
||||
diag.span_suggestion(
|
||||
start,
|
||||
"use a string literal instead",
|
||||
format!("\"{str}\""),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
diag.multipart_suggestion(
|
||||
"try",
|
||||
vec![(start, String::new()), (end, String::new())],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
let mut remove = vec![(start, String::new())];
|
||||
// avoid debug ICE from empty suggestions
|
||||
if !end.is_empty() {
|
||||
remove.push((end, String::new()));
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -149,9 +147,9 @@ impl EarlyLintPass for RawStrings {
|
|||
let (start, end) = hash_spans(expr.span, prefix, req, max);
|
||||
|
||||
let message = match max - req {
|
||||
_ if req == 0 => "remove all the hashes around the literal".to_string(),
|
||||
1 => "remove one hash from both sides of the literal".to_string(),
|
||||
n => format!("remove {n} hashes from both sides of the literal"),
|
||||
_ if req == 0 => format!("remove all the hashes around the {descr} literal"),
|
||||
1 => format!("remove one hash from both sides of the {descr} literal"),
|
||||
n => format!("remove {n} hashes from both sides of the {descr} literal"),
|
||||
};
|
||||
|
||||
diag.multipart_suggestion(
|
||||
|
|
|
@ -3,11 +3,9 @@ use clippy_utils::is_from_proc_macro;
|
|||
use clippy_utils::ty::needs_ordered_drop;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{
|
||||
BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath,
|
||||
};
|
||||
use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath};
|
||||
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_span::symbol::Ident;
|
||||
use rustc_span::DesugaringKind;
|
||||
|
@ -39,7 +37,7 @@ declare_clippy_lint! {
|
|||
/// // no redefinition with the same name
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub REDUNDANT_LOCALS,
|
||||
correctness,
|
||||
"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
|
||||
if !affects_assignments(cx, mutability, binding_id, local.hir_id);
|
||||
// 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
|
||||
if !in_external_macro(cx.sess(), local.span);
|
||||
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 {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
REDUNDANT_LOCALS,
|
||||
vec![binding_pat.span, local.span],
|
||||
"redundant redefinition of a binding",
|
||||
None,
|
||||
&format!("remove the redefinition of `{ident}`"),
|
||||
local.span,
|
||||
&format!("redundant redefinition of a binding `{ident}`"),
|
||||
Some(binding_pat.span),
|
||||
&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
|
||||
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 { .. })
|
||||
&& let item = cx.tcx.hir().item(id)
|
||||
&& let ItemKind::Impl(Impl {
|
||||
items,
|
||||
of_trait,
|
||||
self_ty,
|
||||
..
|
||||
}) = &item.kind
|
||||
items,
|
||||
of_trait,
|
||||
self_ty,
|
||||
..
|
||||
}) = &item.kind
|
||||
&& let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
|
||||
{
|
||||
if !map.contains_key(res) {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::DefId;
|
||||
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_span::symbol::kw;
|
||||
use rustc_span::{sym, Span};
|
||||
|
@ -99,6 +101,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
|
|||
if let Res::Def(_, def_id) = path.res
|
||||
&& let Some(first_segment) = get_first_segment(path)
|
||||
&& 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 {
|
||||
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.
|
||||
(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
|
||||
(msrv: Option<String> = None),
|
||||
|
@ -744,3 +744,44 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec<usize>) {
|
|||
|
||||
(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);
|
||||
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.contains(&kw::Underscore);
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
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::{is_in_cfg_test, is_in_test_function};
|
||||
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_hir::{Expr, Impl, Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{sym, BytePos};
|
||||
use rustc_span::{sym, BytePos, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### 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) {
|
||||
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()];
|
||||
for piece in &format_args.template {
|
||||
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 {
|
||||
if let FormatArgsPiece::Placeholder(FormatPlaceholder {
|
||||
argument,
|
||||
|
@ -471,9 +486,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
|
|||
&& let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind
|
||||
&& !arg.expr.span.from_expansion()
|
||||
&& let Some(value_string) = snippet_opt(cx, arg.expr.span)
|
||||
{
|
||||
{
|
||||
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,
|
||||
None => return,
|
||||
},
|
||||
|
@ -493,12 +508,6 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
|
|||
_ => 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 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(
|
||||
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,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
sug_span = Some(sug_span.unwrap_or(arg.expr.span).to(arg.expr.span));
|
||||
|
||||
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
|
||||
|
@ -593,3 +631,47 @@ fn conservative_unescape(literal: &str) -> Result<String, UnescapeErr> {
|
|||
|
||||
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_lexer::tokenize;
|
||||
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::{bug, mir, span_bug};
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::SyntaxContext;
|
||||
use rustc_target::abi::Size;
|
||||
use std::cmp::Ordering::{self, Equal};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter;
|
||||
|
@ -403,7 +404,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||
&& adt_def.is_struct()
|
||||
&& 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 {
|
||||
result
|
||||
|
@ -483,7 +484,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None)
|
||||
.ok()
|
||||
.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;
|
||||
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;
|
||||
match result {
|
||||
mir::Const::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
|
||||
let mir::Const::Val(val, _) = result else {
|
||||
// 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::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
|
||||
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()))),
|
||||
_ => None,
|
||||
},
|
||||
mir::Const::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) =>
|
||||
{
|
||||
let data = cv.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
|
||||
(_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => {
|
||||
let data = val.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
|
||||
String::from_utf8(data.to_owned()).ok().map(Constant::Str)
|
||||
},
|
||||
mir::Const::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => {
|
||||
let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory();
|
||||
match result.ty().kind() {
|
||||
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
||||
ty::Array(sub_type, len) => match sub_type.kind() {
|
||||
ty::Float(FloatTy::F32) => match len.try_to_target_usize(lcx.tcx) {
|
||||
Some(len) => alloc
|
||||
.inner()
|
||||
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap()))
|
||||
.to_owned()
|
||||
.array_chunks::<4>()
|
||||
.map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk))))
|
||||
.collect::<Option<Vec<Constant<'tcx>>>>()
|
||||
.map(Constant::Vec),
|
||||
_ => None,
|
||||
},
|
||||
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,
|
||||
(_, ty::Adt(adt_def, _)) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
||||
(ConstValue::Indirect { alloc_id, offset }, ty::Array(sub_type, len)) => {
|
||||
let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
|
||||
let len = len.try_to_target_usize(lcx.tcx)?;
|
||||
let ty::Float(flt) = sub_type.kind() else {
|
||||
return None;
|
||||
};
|
||||
let size = Size::from_bits(flt.bit_width());
|
||||
let mut res = Vec::new();
|
||||
for idx in 0..len {
|
||||
let range = alloc_range(offset + size * idx, size);
|
||||
let val = alloc.read_scalar(&lcx.tcx, range, /* read_provenance */ false).ok()?;
|
||||
res.push(match flt {
|
||||
FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)),
|
||||
FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().ok()?)),
|
||||
});
|
||||
}
|
||||
Some(Constant::Vec(res))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
@ -83,9 +83,9 @@ pub fn span_lint_and_help<T: LintContext>(
|
|||
cx.struct_span_lint(lint, span, msg.to_string(), |diag| {
|
||||
let help = help.to_string();
|
||||
if let Some(help_span) = help_span {
|
||||
diag.span_help(help_span, help.to_string());
|
||||
diag.span_help(help_span, help);
|
||||
} else {
|
||||
diag.help(help.to_string());
|
||||
diag.help(help);
|
||||
}
|
||||
docs_link(diag, lint);
|
||||
diag
|
||||
|
|
|
@ -80,7 +80,6 @@ use std::sync::{Mutex, MutexGuard, OnceLock};
|
|||
use if_chain::if_chain;
|
||||
use itertools::Itertools;
|
||||
use rustc_ast::ast::{self, LitKind, RangeLimits};
|
||||
use rustc_ast::Attribute;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::unhash::UnhashMap;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
@ -113,7 +112,7 @@ use rustc_span::{sym, Span};
|
|||
use rustc_target::abi::Integer;
|
||||
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::ty::{
|
||||
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()
|
||||
&& let bnd_ty = subst.type_at(0)
|
||||
&& 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 min_const_kind = Const::from_value(const_val, bnd_ty)
|
||||
&& let Some(min_const) = miri_to_const(cx, min_const_kind)
|
||||
&& let Some(min_const) = mir_to_const(cx, Const::from_ty_const(min_val, cx.tcx))
|
||||
&& let Some(start_const) = constant(cx, cx.typeck_results(), start)
|
||||
{
|
||||
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()
|
||||
&& let bnd_ty = subst.type_at(0)
|
||||
&& 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 max_const_kind = Const::from_value(const_val, bnd_ty)
|
||||
&& let Some(max_const) = miri_to_const(cx, max_const_kind)
|
||||
&& let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, cx.tcx))
|
||||
&& let Some(end_const) = constant(cx, cx.typeck_results(), end)
|
||||
{
|
||||
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
|
||||
pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
||||
fn is_cfg_test(attr: &Attribute) -> bool {
|
||||
/// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent
|
||||
/// use [`is_in_cfg_test`]
|
||||
pub fn is_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
||||
tcx.hir().attrs(id).iter().any(|attr| {
|
||||
if attr.has_name(sym::cfg)
|
||||
&& let Some(items) = attr.meta_item_list()
|
||||
&& let [item] = &*items
|
||||
|
@ -2470,11 +2466,14 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
|||
} else {
|
||||
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()
|
||||
.parent_iter(id)
|
||||
.flat_map(|(parent_id, _)| tcx.hir().attrs(parent_id))
|
||||
.any(is_cfg_test)
|
||||
.parent_id_iter(id)
|
||||
.any(|parent_id| is_cfg_test(tcx, parent_id))
|
||||
}
|
||||
|
||||
/// 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
|
||||
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,68,0 { PATH_MAIN_SEPARATOR_STR }
|
||||
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_session::Session;
|
||||
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::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 {
|
||||
($t:ident, $f:ident) => {
|
||||
impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> {
|
||||
|
@ -748,3 +769,26 @@ pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool {
|
|||
})
|
||||
.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::process::exit;
|
||||
|
||||
use anstream::println;
|
||||
|
||||
/// 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`.
|
||||
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() {
|
||||
println!(
|
||||
"\
|
||||
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)]
|
||||
"
|
||||
);
|
||||
println!("{}", help_message());
|
||||
}
|
||||
|
||||
const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml";
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
#[allow(clippy::ignored_unit_patterns)]
|
||||
pub fn main() {
|
||||
let handler = EarlyErrorHandler::new(ErrorOutputType::default());
|
||||
|
||||
|
@ -236,6 +214,7 @@ pub fn main() {
|
|||
|
||||
if orig_args.iter().any(|a| a == "--version" || a == "-V") {
|
||||
let version_info = rustc_tools_util::get_version_info!();
|
||||
|
||||
println!("{version_info}");
|
||||
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::process::{self, Command};
|
||||
|
||||
const CARGO_CLIPPY_HELP: &str = "Checks a package to catch common mistakes and improve your Rust code.
|
||||
|
||||
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)]
|
||||
";
|
||||
use anstream::println;
|
||||
|
||||
#[allow(clippy::ignored_unit_patterns)]
|
||||
fn show_help() {
|
||||
println!("{CARGO_CLIPPY_HELP}");
|
||||
println!("{}", help_message());
|
||||
}
|
||||
|
||||
#[allow(clippy::ignored_unit_patterns)]
|
||||
fn show_version() {
|
||||
let version_info = rustc_tools_util::get_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)]
|
||||
mod tests {
|
||||
use super::ClippyCmd;
|
||||
|
|
|
@ -21,6 +21,18 @@ pub fn derive(_: TokenStream) -> TokenStream {
|
|||
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)]
|
||||
pub fn derive_foo(_input: TokenStream) -> TokenStream {
|
||||
quote! {
|
||||
|
@ -141,3 +153,19 @@ pub fn shadow_derive(_: TokenStream) -> TokenStream {
|
|||
.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)]
|
||||
#![warn(clippy::expl_impl_clone_on_copy)]
|
||||
|
||||
|
||||
#[derive(Copy)]
|
||||
struct Qux;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 | |
|
||||
|
@ -10,7 +10,7 @@ LL | | }
|
|||
| |_^
|
||||
|
|
||||
note: consider deriving `Clone` or removing `Copy`
|
||||
--> $DIR/derive.rs:8:1
|
||||
--> $DIR/derive.rs:7:1
|
||||
|
|
||||
LL | / impl Clone for Qux {
|
||||
LL | |
|
||||
|
@ -23,7 +23,7 @@ LL | | }
|
|||
= help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]`
|
||||
|
||||
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 | |
|
||||
|
@ -34,7 +34,7 @@ LL | | }
|
|||
| |_^
|
||||
|
|
||||
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 | |
|
||||
|
@ -45,7 +45,7 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
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 | |
|
||||
|
@ -56,7 +56,7 @@ LL | | }
|
|||
| |_^
|
||||
|
|
||||
note: consider deriving `Clone` or removing `Copy`
|
||||
--> $DIR/derive.rs:45:1
|
||||
--> $DIR/derive.rs:44:1
|
||||
|
|
||||
LL | / impl Clone for BigArray {
|
||||
LL | |
|
||||
|
@ -67,7 +67,7 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
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 | |
|
||||
|
@ -78,7 +78,7 @@ LL | | }
|
|||
| |_^
|
||||
|
|
||||
note: consider deriving `Clone` or removing `Copy`
|
||||
--> $DIR/derive.rs:57:1
|
||||
--> $DIR/derive.rs:56:1
|
||||
|
|
||||
LL | / impl Clone for FnPtr {
|
||||
LL | |
|
||||
|
@ -89,7 +89,7 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
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 | |
|
||||
|
@ -100,7 +100,7 @@ LL | | }
|
|||
| |_^
|
||||
|
|
||||
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 | |
|
||||
|
|
|
@ -22,9 +22,9 @@ mod rustc_ok {
|
|||
|
||||
#[expect(illegal_floating_point_literal_pattern)]
|
||||
match x {
|
||||
5.0 => {}
|
||||
6.0 => {}
|
||||
_ => {}
|
||||
5.0 => {},
|
||||
6.0 => {},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,9 +41,9 @@ mod rustc_warn {
|
|||
#[expect(illegal_floating_point_literal_pattern)]
|
||||
//~^ ERROR: this lint expectation is unfulfilled
|
||||
match x {
|
||||
5 => {}
|
||||
6 => {}
|
||||
_ => {}
|
||||
5 => {},
|
||||
6 => {},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//@aux-build:proc_macro_derive.rs
|
||||
#![warn(clippy::ignored_unit_patterns)]
|
||||
#![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)]
|
||||
|
||||
|
@ -14,8 +15,22 @@ fn main() {
|
|||
//~^ ERROR: matching over `()` is more explicit
|
||||
let _ = foo().map_err(|()| todo!());
|
||||
//~^ 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)]
|
||||
pub fn moo(_: ()) {
|
||||
let () = foo().unwrap();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//@aux-build:proc_macro_derive.rs
|
||||
#![warn(clippy::ignored_unit_patterns)]
|
||||
#![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)]
|
||||
|
||||
|
@ -14,8 +15,22 @@ fn main() {
|
|||
//~^ ERROR: matching over `()` is more explicit
|
||||
let _ = foo().map_err(|_| todo!());
|
||||
//~^ 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)]
|
||||
pub fn moo(_: ()) {
|
||||
let _ = foo().unwrap();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: matching over `()` is more explicit
|
||||
--> $DIR/ignored_unit_patterns.rs:10:12
|
||||
--> $DIR/ignored_unit_patterns.rs:11:12
|
||||
|
|
||||
LL | Ok(_) => {},
|
||||
| ^ help: use `()` instead of `_`: `()`
|
||||
|
@ -8,28 +8,40 @@ LL | Ok(_) => {},
|
|||
= help: to override `-D warnings` add `#[allow(clippy::ignored_unit_patterns)]`
|
||||
|
||||
error: matching over `()` is more explicit
|
||||
--> $DIR/ignored_unit_patterns.rs:11:13
|
||||
--> $DIR/ignored_unit_patterns.rs:12:13
|
||||
|
|
||||
LL | Err(_) => {},
|
||||
| ^ help: use `()` instead of `_`: `()`
|
||||
|
||||
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() {}
|
||||
| ^ help: use `()` instead of `_`: `()`
|
||||
|
||||
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!());
|
||||
| ^ help: use `()` instead of `_`: `()`
|
||||
|
||||
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();
|
||||
| ^ 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!()
|
||||
}
|
||||
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!()
|
||||
}
|
||||
fn fooi() -> i32 {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 {
|
||||
| ^^^^^^
|
||||
|
@ -8,7 +8,7 @@ LL | while y < 10 {
|
|||
= note: `#[deny(clippy::while_immutable_condition)]` on by default
|
||||
|
||||
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 {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
@ -16,7 +16,7 @@ LL | while y < 10 && x < 3 {
|
|||
= 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
|
||||
--> $DIR/infinite_loop.rs:40:11
|
||||
--> $DIR/infinite_loop.rs:38:11
|
||||
|
|
||||
LL | while !cond {
|
||||
| ^^^^^
|
||||
|
@ -24,7 +24,7 @@ LL | while !cond {
|
|||
= 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
|
||||
--> $DIR/infinite_loop.rs:86:11
|
||||
--> $DIR/infinite_loop.rs:84:11
|
||||
|
|
||||
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
|
||||
|
||||
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 {
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
@ -40,7 +40,7 @@ LL | while i < 3 && j > 0 {
|
|||
= 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
|
||||
--> $DIR/infinite_loop.rs:99:11
|
||||
--> $DIR/infinite_loop.rs:97:11
|
||||
|
|
||||
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
|
||||
|
||||
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 {
|
||||
| ^^^^^
|
||||
|
@ -56,7 +56,7 @@ LL | while i < 3 {
|
|||
= 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
|
||||
--> $DIR/infinite_loop.rs:123:11
|
||||
--> $DIR/infinite_loop.rs:121:11
|
||||
|
|
||||
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
|
||||
|
||||
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 {
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
@ -72,7 +72,7 @@ LL | while self.count < n {
|
|||
= 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
|
||||
--> $DIR/infinite_loop.rs:201:11
|
||||
--> $DIR/infinite_loop.rs:199:11
|
||||
|
|
||||
LL | while y < 10 {
|
||||
| ^^^^^^
|
||||
|
@ -82,7 +82,7 @@ LL | while y < 10 {
|
|||
= help: rewrite it as `if cond { loop { } }`
|
||||
|
||||
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 {
|
||||
| ^^^^^^
|
||||
|
@ -91,14 +91,5 @@ LL | while y < 10 {
|
|||
= note: this loop contains `return`s or `break`s
|
||||
= help: rewrite it as `if cond { loop { } }`
|
||||
|
||||
error: this argument is a mutable reference, but not used mutably
|
||||
--> $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
|
||||
error: aborting due to 11 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)]
|
||||
#![warn(clippy::items_after_test_module)]
|
||||
|
||||
|
@ -6,6 +5,13 @@ fn main() {}
|
|||
|
||||
fn should_not_lint() {}
|
||||
|
||||
fn should_lint() {}
|
||||
|
||||
const SHOULD_ALSO_LINT: usize = 1;
|
||||
macro_rules! should_lint {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[allow(unused)] // Some attributes to check that span replacement is good enough
|
||||
#[allow(clippy::allow_attributes)]
|
||||
|
@ -14,10 +20,3 @@ mod tests {
|
|||
#[test]
|
||||
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 = ()>) {}
|
||||
//~^ 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() {
|
||||
let _ = some_async_fn();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -9,7 +9,7 @@ LL | let _ = some_async_fn();
|
|||
= help: to override `-D warnings` add `#[allow(clippy::let_underscore_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();
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
@ -17,21 +17,12 @@ LL | let _ = custom();
|
|||
= help: consider awaiting the future or dropping explicitly with `std::mem::drop`
|
||||
|
||||
error: non-binding `let` on a future
|
||||
--> $DIR/let_underscore_future.rs:23:5
|
||||
--> $DIR/let_underscore_future.rs:21:5
|
||||
|
|
||||
LL | let _ = future;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider awaiting the future or dropping explicitly with `std::mem::drop`
|
||||
|
||||
error: this argument is a mutable reference, but not used mutably
|
||||
--> $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
|
||||
error: aborting due to 3 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,
|
||||
};
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
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 | | };
|
||||
| |______^ 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,
|
||||
}
|
||||
|
||||
// user forgot to remove the marker
|
||||
// if the user explicitly marks as nonexhaustive we shouldn't warn them
|
||||
#[non_exhaustive]
|
||||
enum Ep {
|
||||
//~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern
|
||||
A,
|
||||
B,
|
||||
#[doc(hidden)]
|
||||
|
|
|
@ -22,23 +22,5 @@ LL | _C,
|
|||
= note: `-D clippy::manual-non-exhaustive` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]`
|
||||
|
||||
error: this seems like a manual implementation of the non-exhaustive pattern
|
||||
--> $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
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -32,8 +32,6 @@ fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<K
|
|||
//~^ ERROR: mutable key type
|
||||
//~| NOTE: `-D clippy::mutable-key-type` implied by `-D warnings`
|
||||
//~| 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();
|
||||
//~^ ERROR: mutable key type
|
||||
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
|
||||
--> $DIR/mut_key.rs:37:5
|
||||
--> $DIR/mut_key.rs:35:5
|
||||
|
|
||||
LL | let _other: HashMap<Key, bool> = HashMap::new();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: mutable key type
|
||||
--> $DIR/mut_key.rs:78:5
|
||||
--> $DIR/mut_key.rs:76:5
|
||||
|
|
||||
LL | let _map = HashMap::<Cell<usize>, usize>::new();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: mutable key type
|
||||
--> $DIR/mut_key.rs:82:5
|
||||
--> $DIR/mut_key.rs:80:5
|
||||
|
|
||||
LL | let _map = HashMap::<&mut usize, usize>::new();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this argument is a mutable reference, but not used mutably
|
||||
--> $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
|
||||
error: aborting due to 17 previous errors
|
||||
|
||||
|
|
|
@ -22,8 +22,6 @@ impl MyStruct {
|
|||
fn takes_an_immutable_reference(&self, a: &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)]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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);
|
||||
| ^^^^^^^
|
||||
|
@ -8,25 +8,16 @@ LL | takes_an_immutable_reference(&mut 42);
|
|||
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]`
|
||||
|
||||
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);
|
||||
| ^^^^^^^
|
||||
|
||||
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);
|
||||
| ^^^^^^^
|
||||
|
||||
error: this argument is a mutable reference, but not used mutably
|
||||
--> $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
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#![allow(clippy::if_same_then_else, clippy::no_effect, clippy::redundant_closure_call)]
|
||||
#![warn(clippy::needless_pass_by_ref_mut)]
|
||||
#![feature(lint_reasons)]
|
||||
//@no-rustfix
|
||||
use std::ptr::NonNull;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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) {
|
||||
| ^^^^^^^^^^^^^ 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)]`
|
||||
|
||||
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>) {
|
||||
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
|
||||
|
||||
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 {
|
||||
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
|
||||
|
||||
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 {
|
||||
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
|
||||
|
||||
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) {
|
||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||
|
||||
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) {
|
||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||
|
||||
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) {
|
||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||
|
||||
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) {
|
||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||
|
||||
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) {
|
||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||
|
||||
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) {
|
||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||
|
||||
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) {
|
||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||
|
||||
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) {
|
||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||
|
||||
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) {
|
||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||
|
||||
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) {}
|
||||
| ^^^^^^^^ 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
|
||||
|
||||
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) {}
|
||||
| ^^^^^^^^ 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
|
||||
|
||||
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) {
|
||||
| ^^^^^^^^ help: consider changing to: `&u32`
|
||||
|
||||
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) {
|
||||
| ^^^^^^^^ help: consider changing to: `&i32`
|
||||
|
||||
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) {
|
||||
| ^^^^^^^^ 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
|
||||
|
||||
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() {
|
||||
| ^^^^^^^^^^ 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
|
||||
|
||||
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 {
|
||||
| ^^^^^^^^^^ 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
|
||||
|
||||
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) {
|
||||
| ^^^^^^^^^^ help: consider changing to: `&usize`
|
||||
|
|
|
@ -18,4 +18,8 @@ fn main() {
|
|||
multiline
|
||||
string
|
||||
";
|
||||
|
||||
"no hashes";
|
||||
b"no hashes";
|
||||
c"no hashes";
|
||||
}
|
||||
|
|
|
@ -18,4 +18,8 @@ fn main() {
|
|||
multiline
|
||||
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`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::needless_raw_strings)]`
|
||||
help: try
|
||||
help: use a plain string literal instead
|
||||
|
|
||||
LL - r#"aaa"#;
|
||||
LL + "aaa";
|
||||
|
@ -18,7 +18,7 @@ error: unnecessary raw string literal
|
|||
LL | br#"aaa"#;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
help: use a plain byte string literal instead
|
||||
|
|
||||
LL - br#"aaa"#;
|
||||
LL + b"aaa";
|
||||
|
@ -30,7 +30,7 @@ error: unnecessary raw string literal
|
|||
LL | cr#"aaa"#;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
help: use a plain C string literal instead
|
||||
|
|
||||
LL - cr#"aaa"#;
|
||||
LL + c"aaa";
|
||||
|
@ -46,7 +46,7 @@ LL | | string
|
|||
LL | | "#;
|
||||
| |______^
|
||||
|
|
||||
help: try
|
||||
help: use a plain string literal instead
|
||||
|
|
||||
LL ~ "
|
||||
LL | a
|
||||
|
@ -55,5 +55,41 @@ LL | string
|
|||
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`
|
||||
= 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";
|
||||
|
@ -18,7 +18,7 @@ error: unnecessary hashes around raw string literal
|
|||
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"!"#;
|
||||
|
@ -30,7 +30,7 @@ error: unnecessary hashes around raw string literal
|
|||
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####" "### "## "# "####;
|
||||
|
@ -42,7 +42,7 @@ error: unnecessary hashes around raw string literal
|
|||
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" "# "## "###;
|
||||
|
@ -54,7 +54,7 @@ error: unnecessary hashes around raw string literal
|
|||
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";
|
||||
|
@ -66,7 +66,7 @@ error: unnecessary hashes around raw string literal
|
|||
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"!"#;
|
||||
|
@ -78,7 +78,7 @@ error: unnecessary hashes around raw string literal
|
|||
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####" "### "## "# "####;
|
||||
|
@ -90,7 +90,7 @@ error: unnecessary hashes around raw string literal
|
|||
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" "# "## "###;
|
||||
|
@ -102,7 +102,7 @@ error: unnecessary hashes around raw string literal
|
|||
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";
|
||||
|
@ -114,7 +114,7 @@ error: unnecessary hashes around raw string literal
|
|||
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"!"#;
|
||||
|
@ -126,7 +126,7 @@ error: unnecessary hashes around raw string literal
|
|||
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####" "### "## "# "####;
|
||||
|
@ -138,7 +138,7 @@ error: unnecessary hashes around raw string literal
|
|||
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" "# "## "###;
|
||||
|
@ -154,7 +154,7 @@ LL | | string
|
|||
LL | | "#;
|
||||
| |______^
|
||||
|
|
||||
help: remove all the hashes around the literal
|
||||
help: remove all the hashes around the string literal
|
||||
|
|
||||
LL ~ r"
|
||||
LL | \a
|
||||
|
@ -169,7 +169,7 @@ error: unnecessary hashes around raw string literal
|
|||
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";
|
||||
|
@ -181,7 +181,7 @@ error: unnecessary hashes around raw string literal
|
|||
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";
|
||||
|
|
|
@ -39,20 +39,30 @@ fn main() {
|
|||
// throw a warning
|
||||
println!("hello world");
|
||||
//~^ ERROR: literal with an empty format string
|
||||
//~| ERROR: literal with an empty format string
|
||||
println!("world hello");
|
||||
//~^ ERROR: literal with an empty format string
|
||||
//~| ERROR: literal with an empty format string
|
||||
|
||||
// named args shouldn't change anything either
|
||||
println!("hello world");
|
||||
//~^ ERROR: literal with an empty format string
|
||||
//~| ERROR: literal with an empty format string
|
||||
println!("world hello");
|
||||
//~^ 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
|
||||
// expansion
|
||||
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
|
||||
println!("{0} {1}", "hello", "world");
|
||||
//~^ ERROR: literal with an empty format string
|
||||
//~| ERROR: literal with an empty format string
|
||||
println!("{1} {0}", "hello", "world");
|
||||
//~^ ERROR: literal with an empty format string
|
||||
//~| ERROR: literal with an empty format string
|
||||
|
||||
// named args shouldn't change anything either
|
||||
println!("{foo} {bar}", foo = "hello", bar = "world");
|
||||
//~^ ERROR: literal with an empty format string
|
||||
//~| ERROR: literal with an empty format string
|
||||
println!("{bar} {foo}", foo = "hello", bar = "world");
|
||||
//~^ 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
|
||||
// expansion
|
||||
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
|
||||
|
|
||||
LL | println!("{0} {1}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - println!("{0} {1}", "hello", "world");
|
||||
LL + println!("hello {1}", "world");
|
||||
LL + println!("hello world");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:40:34
|
||||
|
|
||||
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
|
||||
--> $DIR/print_literal.rs:42:25
|
||||
|
|
||||
LL | println!("{1} {0}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - println!("{1} {0}", "hello", "world");
|
||||
LL + println!("world {0}", "hello");
|
||||
LL + println!("world hello");
|
||||
|
|
||||
|
||||
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
|
||||
|
|
||||
LL - println!("{1} {0}", "hello", "world");
|
||||
LL + println!("{1} hello", "world");
|
||||
LL - println!("{foo} {bar}", foo = "hello", bar = "world");
|
||||
LL + println!("hello world");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $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");
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
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
|
||||
--> $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
|
||||
|
|
||||
LL - println!("{bar} {foo}", foo = "hello", bar = "world");
|
||||
LL + println!("{bar} hello", bar = "world");
|
||||
LL - println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}");
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
|
||||
LL | let x = 1;
|
||||
| ^
|
||||
LL | let x = x;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: remove the redefinition of `x`
|
||||
= note: `-D clippy::redundant-locals` implied by `-D warnings`
|
||||
= 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
|
||||
|
|
||||
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
|
||||
|
|
||||
LL | fn parameter(x: i32) {
|
||||
| ^
|
||||
|
||||
error: redundant redefinition of a binding `x`
|
||||
--> $DIR/redundant_locals.rs:52:5
|
||||
|
|
||||
LL | let x = x;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: remove the redefinition of `x`
|
||||
|
||||
error: redundant redefinition of a binding
|
||||
help: `x` is initially defined here
|
||||
--> $DIR/redundant_locals.rs:51:9
|
||||
|
|
||||
LL | let x = 1;
|
||||
| ^
|
||||
|
||||
error: redundant redefinition of a binding `x`
|
||||
--> $DIR/redundant_locals.rs:53:5
|
||||
|
|
||||
LL | let x = x;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: remove the redefinition of `x`
|
||||
|
||||
error: redundant redefinition of a binding
|
||||
help: `x` is initially defined here
|
||||
--> $DIR/redundant_locals.rs:52:9
|
||||
|
|
||||
LL | let x = x;
|
||||
| ^
|
||||
|
||||
error: redundant redefinition of a binding `x`
|
||||
--> $DIR/redundant_locals.rs:54:5
|
||||
|
|
||||
LL | let x = x;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: remove the redefinition of `x`
|
||||
|
||||
error: redundant redefinition of a binding
|
||||
help: `x` is initially defined here
|
||||
--> $DIR/redundant_locals.rs:53:9
|
||||
|
|
||||
LL | let x = x;
|
||||
| ^
|
||||
|
||||
error: redundant redefinition of a binding `x`
|
||||
--> $DIR/redundant_locals.rs:55:5
|
||||
|
|
||||
LL | let x = x;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: remove the redefinition of `x`
|
||||
|
||||
error: redundant redefinition of a binding
|
||||
help: `x` is initially defined here
|
||||
--> $DIR/redundant_locals.rs:54:9
|
||||
|
|
||||
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`
|
||||
|
||||
error: redundant redefinition of a binding
|
||||
help: `a` is initially defined here
|
||||
--> $DIR/redundant_locals.rs:59:9
|
||||
|
|
||||
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`
|
||||
|
||||
error: redundant redefinition of a binding
|
||||
help: `b` is initially defined here
|
||||
--> $DIR/redundant_locals.rs:60:9
|
||||
|
|
||||
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
|
||||
|
|
||||
LL | let x = 1;
|
||||
| ^
|
||||
|
||||
error: redundant redefinition of a binding `x`
|
||||
--> $DIR/redundant_locals.rs:75:9
|
||||
|
|
||||
LL | let x = x;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: remove the redefinition of `x`
|
||||
|
||||
error: redundant redefinition of a binding
|
||||
help: `x` is initially defined here
|
||||
--> $DIR/redundant_locals.rs:74:13
|
||||
|
|
||||
LL | let x = 1;
|
||||
| ^
|
||||
|
||||
error: redundant redefinition of a binding `x`
|
||||
--> $DIR/redundant_locals.rs:78:9
|
||||
|
|
||||
LL | let x = x;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: remove the redefinition of `x`
|
||||
|
||||
error: redundant redefinition of a binding
|
||||
help: `x` is initially defined here
|
||||
--> $DIR/redundant_locals.rs:77:6
|
||||
|
|
||||
LL | |x: i32| {
|
||||
| ^
|
||||
|
||||
error: redundant redefinition of a binding `x`
|
||||
--> $DIR/redundant_locals.rs:97:9
|
||||
|
|
||||
LL | let x = x;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: remove the redefinition of `x`
|
||||
|
||||
error: redundant redefinition of a binding
|
||||
help: `x` is initially defined here
|
||||
--> $DIR/redundant_locals.rs:94:9
|
||||
|
|
||||
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) {
|
||||
//~^ 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!()
|
||||
}
|
||||
|
||||
|
|
|
@ -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 | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
@ -47,7 +45,7 @@ LL | | }
|
|||
= 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`
|
||||
--> $DIR/method_list_2.rs:48:5
|
||||
--> $DIR/method_list_2.rs:46:5
|
||||
|
|
||||
LL | / pub fn index(&self, index: usize) -> &Self {
|
||||
LL | |
|
||||
|
@ -58,7 +56,7 @@ LL | | }
|
|||
= 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`
|
||||
--> $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 | |
|
||||
|
@ -69,7 +67,7 @@ LL | | }
|
|||
= 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`
|
||||
--> $DIR/method_list_2.rs:58:5
|
||||
--> $DIR/method_list_2.rs:56:5
|
||||
|
|
||||
LL | / pub fn into_iter(self) -> Self {
|
||||
LL | |
|
||||
|
@ -80,7 +78,7 @@ LL | | }
|
|||
= 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`
|
||||
--> $DIR/method_list_2.rs:63:5
|
||||
--> $DIR/method_list_2.rs:61:5
|
||||
|
|
||||
LL | / pub fn mul(self, rhs: Self) -> Self {
|
||||
LL | |
|
||||
|
@ -91,7 +89,7 @@ LL | | }
|
|||
= 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`
|
||||
--> $DIR/method_list_2.rs:68:5
|
||||
--> $DIR/method_list_2.rs:66:5
|
||||
|
|
||||
LL | / pub fn neg(self) -> Self {
|
||||
LL | |
|
||||
|
@ -102,7 +100,7 @@ LL | | }
|
|||
= 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`
|
||||
--> $DIR/method_list_2.rs:73:5
|
||||
--> $DIR/method_list_2.rs:71:5
|
||||
|
|
||||
LL | / pub fn next(&mut self) -> Option<Self> {
|
||||
LL | |
|
||||
|
@ -113,7 +111,7 @@ LL | | }
|
|||
= 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`
|
||||
--> $DIR/method_list_2.rs:78:5
|
||||
--> $DIR/method_list_2.rs:76:5
|
||||
|
|
||||
LL | / pub fn not(self) -> Self {
|
||||
LL | |
|
||||
|
@ -124,7 +122,7 @@ LL | | }
|
|||
= 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`
|
||||
--> $DIR/method_list_2.rs:83:5
|
||||
--> $DIR/method_list_2.rs:81:5
|
||||
|
|
||||
LL | / pub fn rem(self, rhs: Self) -> Self {
|
||||
LL | |
|
||||
|
@ -135,7 +133,7 @@ LL | | }
|
|||
= 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`
|
||||
--> $DIR/method_list_2.rs:88:5
|
||||
--> $DIR/method_list_2.rs:86:5
|
||||
|
|
||||
LL | / pub fn shl(self, rhs: Self) -> Self {
|
||||
LL | |
|
||||
|
@ -146,7 +144,7 @@ LL | | }
|
|||
= 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`
|
||||
--> $DIR/method_list_2.rs:93:5
|
||||
--> $DIR/method_list_2.rs:91:5
|
||||
|
|
||||
LL | / pub fn shr(self, rhs: Self) -> Self {
|
||||
LL | |
|
||||
|
@ -157,7 +155,7 @@ LL | | }
|
|||
= 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`
|
||||
--> $DIR/method_list_2.rs:98:5
|
||||
--> $DIR/method_list_2.rs:96:5
|
||||
|
|
||||
LL | / pub fn sub(self, rhs: Self) -> Self {
|
||||
LL | |
|
||||
|
@ -167,15 +165,5 @@ LL | | }
|
|||
|
|
||||
= 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
|
||||
--> $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
|
||||
error: aborting due to 15 previous errors
|
||||
|
||||
|
|
|
@ -103,8 +103,6 @@ fn from_empty_vec() {
|
|||
}
|
||||
|
||||
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() {
|
||||
let len = 300;
|
||||
|
|
|
@ -105,14 +105,5 @@ LL | vec1 = vec![];
|
|||
LL | vec1.resize(10, 0);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this argument is a mutable reference, but not used mutably
|
||||
--> $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
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
//@aux-build:proc_macro_derive.rs
|
||||
#![warn(clippy::std_instead_of_core)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_use]
|
||||
extern crate proc_macro_derive;
|
||||
|
||||
#[warn(clippy::std_instead_of_core)]
|
||||
fn std_instead_of_core() {
|
||||
// Regular import
|
||||
|
@ -55,6 +59,13 @@ fn 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() {
|
||||
std_instead_of_core();
|
||||
std_instead_of_alloc();
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
//@aux-build:proc_macro_derive.rs
|
||||
#![warn(clippy::std_instead_of_core)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_use]
|
||||
extern crate proc_macro_derive;
|
||||
|
||||
#[warn(clippy::std_instead_of_core)]
|
||||
fn std_instead_of_core() {
|
||||
// Regular import
|
||||
|
@ -55,6 +59,13 @@ fn 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() {
|
||||
std_instead_of_core();
|
||||
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