diff options
110 files changed, 2653 insertions, 404 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 70a09db074e..52efa8db485 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,181 @@ document. ## Unreleased / Beta / In Rust Nightly -[b52fb523...master](https://github.com/rust-lang/rust-clippy/compare/b52fb523...master) +[4f142aa1...master](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...master) + +## Rust 1.66 + +Current stable, released 2022-12-15 + +[b52fb523...4f142aa1](https://github.com/rust-lang/rust-clippy/compare/b52fb523...4f142aa1) + +### New Lints + +* [`manual_clamp`] + [#9484](https://github.com/rust-lang/rust-clippy/pull/9484) +* [`missing_trait_methods`] + [#9670](https://github.com/rust-lang/rust-clippy/pull/9670) +* [`unused_format_specs`] + [#9637](https://github.com/rust-lang/rust-clippy/pull/9637) +* [`iter_kv_map`] + [#9409](https://github.com/rust-lang/rust-clippy/pull/9409) +* [`manual_filter`] + [#9451](https://github.com/rust-lang/rust-clippy/pull/9451) +* [`box_default`] + [#9511](https://github.com/rust-lang/rust-clippy/pull/9511) +* [`implicit_saturating_add`] + [#9549](https://github.com/rust-lang/rust-clippy/pull/9549) +* [`as_ptr_cast_mut`] + [#9572](https://github.com/rust-lang/rust-clippy/pull/9572) +* [`disallowed_macros`] + [#9495](https://github.com/rust-lang/rust-clippy/pull/9495) +* [`partial_pub_fields`] + [#9658](https://github.com/rust-lang/rust-clippy/pull/9658) +* [`uninlined_format_args`] + [#9233](https://github.com/rust-lang/rust-clippy/pull/9233) +* [`cast_nan_to_int`] + [#9617](https://github.com/rust-lang/rust-clippy/pull/9617) + +### Moves and Deprecations + +* `positional_named_format_parameters` was uplifted to rustc under the new name + `named_arguments_used_positionally` + [#8518](https://github.com/rust-lang/rust-clippy/pull/8518) +* Moved [`implicit_saturating_sub`] to `style` (Now warn-by-default) + [#9584](https://github.com/rust-lang/rust-clippy/pull/9584) +* Moved `derive_partial_eq_without_eq` to `nursery` (now allow-by-default) + [#9536](https://github.com/rust-lang/rust-clippy/pull/9536) + +### Enhancements + +* [`nonstandard_macro_braces`]: Now includes `matches!()` in the default lint config + [#9471](https://github.com/rust-lang/rust-clippy/pull/9471) +* [`suboptimal_flops`]: Now supports multiplication and subtraction operations + [#9581](https://github.com/rust-lang/rust-clippy/pull/9581) +* [`arithmetic_side_effects`]: Now detects cases with literals behind references + [#9587](https://github.com/rust-lang/rust-clippy/pull/9587) +* [`upper_case_acronyms`]: Now also checks enum names + [#9580](https://github.com/rust-lang/rust-clippy/pull/9580) +* [`needless_borrowed_reference`]: Now lints nested patterns + [#9573](https://github.com/rust-lang/rust-clippy/pull/9573) +* [`unnecessary_cast`]: Now works for non-trivial non-literal expressions + [#9576](https://github.com/rust-lang/rust-clippy/pull/9576) +* [`arithmetic_side_effects`]: Now detects operations with custom types + [#9559](https://github.com/rust-lang/rust-clippy/pull/9559) +* [`disallowed_methods`], [`disallowed_types`]: Not correctly lints types, functions and macros + with the same path + [#9495](https://github.com/rust-lang/rust-clippy/pull/9495) +* [`self_named_module_files`], [`mod_module_files`]: Now take remapped path prefixes into account + [#9475](https://github.com/rust-lang/rust-clippy/pull/9475) +* [`bool_to_int_with_if`]: Now detects the inverse if case + [#9476](https://github.com/rust-lang/rust-clippy/pull/9476) + +### False Positive Fixes + +* [`arithmetic_side_effects`]: Now allows operations that can't overflow + [#9474](https://github.com/rust-lang/rust-clippy/pull/9474) +* [`unnecessary_lazy_evaluations`]: No longer lints in external macros + [#9486](https://github.com/rust-lang/rust-clippy/pull/9486) +* [`needless_borrow`], [`explicit_auto_deref`]: No longer lint on unions that require the reference + [#9490](https://github.com/rust-lang/rust-clippy/pull/9490) +* [`almost_complete_letter_range`]: No longer lints in external macros + [#9467](https://github.com/rust-lang/rust-clippy/pull/9467) +* [`drop_copy`]: No longer lints on idiomatic cases in match arms + [#9491](https://github.com/rust-lang/rust-clippy/pull/9491) +* [`question_mark`]: No longer lints in const context + [#9487](https://github.com/rust-lang/rust-clippy/pull/9487) +* [`collapsible_if`]: Suggestion now work in macros + [#9410](https://github.com/rust-lang/rust-clippy/pull/9410) +* [`std_instead_of_core`]: No longer triggers on unstable modules + [#9545](https://github.com/rust-lang/rust-clippy/pull/9545) +* [`unused_peekable`]: No longer lints, if the peak is done in a closure or function + [#9465](https://github.com/rust-lang/rust-clippy/pull/9465) +* [`useless_attribute`]: No longer lints on `#[allow]` attributes for [`unsafe_removed_from_name`] + [#9593](https://github.com/rust-lang/rust-clippy/pull/9593) +* [`unnecessary_lazy_evaluations`]: No longer suggest switching to early evaluation when type has + custom `Drop` implementation + [#9551](https://github.com/rust-lang/rust-clippy/pull/9551) +* [`unnecessary_cast`]: No longer lints on negative hexadecimal literals when cast as floats + [#9609](https://github.com/rust-lang/rust-clippy/pull/9609) +* [`use_self`]: No longer lints in proc macros + [#9454](https://github.com/rust-lang/rust-clippy/pull/9454) +* [`never_loop`]: Now takes `let ... else` statements into consideration. + [#9496](https://github.com/rust-lang/rust-clippy/pull/9496) +* [`default_numeric_fallback`]: Now ignores constants + [#9636](https://github.com/rust-lang/rust-clippy/pull/9636) +* [`uninit_vec`]: No longer lints `Vec::set_len(0)` + [#9519](https://github.com/rust-lang/rust-clippy/pull/9519) +* [`arithmetic_side_effects`]: Now ignores references to integer types + [#9507](https://github.com/rust-lang/rust-clippy/pull/9507) +* [`large_stack_arrays`]: No longer lints inside static items + [#9466](https://github.com/rust-lang/rust-clippy/pull/9466) +* [`ref_option_ref`]: No longer lints if the inner reference is mutable + [#9684](https://github.com/rust-lang/rust-clippy/pull/9684) +* [`ptr_arg`]: No longer lints if the argument is used as an incomplete trait object + [#9645](https://github.com/rust-lang/rust-clippy/pull/9645) +* [`should_implement_trait`]: Now also works for `default` methods + [#9546](https://github.com/rust-lang/rust-clippy/pull/9546) + +### Suggestion Fixes/Improvements + +* [`derivable_impls`]: The suggestion is now machine applicable + [#9429](https://github.com/rust-lang/rust-clippy/pull/9429) +* [`match_single_binding`]: The suggestion now handles scrutinies with side effects better + [#9601](https://github.com/rust-lang/rust-clippy/pull/9601) +* [`zero_prefixed_literal`]: Only suggests using octal numbers, if this is possible + [#9652](https://github.com/rust-lang/rust-clippy/pull/9652) +* [`rc_buffer`]: The suggestion is no longer machine applicable to avoid semantic changes + [#9633](https://github.com/rust-lang/rust-clippy/pull/9633) +* [`print_literal`], [`write_literal`], [`uninlined_format_args`]: The suggestion now ignores + comments after the macro call. + [#9586](https://github.com/rust-lang/rust-clippy/pull/9586) +* [`expect_fun_call`]:Improved the suggestion for `format!` calls with captured variables + [#9586](https://github.com/rust-lang/rust-clippy/pull/9586) +* [`nonstandard_macro_braces`]: The suggestion is now machine applicable and will no longer + replace brackets inside the macro argument. + [#9499](https://github.com/rust-lang/rust-clippy/pull/9499) +* [`from_over_into`]: The suggestion is now a machine applicable and contains explanations + [#9649](https://github.com/rust-lang/rust-clippy/pull/9649) +* [`needless_return`]: The automatic suggestion now removes all required semicolons + [#9497](https://github.com/rust-lang/rust-clippy/pull/9497) +* [`to_string_in_format_args`]: The suggestion now keeps parenthesis around values + [#9590](https://github.com/rust-lang/rust-clippy/pull/9590) +* [`manual_assert`]: The suggestion now preserves comments + [#9479](https://github.com/rust-lang/rust-clippy/pull/9479) +* [`redundant_allocation`]: The suggestion applicability is now marked `MaybeIncorrect` to + avoid semantic changes + [#9634](https://github.com/rust-lang/rust-clippy/pull/9634) +* [`assertions_on_result_states`]: The suggestion has been corrected, for cases where the + `assert!` is not in a statement. + [#9453](https://github.com/rust-lang/rust-clippy/pull/9453) +* [`nonminimal_bool`]: The suggestion no longer expands macros + [#9457](https://github.com/rust-lang/rust-clippy/pull/9457) +* [`collapsible_match`]: Now specifies field names, when a struct is destructed + [#9685](https://github.com/rust-lang/rust-clippy/pull/9685) +* [`unnecessary_cast`]: The suggestion now adds parenthesis for negative numbers + [#9577](https://github.com/rust-lang/rust-clippy/pull/9577) +* [`redundant_closure`]: The suggestion now works for `impl FnMut` arguments + [#9556](https://github.com/rust-lang/rust-clippy/pull/9556) + +### ICE Fixes + +* [`unnecessary_to_owned`]: Avoid ICEs in favor of false negatives if information is missing + [#9505](https://github.com/rust-lang/rust-clippy/pull/9505) +* [`manual_range_contains`]: No longer ICEs on values behind references + [#9627](https://github.com/rust-lang/rust-clippy/pull/9627) +* [`needless_pass_by_value`]: No longer ICEs on unsized `dyn Fn` arguments + [#9531](https://github.com/rust-lang/rust-clippy/pull/9531) +* `*_interior_mutable_const` lints: no longer ICE on const unions containing `!Freeze` types + [#9539](https://github.com/rust-lang/rust-clippy/pull/9539) + +### Others + +* Released `rustc_tools_util` for version information on `Crates.io`. (Further adjustments will + not be published as part of this changelog) ## Rust 1.65 -Current stable, released 2022-11-03 +Released 2022-11-03 [3c7e7dbc...b52fb523](https://github.com/rust-lang/rust-clippy/compare/3c7e7dbc...b52fb523) @@ -4033,6 +4203,7 @@ Released 2018-09-13 [`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const [`float_equality_without_abs`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_equality_without_abs [`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons +[`fn_null_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_null_check [`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools [`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast [`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any @@ -4290,6 +4461,7 @@ Released 2018-09-13 [`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch +[`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence @@ -4420,6 +4592,7 @@ Released 2018-09-13 [`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool [`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char [`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float +[`transmute_null_to_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_null_to_fn [`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes [`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr [`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref diff --git a/Cargo.toml b/Cargo.toml index 6bdac84ada0..e1b15cc49da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.67" +version = "0.1.68" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -23,7 +23,7 @@ path = "src/driver.rs" [dependencies] clippy_lints = { path = "clippy_lints" } semver = "1.0" -rustc_tools_util = "0.2.1" +rustc_tools_util = "0.3.0" tempfile = { version = "3.2", optional = true } termize = "0.1" @@ -56,7 +56,7 @@ tokio = { version = "1", features = ["io-util"] } rustc-semver = "1.1" [build-dependencies] -rustc_tools_util = "0.2.1" +rustc_tools_util = "0.3.0" [features] deny-warnings = ["clippy_lints/deny-warnings"] diff --git a/book/src/README.md b/book/src/README.md index 6248d588a89..23867df8efe 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -1,6 +1,6 @@ # Clippy -[](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test%22+event%3Apush+branch%3Aauto) +[/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test+(bors)%22+event%3Apush+branch%3Aauto) [](https://github.com/rust-lang/rust-clippy#license) A collection of lints to catch common mistakes and improve your diff --git a/build.rs b/build.rs index b5484bec3c8..b79d09b0dd2 100644 --- a/build.rs +++ b/build.rs @@ -3,17 +3,5 @@ fn main() { println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap()); // Don't rebuild even if nothing changed println!("cargo:rerun-if-changed=build.rs"); - // forward git repo hashes we build at - println!( - "cargo:rustc-env=GIT_HASH={}", - rustc_tools_util::get_commit_hash().unwrap_or_default() - ); - println!( - "cargo:rustc-env=COMMIT_DATE={}", - rustc_tools_util::get_commit_date().unwrap_or_default() - ); - println!( - "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}", - rustc_tools_util::get_channel() - ); + rustc_tools_util::setup_version_info!(); } diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index dcadd012a44..38a87017635 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.67" +version = "0.1.68" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 36daceabe0b..91900542af8 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// ```rust /// let x: Box<String> = Box::default(); /// ``` - #[clippy::version = "1.65.0"] + #[clippy::version = "1.66.0"] pub BOX_DEFAULT, perf, "Using Box::new(T::default()) instead of Box::default()" diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index c6d505c4a18..161e3a698e9 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -641,7 +641,7 @@ declare_clippy_lint! { /// ```rust,ignore /// let _: = 0_u64; /// ``` - #[clippy::version = "1.64.0"] + #[clippy::version = "1.66.0"] pub CAST_NAN_TO_INT, suspicious, "casting a known floating-point NaN into an integer" diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 3cd7d1d7e72..980e128cba4 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -161,6 +161,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::float_literal::LOSSY_FLOAT_LITERAL_INFO, crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO, crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO, + crate::fn_null_check::FN_NULL_CHECK_INFO, crate::format::USELESS_FORMAT_INFO, crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO, crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO, @@ -494,6 +495,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO, crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO, crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO, + crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO, crate::precedence::PRECEDENCE_INFO, crate::ptr::CMP_NULL_INFO, crate::ptr::INVALID_NULL_PTR_USAGE_INFO, @@ -568,6 +570,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO, crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO, crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO, + crate::transmute::TRANSMUTE_NULL_TO_FN_INFO, crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO, crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO, crate::transmute::TRANSMUTE_PTR_TO_REF_INFO, diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 38329659e02..7b43d8ccc67 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1244,7 +1244,7 @@ fn is_mixed_projection_predicate<'tcx>( let mut projection_ty = projection_predicate.projection_ty; loop { match projection_ty.self_ty().kind() { - ty::Projection(inner_projection_ty) => { + ty::Alias(ty::Projection, inner_projection_ty) => { projection_ty = *inner_projection_ty; } ty::Param(param_ty) => { @@ -1330,7 +1330,7 @@ fn replace_types<'tcx>( && let Some(term_ty) = projection_predicate.term.ty() && let ty::Param(term_param_ty) = term_ty.kind() { - let item_def_id = projection_predicate.projection_ty.item_def_id; + let item_def_id = projection_predicate.projection_ty.def_id; let assoc_item = cx.tcx.associated_item(item_def_id); let projection = cx.tcx .mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, [])); @@ -1390,10 +1390,15 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc continue; }, ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty), - ty::Projection(_) if ty.has_non_region_param() => TyPosition::new_deref_stable_for_result(precedence, ty), - ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => { - Position::ReborrowStable(precedence).into() + ty::Alias(ty::Projection, _) if ty.has_non_region_param() => { + TyPosition::new_deref_stable_for_result(precedence, ty) }, + ty::Infer(_) + | ty::Error(_) + | ty::Bound(..) + | ty::Alias(ty::Opaque, ..) + | ty::Placeholder(_) + | ty::Dynamic(..) => Position::ReborrowStable(precedence).into(), ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => { Position::ReborrowStable(precedence).into() }, @@ -1417,7 +1422,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc | ty::Closure(..) | ty::Never | ty::Tuple(_) - | ty::Projection(_) => { + | ty::Alias(ty::Projection, _) => { Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds())).into() }, }; diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 9e596ca8157..cf3483d4c00 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -15,7 +15,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::traits::Reveal; use rustc_middle::ty::{ self, Binder, BoundConstness, Clause, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, - TraitRef, Ty, TyCtxt, + Ty, TyCtxt, }; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -513,10 +513,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain( params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| { tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate { - trait_ref: TraitRef::new( - eq_trait_id, - tcx.mk_substs(std::iter::once(tcx.mk_param_from_def(param))), - ), + trait_ref: tcx.mk_trait_ref(eq_trait_id, [tcx.mk_param_from_def(param)]), constness: BoundConstness::NotConst, polarity: ImplPolarity::Positive, })))) diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index 68122b4cef5..1971cab64ef 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -47,7 +47,7 @@ declare_clippy_lint! { /// value: usize, /// } /// ``` - #[clippy::version = "1.65.0"] + #[clippy::version = "1.66.0"] pub DISALLOWED_MACROS, style, "use of a disallowed macro" diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index aee3d8c4f08..1f56d0118a4 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -106,7 +106,9 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if let ItemKind::Use(path, UseKind::Single) = &item.kind { - self.check_res_emit(cx, &path.res, item.span); + for res in &path.res { + self.check_res_emit(cx, res, item.span); + } } } diff --git a/clippy_lints/src/fn_null_check.rs b/clippy_lints/src/fn_null_check.rs new file mode 100644 index 00000000000..91c8c340ce2 --- /dev/null +++ b/clippy_lints/src/fn_null_check.rs @@ -0,0 +1,106 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{is_integer_literal, is_path_diagnostic_item}; +use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for comparing a function pointer to null. + /// + /// ### Why is this bad? + /// Function pointers are assumed to not be null. + /// + /// ### Example + /// ```rust,ignore + /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */ + /// + /// if (fn_ptr as *const ()).is_null() { ... } + /// ``` + /// Use instead: + /// ```rust,ignore + /// let fn_ptr: Option<fn()> = /* somehow obtained nullable function pointer */ + /// + /// if fn_ptr.is_none() { ... } + /// ``` + #[clippy::version = "1.67.0"] + pub FN_NULL_CHECK, + correctness, + "`fn()` type assumed to be nullable" +} +declare_lint_pass!(FnNullCheck => [FN_NULL_CHECK]); + +fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { + span_lint_and_help( + cx, + FN_NULL_CHECK, + expr.span, + "function pointer assumed to be nullable, even though it isn't", + None, + "try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value", + ); +} + +fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let ExprKind::Cast(cast_expr, cast_ty) = expr.kind + && let TyKind::Ptr(_) = cast_ty.kind + { + cx.typeck_results().expr_ty_adjusted(cast_expr).is_fn() + } else { + false + } +} + +impl<'tcx> LateLintPass<'tcx> for FnNullCheck { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + match expr.kind { + // Catching: + // (fn_ptr as *<const/mut> <ty>).is_null() + ExprKind::MethodCall(method_name, receiver, _, _) + if method_name.ident.as_str() == "is_null" && is_fn_ptr_cast(cx, receiver) => + { + lint_expr(cx, expr); + }, + + ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => { + let to_check: &Expr<'_>; + if is_fn_ptr_cast(cx, left) { + to_check = right; + } else if is_fn_ptr_cast(cx, right) { + to_check = left; + } else { + return; + } + + match to_check.kind { + // Catching: + // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>) + ExprKind::Cast(cast_expr, _) if is_integer_literal(cast_expr, 0) => { + lint_expr(cx, expr); + }, + + // Catching: + // (fn_ptr as *<const/mut> <ty>) == std::ptr::null() + ExprKind::Call(func, []) if is_path_diagnostic_item(cx, func, sym::ptr_null) => { + lint_expr(cx, expr); + }, + + // Catching: + // (fn_ptr as *<const/mut> <ty>) == <const that evaluates to null_ptr> + _ if matches!( + constant(cx, cx.typeck_results(), to_check), + Some((Constant::RawPtr(0), _)) + ) => + { + lint_expr(cx, expr); + }, + + _ => {}, + } + }, + _ => {}, + } + } +} diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index f0995a81329..62284235dbf 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -2,7 +2,8 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; use clippy_utils::macros::FormatParamKind::{Implicit, Named, NamedInline, Numbered, Starred}; use clippy_utils::macros::{ - is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, FormatParamUsage, + is_assert_macro, is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, + FormatParamUsage, }; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; @@ -122,7 +123,7 @@ declare_clippy_lint! { /// /// If a format string contains a numbered argument that cannot be inlined /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`. - #[clippy::version = "1.65.0"] + #[clippy::version = "1.66.0"] pub UNINLINED_FORMAT_ARGS, style, "using non-inlined variables in `format!` calls" @@ -290,8 +291,9 @@ fn check_uninlined_args( if args.format_string.span.from_expansion() { return; } - if call_site.edition() < Edition2021 && is_panic(cx, def_id) { - // panic! before 2021 edition considers a single string argument as non-format + if call_site.edition() < Edition2021 && (is_panic(cx, def_id) || is_assert_macro(cx, def_id)) { + // panic!, assert!, and debug_assert! before 2021 edition considers a single string argument as + // non-format return; } diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index cc3c35f4863..a92f7548ff2 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id) && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id) - && !matches!(middle_trait_ref.substs.type_at(1).kind(), ty::Opaque(..)) + && !matches!(middle_trait_ref.substs.type_at(1).kind(), ty::Alias(ty::Opaque, _)) { span_lint_and_then( cx, @@ -127,7 +127,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> { self.cx.tcx.hir() } - fn visit_path(&mut self, path: &'tcx Path<'tcx>, _id: HirId) { + fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { for segment in path.segments { match segment.ident.name { kw::SelfLower => self.lower.push(segment.ident.span), diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 61934a91426..989f83cf80d 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -4,7 +4,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, HirId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{Clause, EarlyBinder, Opaque, PredicateKind}; +use rustc_middle::ty::{self, AliasTy, Clause, EarlyBinder, PredicateKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; @@ -62,11 +62,11 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { return; } let ret_ty = return_ty(cx, hir_id); - if let Opaque(id, subst) = *ret_ty.kind() { - let preds = cx.tcx.explicit_item_bounds(id); + if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() { + let preds = cx.tcx.explicit_item_bounds(def_id); let mut is_future = false; for &(p, _span) in preds { - let p = EarlyBinder(p).subst(cx.tcx, subst); + let p = EarlyBinder(p).subst(cx.tcx, substs); if let Some(trait_pred) = p.to_opt_poly_trait_pred() { if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() { is_future = true; diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs index bf1351829c6..6e19343931e 100644 --- a/clippy_lints/src/implicit_saturating_add.rs +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// /// u = u.saturating_add(1); /// ``` - #[clippy::version = "1.65.0"] + #[clippy::version = "1.66.0"] pub IMPLICIT_SATURATING_ADD, style, "Perform saturating addition instead of implicitly checking max bound of data type" diff --git a/clippy_lints/src/invalid_utf8_in_unchecked.rs b/clippy_lints/src/invalid_utf8_in_unchecked.rs index e0a607f9a95..6a4861747d2 100644 --- a/clippy_lints/src/invalid_utf8_in_unchecked.rs +++ b/clippy_lints/src/invalid_utf8_in_unchecked.rs @@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidUtf8InUnchecked { if let Some([arg]) = match_function_call(cx, expr, &paths::STR_FROM_UTF8_UNCHECKED) { match &arg.kind { ExprKind::Lit(Spanned { node: lit, .. }) => { - if let LitKind::ByteStr(bytes) = &lit + if let LitKind::ByteStr(bytes, _) = &lit && std::str::from_utf8(bytes).is_err() { lint(cx, expr.span); diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 76c83ab47d0..db637dfc068 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -34,12 +34,12 @@ declare_clippy_lint! { } pub struct LargeConstArrays { - maximum_allowed_size: u64, + maximum_allowed_size: u128, } impl LargeConstArrays { #[must_use] - pub fn new(maximum_allowed_size: u64) -> Self { + pub fn new(maximum_allowed_size: u128) -> Self { Self { maximum_allowed_size } } } @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind(); if let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx); if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()); - if self.maximum_allowed_size < element_count * element_size; + if self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size); then { let hi_pos = item.ident.span.lo() - BytePos::from_usize(1); diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 84dd61a1e4b..424c0d9e798 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -60,7 +60,7 @@ impl LateLintPass<'_> for LargeIncludeFile { then { let len = match &lit.node { // include_bytes - LitKind::ByteStr(bstr) => bstr.len(), + LitKind::ByteStr(bstr, _) => bstr.len(), // include_str LitKind::Str(sym, _) => sym.as_str().len(), _ => return, diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 5857d81ab1f..89ae83d48f5 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -24,12 +24,12 @@ declare_clippy_lint! { } pub struct LargeStackArrays { - maximum_allowed_size: u64, + maximum_allowed_size: u128, } impl LargeStackArrays { #[must_use] - pub fn new(maximum_allowed_size: u64) -> Self { + pub fn new(maximum_allowed_size: u128) -> Self { Self { maximum_allowed_size } } } @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && !cx.tcx.hir().parent_iter(expr.hir_id) .any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. }))) - && self.maximum_allowed_size < element_count * element_size { + && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) { span_lint_and_help( cx, LARGE_STACK_ARRAYS, diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 3babc2a5895..e88d1764a24 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -501,7 +501,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { .filter_by_name_unhygienic(is_empty) .any(|item| is_is_empty(cx, item)) }), - ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id), + ty::Alias(ty::Projection, ref proj) => has_is_empty_impl(cx, proj.def_id), ty::Adt(id, _) => has_is_empty_impl(cx, id.did()), ty::Array(..) | ty::Slice(..) | ty::Str => true, _ => false, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 39850d59803..676ef3946bf 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -125,6 +125,7 @@ mod explicit_write; mod fallible_impl_from; mod float_literal; mod floating_point_arithmetic; +mod fn_null_check; mod format; mod format_args; mod format_impl; @@ -234,6 +235,7 @@ mod partialeq_ne_impl; mod partialeq_to_none; mod pass_by_ref_or_value; mod pattern_type_mismatch; +mod permissions_set_readonly_false; mod precedence; mod ptr; mod ptr_offset_with_cast; @@ -902,6 +904,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow)); store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv()))); store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock)); + store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck)); + store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index b6f4cf7bbb3..28ee24309cc 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -25,7 +25,6 @@ pub(super) struct IncrementVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, // context reference states: HirIdMap<IncrementVisitorVarState>, // incremented variables depth: u32, // depth of conditional expressions - done: bool, } impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> { @@ -34,7 +33,6 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> { cx, states: HirIdMap::default(), depth: 0, - done: false, } } @@ -51,10 +49,6 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if self.done { - return; - } - // If node is a variable if let Some(def_id) = path_to_local(expr) { if let Some(parent) = get_parent_expr(self.cx, expr) { @@ -95,7 +89,9 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { walk_expr(self, expr); self.depth -= 1; } else if let ExprKind::Continue(_) = expr.kind { - self.done = true; + // If we see a `continue` block, then we increment depth so that the IncrementVisitor + // state will be set to DontWarn if we see the variable being modified anywhere afterwards. + self.depth += 1; } else { walk_expr(self, expr); } diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index f5617a905ff..26ae4b409c7 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -95,7 +95,10 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { let hir_id = item.hir_id(); let attrs = cx.tcx.hir().attrs(hir_id); if let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use)); - if let Res::Def(DefKind::Mod, id) = path.res; + if let Some(id) = path.res.iter().find_map(|res| match res { + Res::Def(DefKind::Mod, id) => Some(id), + _ => None, + }); if !id.is_local(); then { for kid in cx.tcx.module_children(id).iter() { diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index bb6d628af3b..f239736d38a 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -35,6 +35,9 @@ declare_clippy_lint! { /// Some may consider panicking in these situations to be desirable, but it also may /// introduce panicking where there wasn't any before. /// + /// See also [the discussion in the + /// PR](https://github.com/rust-lang/rust-clippy/pull/9484#issuecomment-1278922613). + /// /// ### Examples /// ```rust /// # let (input, min, max) = (0, -2, 1); @@ -78,7 +81,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.66.0"] pub MANUAL_CLAMP, - complexity, + nursery, "using a clamp pattern instead of the clamp function" } impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]); diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 5ab049d8d13..d9ef7dffa02 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -1,11 +1,12 @@ use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::{diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, source::snippet}; +use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, source::snippet}; +use rustc_ast::ast::RangeLimits; use rustc_ast::LitKind::{Byte, Char}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd}; +use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{def_id::DefId, sym}; +use rustc_span::{def_id::DefId, sym, Span}; declare_clippy_lint! { /// ### What it does @@ -23,6 +24,10 @@ declare_clippy_lint! { /// assert!(matches!(b'X', b'A'..=b'Z')); /// assert!(matches!('2', '0'..='9')); /// assert!(matches!('x', 'A'..='Z' | 'a'..='z')); + /// + /// ('0'..='9').contains(&'0'); + /// ('a'..='z').contains(&'a'); + /// ('A'..='Z').contains(&'A'); /// } /// ``` /// Use instead: @@ -32,6 +37,10 @@ declare_clippy_lint! { /// assert!(b'X'.is_ascii_uppercase()); /// assert!('2'.is_ascii_digit()); /// assert!('x'.is_ascii_alphabetic()); + /// + /// '0'.is_ascii_digit(); + /// 'a'.is_ascii_lowercase(); + /// 'A'.is_ascii_uppercase(); /// } /// ``` #[clippy::version = "1.66.0"] @@ -75,40 +84,21 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { return; } - let Some(macro_call) = root_macro_call(expr.span) else { return }; - - if is_matches_macro(cx, macro_call.def_id) { + if let Some(macro_call) = root_macro_call(expr.span) + && is_matches_macro(cx, macro_call.def_id) { if let ExprKind::Match(recv, [arm, ..], _) = expr.kind { let range = check_pat(&arm.pat.kind); - - if let Some(sugg) = match range { - CharRange::UpperChar => Some("is_ascii_uppercase"), - CharRange::LowerChar => Some("is_ascii_lowercase"), - CharRange::FullChar => Some("is_ascii_alphabetic"), - CharRange::Digit => Some("is_ascii_digit"), - CharRange::Otherwise => None, - } { - let default_snip = ".."; - // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for - // macro span, so we check applicability manually by comparing `recv` is not default. - let recv = snippet(cx, recv.span, default_snip); - - let applicability = if recv == default_snip { - Applicability::HasPlaceholders - } else { - Applicability::MachineApplicable - }; - - span_lint_and_sugg( - cx, - MANUAL_IS_ASCII_CHECK, - macro_call.span, - "manual check for common ascii range", - "try", - format!("{recv}.{sugg}()"), - applicability, - ); - } + check_is_ascii(cx, macro_call.span, recv, &range); + } + } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind + && path.ident.name == sym!(contains) + && let Some(higher::Range { start: Some(start), end: Some(end), limits: RangeLimits::Closed }) + = higher::Range::hir(receiver) { + let range = check_range(start, end); + if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = arg.kind { + check_is_ascii(cx, expr.span, e, &range); + } else { + check_is_ascii(cx, expr.span, arg, &range); } } } @@ -116,6 +106,37 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { extract_msrv_attr!(LateContext); } +fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &CharRange) { + if let Some(sugg) = match range { + CharRange::UpperChar => Some("is_ascii_uppercase"), + CharRange::LowerChar => Some("is_ascii_lowercase"), + CharRange::FullChar => Some("is_ascii_alphabetic"), + CharRange::Digit => Some("is_ascii_digit"), + CharRange::Otherwise => None, + } { + let default_snip = ".."; + // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for + // macro span, so we check applicability manually by comparing `recv` is not default. + let recv = snippet(cx, recv.span, default_snip); + + let applicability = if recv == default_snip { + Applicability::HasPlaceholders + } else { + Applicability::MachineApplicable + }; + + span_lint_and_sugg( + cx, + MANUAL_IS_ASCII_CHECK, + span, + "manual check for common ascii range", + "try", + format!("{recv}.{sugg}()"), + applicability, + ); + } +} + fn check_pat(pat_kind: &PatKind<'_>) -> CharRange { match pat_kind { PatKind::Or(pats) => { diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index c1e6c82487d..72cdb9c1736 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -70,7 +70,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain { && seg.args.is_none() && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id) - && match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) { + && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id) + { check_into_iter(cx, parent_expr, left_expr, target_expr, &self.msrv); check_iter(cx, parent_expr, left_expr, target_expr, &self.msrv); check_to_owned(cx, parent_expr, left_expr, target_expr, &self.msrv); diff --git a/clippy_lints/src/matches/manual_filter.rs b/clippy_lints/src/matches/manual_filter.rs index d521a529e0d..f6bf0e7aa1a 100644 --- a/clippy_lints/src/matches/manual_filter.rs +++ b/clippy_lints/src/matches/manual_filter.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::contains_unsafe_block; use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; -use rustc_hir::LangItem::OptionSome; +use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind}; use rustc_lint::LateContext; use rustc_span::{sym, SyntaxContext}; @@ -25,15 +25,13 @@ fn get_cond_expr<'tcx>( if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr); if let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind; if let PatKind::Binding(_,target, ..) = pat.kind; - if let (then_visitor, else_visitor) - = (is_some_expr(cx, target, ctxt, then_expr), - is_some_expr(cx, target, ctxt, else_expr)); - if then_visitor != else_visitor; // check that one expr resolves to `Some(x)`, the other to `None` + if is_some_expr(cx, target, ctxt, then_expr) && is_none_expr(cx, else_expr) + || is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr); // check that one expr resolves to `Some(x)`, the other to `None` then { return Some(SomeExpr { expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()), needs_unsafe_block: contains_unsafe_block(cx, expr), - needs_negated: !then_visitor // if the `then_expr` resolves to `None`, need to negate the cond + needs_negated: is_none_expr(cx, then_expr) // if the `then_expr` resolves to `None`, need to negate the cond }) } }; @@ -74,6 +72,13 @@ fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: false } +fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) { + return is_res_lang_ctor(cx, path_res(cx, inner_expr), OptionNone); + }; + false +} + // given the closure: `|<pattern>| <expr>` // returns `|&<pattern>| <expr>` fn add_ampersand_if_copy(body_str: String, has_copy_trait: bool) -> String { diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index 168c1e4d2e6..158e6caa4de 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -282,7 +282,7 @@ impl<'a> NormalizedPat<'a> { // TODO: Handle negative integers. They're currently treated as a wild match. ExprKind::Lit(lit) => match lit.node { LitKind::Str(sym, _) => Self::LitStr(sym), - LitKind::ByteStr(ref bytes) => Self::LitBytes(bytes), + LitKind::ByteStr(ref bytes, _) => Self::LitBytes(bytes), LitKind::Byte(val) => Self::LitInt(val.into()), LitKind::Char(val) => Self::LitInt(val.into()), LitKind::Int(val, _) => Self::LitInt(val), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cb7229ba8a4..561e4336593 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3059,7 +3059,7 @@ declare_clippy_lint! { /// let map: HashMap<u32, u32> = HashMap::new(); /// let values = map.values().collect::<Vec<_>>(); /// ``` - #[clippy::version = "1.65.0"] + #[clippy::version = "1.66.0"] pub ITER_KV_MAP, complexity, "iterating on map using `iter` when `keys` or `values` would do" diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index b088e642e0e..f4d3ef3b742 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -151,7 +151,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty]) && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions( cx.param_env, - cx.tcx.mk_projection(into_iter_item_proj.item_def_id, into_iter_item_proj.substs) + cx.tcx.mk_projection(into_iter_item_proj.def_id, into_iter_item_proj.substs) ) { iter_item_ty == into_iter_item_ty diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 30421a6dd5a..910ee14855e 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -97,7 +97,7 @@ struct UnwrapVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> { type NestedFilter = nested_filter::All; - fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) { + fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { self.identifiers.insert(ident(path)); walk_path(self, path); } @@ -116,7 +116,7 @@ struct MapExprVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for MapExprVisitor<'a, 'tcx> { type NestedFilter = nested_filter::All; - fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) { + fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { if self.identifiers.contains(&ident(path)) { self.found_identifier = true; return; diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 7e3bed1e41a..660b7049cce 100644 --- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, match_def_path, paths}; +use clippy_utils::{get_trait_def_id, is_expr_used_or_unified, match_def_path, paths}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -19,6 +19,10 @@ pub(super) fn check<'tcx>( // Get receiver type let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if is_expr_used_or_unified(cx.tcx, expr) { + return; + } + if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) && implements_trait(cx, ty, seek_trait_id, &[]) && let ExprKind::Call(func, args1) = arg.kind && diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 4712846939e..773174679db 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -66,35 +66,38 @@ impl LateLintPass<'_> for ImportRename { } fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if_chain! { - if let ItemKind::Use(path, UseKind::Single) = &item.kind; - if let Res::Def(_, id) = path.res; - if let Some(name) = self.renames.get(&id); - // Remove semicolon since it is not present for nested imports - let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';'); - if let Some(snip) = snippet_opt(cx, span_without_semi); - if let Some(import) = match snip.split_once(" as ") { - None => Some(snip.as_str()), - Some((import, rename)) => { - if rename.trim() == name.as_str() { - None - } else { - Some(import.trim()) + if let ItemKind::Use(path, UseKind::Single) = &item.kind { + for &res in &path.res { + if_chain! { + if let Res::Def(_, id) = res; + if let Some(name) = self.renames.get(&id); + // Remove semicolon since it is not present for nested imports + let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';'); + if let Some(snip) = snippet_opt(cx, span_without_semi); + if let Some(import) = match snip.split_once(" as ") { + None => Some(snip.as_str()), + Some((import, rename)) => { + if rename.trim() == name.as_str() { + None + } else { + Some(import.trim()) + } + }, + }; + then { + span_lint_and_sugg( + cx, + MISSING_ENFORCED_IMPORT_RENAMES, + span_without_semi, + "this import should be renamed", + "try", + format!( + "{import} as {name}", + ), + Applicability::MachineApplicable, + ); } - }, - }; - then { - span_lint_and_sugg( - cx, - MISSING_ENFORCED_IMPORT_RENAMES, - span_without_semi, - "this import should be renamed", - "try", - format!( - "{import} as {name}", - ), - Applicability::MachineApplicable, - ); + } } } } diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs new file mode 100644 index 00000000000..e7095ec191f --- /dev/null +++ b/clippy_lints/src/permissions_set_readonly_false.rs @@ -0,0 +1,52 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::paths; +use clippy_utils::ty::match_type; +use rustc_ast::ast::LitKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`. + /// + /// ### Why is this bad? + /// On Unix platforms this results in the file being world writable, + /// equivalent to `chmod a+w <file>`. + /// ### Example + /// ```rust + /// use std::fs::File; + /// let f = File::create("foo.txt").unwrap(); + /// let metadata = f.metadata().unwrap(); + /// let mut permissions = metadata.permissions(); + /// permissions.set_readonly(false); + /// ``` + #[clippy::version = "1.66.0"] + pub PERMISSIONS_SET_READONLY_FALSE, + suspicious, + "Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`" +} +declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALSE]); + +impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind + && match_type(cx, cx.typeck_results().expr_ty(receiver), &paths::PERMISSIONS) + && path.ident.name == sym!(set_readonly) + && let ExprKind::Lit(lit) = &arg.kind + && LitKind::Bool(false) == lit.node + { + span_lint_and_then( + cx, + PERMISSIONS_SET_READONLY_FALSE, + expr.span, + "call to `set_readonly` with argument `false`", + |diag| { + diag.note("on Unix platforms this results in the file being world writable"); + diag.help("you can set the desired permissions using `PermissionsExt`. For more information, see\n\ + https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html"); + } + ); + } + } +} diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 833dc4913b4..c2a8db7df03 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -84,7 +84,11 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { fn is_not_macro_export<'tcx>(item: &'tcx Item<'tcx>) -> bool { if let ItemKind::Use(path, _) = item.kind { - if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = path.res { + if path + .res + .iter() + .all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _))) + { return false; } } else if let ItemKind::Macro(..) = item.kind { diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 81143d7799e..d4d50660520 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -6,7 +6,7 @@ use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind}; +use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, LangItem, MatchSource, PatKind, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; @@ -207,6 +207,12 @@ fn check_final_expr<'tcx>( match &peeled_drop_expr.kind { // simple return is always "bad" ExprKind::Ret(ref inner) => { + // if desugar of `do yeet`, don't lint + if let Some(inner_expr) = inner + && let ExprKind::Call(path_expr, _) = inner_expr.kind + && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind { + return; + } if cx.tcx.hir().attrs(expr.hir_id).is_empty() { let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); if !borrows { diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index 2036e85db7e..d46f6a6352c 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -149,7 +149,7 @@ impl SingleComponentPathImports { // keep track of `use some_module;` usages if segments.len() == 1 { - if let UseTreeKind::Simple(None, _, _) = use_tree.kind { + if let UseTreeKind::Simple(None) = use_tree.kind { let name = segments[0].ident.name; if !macros.contains(&name) { single_use_usages.push(SingleUse { @@ -169,7 +169,7 @@ impl SingleComponentPathImports { for tree in trees { let segments = &tree.0.prefix.segments; if segments.len() == 1 { - if let UseTreeKind::Simple(None, _, _) = tree.0.kind { + if let UseTreeKind::Simple(None) = tree.0.kind { let name = segments[0].ident.name; if !macros.contains(&name) { single_use_usages.push(SingleUse { diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 83e651aba8e..691d759d773 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -3,6 +3,7 @@ mod transmute_float_to_int; mod transmute_int_to_bool; mod transmute_int_to_char; mod transmute_int_to_float; +mod transmute_null_to_fn; mod transmute_num_to_bytes; mod transmute_ptr_to_ptr; mod transmute_ptr_to_ref; @@ -409,6 +410,34 @@ declare_clippy_lint! { "transmutes from a null pointer to a reference, which is undefined behavior" } +declare_clippy_lint! { + /// ### What it does + /// Checks for null function pointer creation through transmute. + /// + /// ### Why is this bad? + /// Creating a null function pointer is undefined behavior. + /// + /// More info: https://doc.rust-lang.org/nomicon/ffi.html#the-nullable-pointer-optimization + /// + /// ### Known problems + /// Not all cases can be detected at the moment of this writing. + /// For example, variables which hold a null pointer and are then fed to a `transmute` + /// call, aren't detectable yet. + /// + /// ### Example + /// ```rust + /// let null_fn: fn() = unsafe { std::mem::transmute( std::ptr::null::<()>() ) }; + /// ``` + /// Use instead: + /// ```rust + /// let null_fn: Option<fn()> = None; + /// ``` + #[clippy::version = "1.67.0"] + pub TRANSMUTE_NULL_TO_FN, + correctness, + "transmute results in a null function pointer, which is undefined behavior" +} + pub struct Transmute { msrv: Msrv, } @@ -428,6 +457,7 @@ impl_lint_pass!(Transmute => [ TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, TRANSMUTE_UNDEFINED_REPR, TRANSMUTING_NULL, + TRANSMUTE_NULL_TO_FN, ]); impl Transmute { #[must_use] @@ -461,6 +491,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { let linted = wrong_transmute::check(cx, e, from_ty, to_ty) | crosspointer_transmute::check(cx, e, from_ty, to_ty) | transmuting_null::check(cx, e, arg, to_ty) + | transmute_null_to_fn::check(cx, e, arg, to_ty) | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv) | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) diff --git a/clippy_lints/src/transmute/transmute_null_to_fn.rs b/clippy_lints/src/transmute/transmute_null_to_fn.rs new file mode 100644 index 00000000000..e75d7f6bf1d --- /dev/null +++ b/clippy_lints/src/transmute/transmute_null_to_fn.rs @@ -0,0 +1,64 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{is_integer_literal, is_path_diagnostic_item}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::Ty; +use rustc_span::symbol::sym; + +use super::TRANSMUTE_NULL_TO_FN; + +fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { + span_lint_and_then( + cx, + TRANSMUTE_NULL_TO_FN, + expr.span, + "transmuting a known null pointer into a function pointer", + |diag| { + diag.span_label(expr.span, "this transmute results in undefined behavior"); + diag.help( + "try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value" + ); + }, + ); +} + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, to_ty: Ty<'tcx>) -> bool { + if !to_ty.is_fn() { + return false; + } + + match arg.kind { + // Catching: + // transmute over constants that resolve to `null`. + ExprKind::Path(ref _qpath) + if matches!(constant(cx, cx.typeck_results(), arg), Some((Constant::RawPtr(0), _))) => + { + lint_expr(cx, expr); + true + }, + + // Catching: + // `std::mem::transmute(0 as *const i32)` + ExprKind::Cast(inner_expr, _cast_ty) if is_integer_literal(inner_expr, 0) => { + lint_expr(cx, expr); + true + }, + + // Catching: + // `std::mem::transmute(std::ptr::null::<i32>())` + ExprKind::Call(func1, []) if is_path_diagnostic_item(cx, func1, sym::ptr_null) => { + lint_expr(cx, expr); + true + }, + + _ => { + // FIXME: + // Also catch transmutations of variables which are known nulls. + // To do this, MIR const propagation seems to be the better tool. + // Whenever MIR const prop routines are more developed, this will + // become available. As of this writing (25/03/19) it is not yet. + false + }, + } +} diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index 19ce5ae72c2..1e407fc4138 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -18,8 +18,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t // Catching transmute over constants that resolve to `null`. let mut const_eval_context = constant_context(cx, cx.typeck_results()); if let ExprKind::Path(ref _qpath) = arg.kind && - let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg) && - x == 0 + let Some(Constant::RawPtr(0)) = const_eval_context.expr(arg) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs index bc0dd263d88..397633f533b 100644 --- a/clippy_lints/src/unnecessary_self_imports.rs +++ b/clippy_lints/src/unnecessary_self_imports.rs @@ -57,7 +57,7 @@ impl EarlyLintPass for UnnecessarySelfImports { format!( "{}{};", last_segment.ident, - if let UseTreeKind::Simple(Some(alias), ..) = self_tree.kind { format!(" as {alias}") } else { String::new() }, + if let UseTreeKind::Simple(Some(alias)) = self_tree.kind { format!(" as {alias}") } else { String::new() }, ), Applicability::MaybeIncorrect, ); diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 95258652768..7ee785804f0 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -39,7 +39,7 @@ impl EarlyLintPass for UnsafeNameRemoval { fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) { match use_tree.kind { - UseTreeKind::Simple(Some(new_name), ..) => { + UseTreeKind::Simple(Some(new_name)) => { let old_name = use_tree .prefix .segments @@ -48,7 +48,7 @@ fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) { .ident; unsafe_to_safe_check(old_name, new_name, cx, span); }, - UseTreeKind::Simple(None, ..) | UseTreeKind::Glob => {}, + UseTreeKind::Simple(None) | UseTreeKind::Glob => {}, UseTreeKind::Nested(ref nested_use_tree) => { for (use_tree, _) in nested_use_tree { check_use_tree(use_tree, cx, span); diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 3743d5d97a7..a95e7b61374 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts}; -use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, paths}; +use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; +use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; +use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -81,16 +81,24 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } } if is_trait_method(cx, e, sym::IntoIterator) && name.ident.name == sym::into_iter { - if let Some(parent_expr) = get_parent_expr(cx, e) { - if let ExprKind::MethodCall(parent_name, ..) = parent_expr.kind { - if parent_name.ident.name != sym::into_iter { - return; - } - } + if get_parent_expr(cx, e).is_some() && + let Some(id) = path_to_local(recv) && + let Node::Pat(pat) = cx.tcx.hir().get(id) && + let PatKind::Binding(ann, ..) = pat.kind && + ann != BindingAnnotation::MUT + { + // Do not remove .into_iter() applied to a non-mutable local variable used in + // a larger expression context as it would differ in mutability. + return; } + let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(recv); - if same_type_and_consts(a, b) { + + // If the types are identical then .into_iter() can be removed, unless the type + // implements Copy, in which case .into_iter() returns a copy of the receiver and + // cannot be safely omitted. + if same_type_and_consts(a, b) && !is_copy(cx, b) { let sugg = snippet(cx, recv.span, "<expr>").into_owned(); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 0c052d86eda..bd7daf0773c 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -299,7 +299,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }; kind!("Float(_, {float_ty})"); }, - LitKind::ByteStr(ref vec) => { + LitKind::ByteStr(ref vec, _) => { bind!(self, vec); kind!("ByteStr(ref {vec})"); chain!(self, "let [{:?}] = **{vec}", vec.value); diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 3e7d0028c0f..c1589c771c4 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -333,7 +333,7 @@ define_Conf! { /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. /// /// The maximum allowed size for arrays on the stack - (array_size_threshold: u64 = 512_000), + (array_size_threshold: u128 = 512_000), /// Lint: VEC_BOX. /// /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 680935f2329..9afe02c1e47 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -7,7 +7,7 @@ use rustc_hir::def::DefKind; use rustc_hir::Item; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, fast_reject::SimplifiedTypeGen, FloatTy}; +use rustc_middle::ty::{self, fast_reject::SimplifiedType, FloatTy}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; @@ -73,10 +73,10 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { let lang_items = cx.tcx.lang_items(); // This list isn't complete, but good enough for our current list of paths. let incoherent_impls = [ - SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F32), - SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F64), - SimplifiedTypeGen::SliceSimplifiedType, - SimplifiedTypeGen::StrSimplifiedType, + SimplifiedType::FloatSimplifiedType(FloatTy::F32), + SimplifiedType::FloatSimplifiedType(FloatTy::F64), + SimplifiedType::SliceSimplifiedType, + SimplifiedType::StrSimplifiedType, ] .iter() .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied()); diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 1aebb8b3104..786d9608c85 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -330,7 +330,7 @@ struct LintCollector<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> { type NestedFilter = nested_filter::All; - fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) { + fn visit_path(&mut self, path: &Path<'_>, _: HirId) { if path.segments.len() == 1 { self.output.insert(path.segments[0].ident.name); } diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index d06a616e4b3..857abe77e21 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -1019,7 +1019,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> { self.cx.tcx.hir() } - fn visit_path(&mut self, path: &'hir hir::Path<'hir>, _id: hir::HirId) { + fn visit_path(&mut self, path: &hir::Path<'hir>, _id: hir::HirId) { for (index, enum_value) in paths::APPLICABILITY_VALUES.iter().enumerate() { if match_path(path, enum_value) { self.add_new_index(index); diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index be98344470b..e4d1ee195c4 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -176,7 +176,8 @@ impl LateLintPass<'_> for WildcardImports { format!("{import_source_snippet}::{imports_string}") }; - let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res { + // Glob imports always have a single resolution. + let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res[0] { (ENUM_GLOB_USE, "usage of wildcard import for enum variants") } else { (WILDCARD_IMPORTS, "usage of wildcard import") diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index fb9f4740ecc..ac6a566b9cd 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.67" +version = "0.1.68" edition = "2021" publish = false diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 6bcf0bbd7eb..49e5f283db0 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -566,7 +566,7 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool { use UseTreeKind::*; match (l, r) { (Glob, Glob) => true, - (Simple(l, _, _), Simple(r, _, _)) => both(l, r, |l, r| eq_id(*l, *r)), + (Simple(l), Simple(r)) => both(l, r, |l, r| eq_id(*l, *r)), (Nested(l), Nested(r)) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)), _ => false, } diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index c6bf98b7b8b..43f0df145f0 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -69,7 +69,9 @@ fn lit_search_pat(lit: &LitKind) -> (Pat, Pat) { LitKind::Str(_, StrStyle::Cooked) => (Pat::Str("\""), Pat::Str("\"")), LitKind::Str(_, StrStyle::Raw(0)) => (Pat::Str("r"), Pat::Str("\"")), LitKind::Str(_, StrStyle::Raw(_)) => (Pat::Str("r#"), Pat::Str("#")), - LitKind::ByteStr(_) => (Pat::Str("b\""), Pat::Str("\"")), + LitKind::ByteStr(_, StrStyle::Cooked) => (Pat::Str("b\""), Pat::Str("\"")), + LitKind::ByteStr(_, StrStyle::Raw(0)) => (Pat::Str("br\""), Pat::Str("\"")), + LitKind::ByteStr(_, StrStyle::Raw(_)) => (Pat::Str("br#\""), Pat::Str("#")), LitKind::Byte(_) => (Pat::Str("b'"), Pat::Str("'")), LitKind::Char(_) => (Pat::Str("'"), Pat::Str("'")), LitKind::Int(_, LitIntType::Signed(IntTy::Isize)) => (Pat::Num, Pat::Str("isize")), diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 315aea9aa09..a67bd8d4600 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -210,7 +210,7 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant { match *lit { LitKind::Str(ref is, _) => Constant::Str(is.to_string()), LitKind::Byte(b) => Constant::Int(u128::from(b)), - LitKind::ByteStr(ref s) => Constant::Binary(Lrc::clone(s)), + LitKind::ByteStr(ref s, _) => Constant::Binary(Lrc::clone(s)), LitKind::Char(c) => Constant::Char(c), LitKind::Int(n, _) => Constant::Int(n), LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty { @@ -620,12 +620,7 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) - ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( int.try_into().expect("invalid f64 bit representation"), ))), - ty::RawPtr(type_and_mut) => { - if let ty::Uint(_) = type_and_mut.ty.kind() { - return Some(Constant::RawPtr(int.assert_bits(int.size()))); - } - None - }, + ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))), // FIXME: implement other conversions. _ => None, } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 09ed7255a2b..43e2d1ec826 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -97,7 +97,7 @@ use rustc_middle::hir::place::PlaceBase; use rustc_middle::ty as rustc_ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::binding::BindingMode; -use rustc_middle::ty::fast_reject::SimplifiedTypeGen::{ +use rustc_middle::ty::fast_reject::SimplifiedType::{ ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType, PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType, }; diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index d13b34a66cc..77c5f115542 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -208,6 +208,12 @@ pub fn is_panic(cx: &LateContext<'_>, def_id: DefId) -> bool { ) } +/// Is `def_id` of `assert!` or `debug_assert!` +pub fn is_assert_macro(cx: &LateContext<'_>, def_id: DefId) -> bool { + let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return false }; + matches!(name, sym::assert_macro | sym::debug_assert_macro) +} + pub enum PanicExpn<'a> { /// No arguments - `panic!()` Empty, diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 6417f0f3c71..9ca50105ae5 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -20,7 +20,6 @@ pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", " pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"]; pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"]; pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; -pub const CORE_ITER_COLLECT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "collect"]; pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"]; pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"]; pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"]; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 480e8e55cf3..e5d7da68281 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -82,7 +82,7 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { ty::Ref(_, _, hir::Mutability::Mut) => { return Err((span, "mutable references in const fn are unstable".into())); }, - ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), + ty::Alias(ty::Opaque, ..) => return Err((span, "`impl Trait` in const fn is unstable".into())), ty::FnPtr(..) => { return Err((span, "function pointers in const fn are unstable".into())); }, @@ -301,11 +301,7 @@ fn check_terminator<'tcx>( check_operand(tcx, value, span, body) }, - TerminatorKind::SwitchInt { - discr, - switch_ty: _, - targets: _, - } => check_operand(tcx, discr, span, body), + TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body), TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())), TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 81b08ae5600..2773da70d78 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -16,8 +16,8 @@ use rustc_infer::infer::{ use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::{ - self, AdtDef, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind, - ProjectionTy, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, + self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate, + PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, VariantDef, VariantDiscr, }; use rustc_middle::ty::{GenericArg, GenericArgKind}; @@ -69,50 +69,66 @@ pub fn contains_adt_constructor<'tcx>(ty: Ty<'tcx>, adt: AdtDef<'tcx>) -> bool { /// This method also recurses into opaque type predicates, so call it with `impl Trait<U>` and `U` /// will also return `true`. pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, needle: Ty<'tcx>) -> bool { - ty.walk().any(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => { - if inner_ty == needle { - return true; - } + fn contains_ty_adt_constructor_opaque_inner<'tcx>( + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + needle: Ty<'tcx>, + seen: &mut FxHashSet<DefId>, + ) -> bool { + ty.walk().any(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => { + if inner_ty == needle { + return true; + } - if inner_ty.ty_adt_def() == needle.ty_adt_def() { - return true; - } + if inner_ty.ty_adt_def() == needle.ty_adt_def() { + return true; + } - if let ty::Opaque(def_id, _) = *inner_ty.kind() { - for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { - match predicate.kind().skip_binder() { - // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through - // and check substituions to find `U`. - ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { - if trait_predicate - .trait_ref - .substs - .types() - .skip(1) // Skip the implicit `Self` generic parameter - .any(|ty| contains_ty_adt_constructor_opaque(cx, ty, needle)) - { - return true; - } - }, - // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`, - // so we check the term for `U`. - ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => { - if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() { - if contains_ty_adt_constructor_opaque(cx, ty, needle) { + if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() { + if !seen.insert(def_id) { + return false; + } + + for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { + match predicate.kind().skip_binder() { + // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through + // and check substituions to find `U`. + ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { + if trait_predicate + .trait_ref + .substs + .types() + .skip(1) // Skip the implicit `Self` generic parameter + .any(|ty| contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen)) + { return true; } - }; - }, - _ => (), + }, + // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`, + // so we check the term for `U`. + ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => { + if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() { + if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) { + return true; + } + }; + }, + _ => (), + } } } - } - false - }, - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, - }) + false + }, + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + }) + } + + // A hash set to ensure that the same opaque type (`impl Trait` in RPIT or TAIT) is not + // visited twice. + let mut seen = FxHashSet::default(); + contains_ty_adt_constructor_opaque_inner(cx, ty, needle, &mut seen) } /// Resolves `<T as Iterator>::Item` for `T` @@ -250,7 +266,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { is_must_use_ty(cx, *ty) }, ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), - ty::Opaque(def_id, _) => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { @@ -631,7 +647,9 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t Some(ExprFnSig::Closure(decl, subs.as_closure().sig())) }, ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), - ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)), + ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { + sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id)) + }, ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), ty::Dynamic(bounds, _, _) => { let lang_items = cx.tcx.lang_items(); @@ -650,7 +668,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t _ => None, } }, - ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) { + ty::Alias(ty::Projection, proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) { Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty), _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), }, @@ -685,8 +703,7 @@ fn sig_from_bounds<'tcx>( inputs = Some(i); }, PredicateKind::Clause(ty::Clause::Projection(p)) - if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() - && p.projection_ty.self_ty() == ty => + if Some(p.projection_ty.def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty => { if output.is_some() { // Multiple different fn trait impls. Is this even allowed? @@ -701,14 +718,14 @@ fn sig_from_bounds<'tcx>( inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id)) } -fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option<ExprFnSig<'tcx>> { +fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option<ExprFnSig<'tcx>> { let mut inputs = None; let mut output = None; let lang_items = cx.tcx.lang_items(); for (pred, _) in cx .tcx - .bound_explicit_item_bounds(ty.item_def_id) + .bound_explicit_item_bounds(ty.def_id) .subst_iter_copied(cx.tcx, ty.substs) { match pred.kind().skip_binder() { @@ -726,7 +743,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O inputs = Some(i); }, PredicateKind::Clause(ty::Clause::Projection(p)) - if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => + if Some(p.projection_ty.def_id) == lang_items.fn_once_output() => { if output.is_some() { // Multiple different fn trait impls. Is this even allowed? @@ -980,13 +997,13 @@ pub fn make_projection<'tcx>( container_id: DefId, assoc_ty: Symbol, substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>, -) -> Option<ProjectionTy<'tcx>> { +) -> Option<AliasTy<'tcx>> { fn helper<'tcx>( tcx: TyCtxt<'tcx>, container_id: DefId, assoc_ty: Symbol, substs: SubstsRef<'tcx>, - ) -> Option<ProjectionTy<'tcx>> { + ) -> Option<AliasTy<'tcx>> { let Some(assoc_item) = tcx .associated_items(container_id) .find_by_name_and_kind(tcx, Ident::with_dummy_span(assoc_ty), AssocKind::Type, container_id) @@ -1039,10 +1056,7 @@ pub fn make_projection<'tcx>( } } - Some(ProjectionTy { - substs, - item_def_id: assoc_item.def_id, - }) + Some(tcx.mk_alias_ty(assoc_item.def_id, substs)) } helper( tcx, @@ -1065,7 +1079,7 @@ pub fn make_normalized_projection<'tcx>( assoc_ty: Symbol, substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>, ) -> Option<Ty<'tcx>> { - fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: ProjectionTy<'tcx>) -> Option<Ty<'tcx>> { + fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> { #[cfg(debug_assertions)] if let Some((i, subst)) = ty .substs @@ -1081,7 +1095,7 @@ pub fn make_normalized_projection<'tcx>( ); return None; } - match tcx.try_normalize_erasing_regions(param_env, tcx.mk_projection(ty.item_def_id, ty.substs)) { + match tcx.try_normalize_erasing_regions(param_env, tcx.mk_projection(ty.def_id, ty.substs)) { Ok(ty) => Some(ty), Err(e) => { debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}"); diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index 797722cfc1f..ab3976a13bd 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -128,7 +128,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { } } - fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) { + fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) { if let hir::def::Res::Local(id) = path.res { if self.binding_ids.contains(&id) { self.usage_found = true; diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml index 082570f1fe5..c01e1062cb5 100644 --- a/declare_clippy_lint/Cargo.toml +++ b/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.67" +version = "0.1.68" edition = "2021" publish = false diff --git a/rust-toolchain b/rust-toolchain index 19fee38db46..8e21cef32ab 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-12-01" +channel = "nightly-2022-12-17" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/rustc_tools_util/CHANGELOG.md b/rustc_tools_util/CHANGELOG.md new file mode 100644 index 00000000000..1b351da2e7b --- /dev/null +++ b/rustc_tools_util/CHANGELOG.md @@ -0,0 +1,6 @@ +# Changelog + +## Version 0.3.0 + +* Added `setup_version_info!();` macro for automated scripts. +* `get_version_info!()` no longer requires the user to import `rustc_tools_util::VersionInfo` and `std::env` diff --git a/rustc_tools_util/Cargo.toml b/rustc_tools_util/Cargo.toml index 89c3d6aaa89..877049ae7d0 100644 --- a/rustc_tools_util/Cargo.toml +++ b/rustc_tools_util/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustc_tools_util" -version = "0.2.1" +version = "0.3.0" description = "small helper to generate version information for git packages" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/rustc_tools_util/README.md b/rustc_tools_util/README.md index e947f9c7e66..eefc661f963 100644 --- a/rustc_tools_util/README.md +++ b/rustc_tools_util/README.md @@ -13,43 +13,39 @@ build = "build.rs" List rustc_tools_util as regular AND build dependency. ````toml [dependencies] -rustc_tools_util = "0.2.1" +rustc_tools_util = "0.3.0" [build-dependencies] -rustc_tools_util = "0.2.1" +rustc_tools_util = "0.3.0" ```` In `build.rs`, generate the data in your `main()` -````rust + +```rust fn main() { - println!( - "cargo:rustc-env=GIT_HASH={}", - rustc_tools_util::get_commit_hash().unwrap_or_default() - ); - println!( - "cargo:rustc-env=COMMIT_DATE={}", - rustc_tools_util::get_commit_date().unwrap_or_default() - ); - println!( - "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}", - rustc_tools_util::get_channel().unwrap_or_default() - ); + rustc_tools_util::setup_version_info!(); } - -```` +``` Use the version information in your main.rs -````rust -use rustc_tools_util::*; +```rust fn show_version() { let version_info = rustc_tools_util::get_version_info!(); println!("{}", version_info); } -```` +``` + This gives the following output in clippy: -`clippy 0.0.212 (a416c5e 2018-12-14)` +`clippy 0.1.66 (a28f3c8 2022-11-20)` + +## Repository + +This project is part of the rust-lang/rust-clippy repository. The source code +can be found under `./rustc_tools_util/`. +The changelog for `rustc_tools_util` is available under: +[`rustc_tools_util/CHANGELOG.md`](https://github.com/rust-lang/rust-clippy/blob/master/rustc_tools_util/CHANGELOG.md) ## License diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs index 01d25c53126..4c1d8c3733d 100644 --- a/rustc_tools_util/src/lib.rs +++ b/rustc_tools_util/src/lib.rs @@ -1,20 +1,20 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] -use std::env; - +/// This macro creates the version string during compilation from the +/// current environment #[macro_export] macro_rules! get_version_info { () => {{ - let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap(); - let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap(); - let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap(); - let crate_name = String::from(env!("CARGO_PKG_NAME")); + let major = std::env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap(); + let minor = std::env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap(); + let patch = std::env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap(); + let crate_name = String::from(std::env!("CARGO_PKG_NAME")); - let host_compiler = option_env!("RUSTC_RELEASE_CHANNEL").map(str::to_string); - let commit_hash = option_env!("GIT_HASH").map(str::to_string); - let commit_date = option_env!("COMMIT_DATE").map(str::to_string); + let host_compiler = std::option_env!("RUSTC_RELEASE_CHANNEL").map(str::to_string); + let commit_hash = std::option_env!("GIT_HASH").map(str::to_string); + let commit_date = std::option_env!("COMMIT_DATE").map(str::to_string); - VersionInfo { + $crate::VersionInfo { major, minor, patch, @@ -26,6 +26,24 @@ macro_rules! get_version_info { }}; } +/// This macro can be used in `build.rs` to automatically set the needed +/// environment values, namely `GIT_HASH`, `COMMIT_DATE` and +/// `RUSTC_RELEASE_CHANNEL` +#[macro_export] +macro_rules! setup_version_info { + () => {{ + println!( + "cargo:rustc-env=GIT_HASH={}", + $crate::get_commit_hash().unwrap_or_default() + ); + println!( + "cargo:rustc-env=COMMIT_DATE={}", + $crate::get_commit_date().unwrap_or_default() + ); + println!("cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}", $crate::get_channel()); + }}; +} + // some code taken and adapted from RLS and cargo pub struct VersionInfo { pub major: u8, @@ -101,7 +119,7 @@ pub fn get_commit_date() -> Option<String> { #[must_use] pub fn get_channel() -> String { - match env::var("CFG_RELEASE_CHANNEL") { + match std::env::var("CFG_RELEASE_CHANNEL") { Ok(channel) => channel, Err(_) => { // if that failed, try to ask rustc -V, do some parsing and find out @@ -136,8 +154,8 @@ mod test { fn test_struct_local() { let vi = get_version_info!(); assert_eq!(vi.major, 0); - assert_eq!(vi.minor, 2); - assert_eq!(vi.patch, 1); + assert_eq!(vi.minor, 3); + assert_eq!(vi.patch, 0); assert_eq!(vi.crate_name, "rustc_tools_util"); // hard to make positive tests for these since they will always change assert!(vi.commit_hash.is_none()); @@ -147,7 +165,7 @@ mod test { #[test] fn test_display_local() { let vi = get_version_info!(); - assert_eq!(vi.to_string(), "rustc_tools_util 0.2.1"); + assert_eq!(vi.to_string(), "rustc_tools_util 0.3.0"); } #[test] @@ -156,7 +174,7 @@ mod test { let s = format!("{vi:?}"); assert_eq!( s, - "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 2, patch: 1 }" + "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 3, patch: 0 }" ); } } diff --git a/src/driver.rs b/src/driver.rs index 9ec4df8e651..bcc096c570e 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -19,7 +19,6 @@ extern crate rustc_span; use rustc_interface::interface; use rustc_session::parse::ParseSess; use rustc_span::symbol::Symbol; -use rustc_tools_util::VersionInfo; use std::borrow::Cow; use std::env; diff --git a/src/main.rs b/src/main.rs index d418d2daa31..7a78b32620d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,6 @@ // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] -use rustc_tools_util::VersionInfo; use std::env; use std::path::PathBuf; use std::process::{self, Command}; diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr index 2a240cc249b..3ca45404e44 100644 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr +++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr @@ -7,14 +7,6 @@ LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"]; = help: convert all references to use `sym::Deref` = note: `-D clippy::unnecessary-def-path` implied by `-D warnings` -error: hardcoded path to a diagnostic item - --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43 - | -LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: convert all references to use `sym::deref_method` - error: hardcoded path to a language item --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40 | @@ -23,5 +15,13 @@ LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"] | = help: convert all references to use `LangItem::DerefMut` +error: hardcoded path to a diagnostic item + --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43 + | +LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: convert all references to use `sym::deref_method` + error: aborting due to 3 previous errors diff --git a/tests/ui/crashes/ice-10044.rs b/tests/ui/crashes/ice-10044.rs new file mode 100644 index 00000000000..65f38fe7118 --- /dev/null +++ b/tests/ui/crashes/ice-10044.rs @@ -0,0 +1,3 @@ +fn main() { + [0; usize::MAX]; +} diff --git a/tests/ui/crashes/ice-10044.stderr b/tests/ui/crashes/ice-10044.stderr new file mode 100644 index 00000000000..731f8265ad6 --- /dev/null +++ b/tests/ui/crashes/ice-10044.stderr @@ -0,0 +1,10 @@ +error: statement with no effect + --> $DIR/ice-10044.rs:2:5 + | +LL | [0; usize::MAX]; + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::no-effect` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/explicit_counter_loop.rs b/tests/ui/explicit_counter_loop.rs index 6eddc01e2c4..46565a97f00 100644 --- a/tests/ui/explicit_counter_loop.rs +++ b/tests/ui/explicit_counter_loop.rs @@ -189,3 +189,33 @@ mod issue_7920 { } } } + +mod issue_10058 { + pub fn test() { + // should not lint since we are increasing counter potentially more than once in the loop + let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1]; + let mut counter = 0; + for value in values { + counter += 1; + + if value == 0 { + continue; + } + + counter += 1; + } + } + + pub fn test2() { + // should not lint since we are increasing counter potentially more than once in the loop + let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1]; + let mut counter = 0; + for value in values { + counter += 1; + + if value != 0 { + counter += 1; + } + } + } +} diff --git a/tests/ui/fn_null_check.rs b/tests/ui/fn_null_check.rs new file mode 100644 index 00000000000..df5bc8420d5 --- /dev/null +++ b/tests/ui/fn_null_check.rs @@ -0,0 +1,21 @@ +#![allow(unused)] +#![warn(clippy::fn_null_check)] +#![allow(clippy::cmp_null)] +#![allow(clippy::ptr_eq)] +#![allow(clippy::zero_ptr)] + +pub const ZPTR: *const () = 0 as *const _; +pub const NOT_ZPTR: *const () = 1 as *const _; + +fn main() { + let fn_ptr = main; + + if (fn_ptr as *mut ()).is_null() {} + if (fn_ptr as *const u8).is_null() {} + if (fn_ptr as *const ()) == std::ptr::null() {} + if (fn_ptr as *const ()) == (0 as *const ()) {} + if (fn_ptr as *const ()) == ZPTR {} + + // no lint + if (fn_ptr as *const ()) == NOT_ZPTR {} +} diff --git a/tests/ui/fn_null_check.stderr b/tests/ui/fn_null_check.stderr new file mode 100644 index 00000000000..660dd323979 --- /dev/null +++ b/tests/ui/fn_null_check.stderr @@ -0,0 +1,43 @@ +error: function pointer assumed to be nullable, even though it isn't + --> $DIR/fn_null_check.rs:13:8 + | +LL | if (fn_ptr as *mut ()).is_null() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value + = note: `-D clippy::fn-null-check` implied by `-D warnings` + +error: function pointer assumed to be nullable, even though it isn't + --> $DIR/fn_null_check.rs:14:8 + | +LL | if (fn_ptr as *const u8).is_null() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value + +error: function pointer assumed to be nullable, even though it isn't + --> $DIR/fn_null_check.rs:15:8 + | +LL | if (fn_ptr as *const ()) == std::ptr::null() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value + +error: function pointer assumed to be nullable, even though it isn't + --> $DIR/fn_null_check.rs:16:8 + | +LL | if (fn_ptr as *const ()) == (0 as *const ()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value + +error: function pointer assumed to be nullable, even though it isn't + --> $DIR/fn_null_check.rs:17:8 + | +LL | if (fn_ptr as *const ()) == ZPTR {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value + +error: aborting due to 5 previous errors + diff --git a/tests/ui/macro_use_imports.stderr b/tests/ui/macro_use_imports.stderr index bf7b6edd0e3..61843124ccd 100644 --- a/tests/ui/macro_use_imports.stderr +++ b/tests/ui/macro_use_imports.stderr @@ -1,8 +1,8 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:23:5 + --> $DIR/macro_use_imports.rs:25:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` | = note: `-D clippy::macro-use-imports` implied by `-D warnings` @@ -13,10 +13,10 @@ LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:25:5 + --> $DIR/macro_use_imports.rs:23:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};` error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:19:5 diff --git a/tests/ui/manual_filter.fixed b/tests/ui/manual_filter.fixed index 3553291b87d..ef6780dc96d 100644 --- a/tests/ui/manual_filter.fixed +++ b/tests/ui/manual_filter.fixed @@ -116,4 +116,45 @@ fn main() { }, None => None, }; + + match Some(20) { + // Don't Lint, because `Some(3*x)` is not `None` + None => None, + Some(x) => { + if x > 0 { + Some(3 * x) + } else { + Some(x) + } + }, + }; + + // Don't lint: https://github.com/rust-lang/rust-clippy/issues/10088 + let result = if let Some(a) = maybe_some() { + if let Some(b) = maybe_some() { + Some(a + b) + } else { + Some(a) + } + } else { + None + }; + + let allowed_integers = vec![3, 4, 5, 6]; + // Don't lint, since there's a side effect in the else branch + match Some(21) { + Some(x) => { + if allowed_integers.contains(&x) { + Some(x) + } else { + println!("Invalid integer: {x:?}"); + None + } + }, + None => None, + }; +} + +fn maybe_some() -> Option<u32> { + Some(0) } diff --git a/tests/ui/manual_filter.rs b/tests/ui/manual_filter.rs index aa9f90f752b..ea0ce83172b 100644 --- a/tests/ui/manual_filter.rs +++ b/tests/ui/manual_filter.rs @@ -240,4 +240,45 @@ fn main() { }, None => None, }; + + match Some(20) { + // Don't Lint, because `Some(3*x)` is not `None` + None => None, + Some(x) => { + if x > 0 { + Some(3 * x) + } else { + Some(x) + } + }, + }; + + // Don't lint: https://github.com/rust-lang/rust-clippy/issues/10088 + let result = if let Some(a) = maybe_some() { + if let Some(b) = maybe_some() { + Some(a + b) + } else { + Some(a) + } + } else { + None + }; + + let allowed_integers = vec![3, 4, 5, 6]; + // Don't lint, since there's a side effect in the else branch + match Some(21) { + Some(x) => { + if allowed_integers.contains(&x) { + Some(x) + } else { + println!("Invalid integer: {x:?}"); + None + } + }, + None => None, + }; +} + +fn maybe_some() -> Option<u32> { + Some(0) } diff --git a/tests/ui/manual_is_ascii_check.fixed b/tests/ui/manual_is_ascii_check.fixed index 231ba83b142..5b2b44c2fdb 100644 --- a/tests/ui/manual_is_ascii_check.fixed +++ b/tests/ui/manual_is_ascii_check.fixed @@ -15,6 +15,19 @@ fn main() { assert!('x'.is_ascii_alphabetic()); assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_')); + + b'0'.is_ascii_digit(); + b'a'.is_ascii_lowercase(); + b'A'.is_ascii_uppercase(); + + '0'.is_ascii_digit(); + 'a'.is_ascii_lowercase(); + 'A'.is_ascii_uppercase(); + + let cool_letter = &'g'; + cool_letter.is_ascii_digit(); + cool_letter.is_ascii_lowercase(); + cool_letter.is_ascii_uppercase(); } #[clippy::msrv = "1.23"] diff --git a/tests/ui/manual_is_ascii_check.rs b/tests/ui/manual_is_ascii_check.rs index 39ee6151c56..c9433f33a1b 100644 --- a/tests/ui/manual_is_ascii_check.rs +++ b/tests/ui/manual_is_ascii_check.rs @@ -15,6 +15,19 @@ fn main() { assert!(matches!('x', 'A'..='Z' | 'a'..='z')); assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_')); + + (b'0'..=b'9').contains(&b'0'); + (b'a'..=b'z').contains(&b'a'); + (b'A'..=b'Z').contains(&b'A'); + + ('0'..='9').contains(&'0'); + ('a'..='z').contains(&'a'); + ('A'..='Z').contains(&'A'); + + let cool_letter = &'g'; + ('0'..='9').contains(cool_letter); + ('a'..='z').contains(cool_letter); + ('A'..='Z').contains(cool_letter); } #[clippy::msrv = "1.23"] diff --git a/tests/ui/manual_is_ascii_check.stderr b/tests/ui/manual_is_ascii_check.stderr index 397cbe05c82..ee60188506d 100644 --- a/tests/ui/manual_is_ascii_check.stderr +++ b/tests/ui/manual_is_ascii_check.stderr @@ -43,28 +43,82 @@ LL | assert!(matches!('x', 'A'..='Z' | 'a'..='z')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()` error: manual check for common ascii range - --> $DIR/manual_is_ascii_check.rs:29:13 + --> $DIR/manual_is_ascii_check.rs:19:5 + | +LL | (b'0'..=b'9').contains(&b'0'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'0'.is_ascii_digit()` + +error: manual check for common ascii range + --> $DIR/manual_is_ascii_check.rs:20:5 + | +LL | (b'a'..=b'z').contains(&b'a'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'a'.is_ascii_lowercase()` + +error: manual check for common ascii range + --> $DIR/manual_is_ascii_check.rs:21:5 + | +LL | (b'A'..=b'Z').contains(&b'A'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'A'.is_ascii_uppercase()` + +error: manual check for common ascii range + --> $DIR/manual_is_ascii_check.rs:23:5 + | +LL | ('0'..='9').contains(&'0'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'0'.is_ascii_digit()` + +error: manual check for common ascii range + --> $DIR/manual_is_ascii_check.rs:24:5 + | +LL | ('a'..='z').contains(&'a'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'a'.is_ascii_lowercase()` + +error: manual check for common ascii range + --> $DIR/manual_is_ascii_check.rs:25:5 + | +LL | ('A'..='Z').contains(&'A'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'A'.is_ascii_uppercase()` + +error: manual check for common ascii range + --> $DIR/manual_is_ascii_check.rs:28:5 + | +LL | ('0'..='9').contains(cool_letter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_digit()` + +error: manual check for common ascii range + --> $DIR/manual_is_ascii_check.rs:29:5 + | +LL | ('a'..='z').contains(cool_letter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_lowercase()` + +error: manual check for common ascii range + --> $DIR/manual_is_ascii_check.rs:30:5 + | +LL | ('A'..='Z').contains(cool_letter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_uppercase()` + +error: manual check for common ascii range + --> $DIR/manual_is_ascii_check.rs:42:13 | LL | assert!(matches!(b'1', b'0'..=b'9')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()` error: manual check for common ascii range - --> $DIR/manual_is_ascii_check.rs:30:13 + --> $DIR/manual_is_ascii_check.rs:43:13 | LL | assert!(matches!('X', 'A'..='Z')); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()` error: manual check for common ascii range - --> $DIR/manual_is_ascii_check.rs:31:13 + --> $DIR/manual_is_ascii_check.rs:44:13 | LL | assert!(matches!('x', 'A'..='Z' | 'a'..='z')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()` error: manual check for common ascii range - --> $DIR/manual_is_ascii_check.rs:41:23 + --> $DIR/manual_is_ascii_check.rs:54:23 | LL | const FOO: bool = matches!('x', '0'..='9'); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_digit()` -error: aborting due to 11 previous errors +error: aborting due to 20 previous errors diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 4386aaec49e..d451be1f389 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -1,6 +1,7 @@ // run-rustfix #![feature(lint_reasons)] +#![feature(yeet_expr)] #![allow(unused)] #![allow( clippy::if_same_then_else, @@ -272,4 +273,8 @@ mod issue9416 { } } +fn issue9947() -> Result<(), String> { + do yeet "hello"; +} + fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 666dc54b76b..e1a1bea2c0b 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -1,6 +1,7 @@ // run-rustfix #![feature(lint_reasons)] +#![feature(yeet_expr)] #![allow(unused)] #![allow( clippy::if_same_then_else, @@ -282,4 +283,8 @@ mod issue9416 { } } +fn issue9947() -> Result<(), String> { + do yeet "hello"; +} + fn main() {} diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index a8b5d86cd55..ca2253e6586 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -1,5 +1,5 @@ error: unneeded `return` statement - --> $DIR/needless_return.rs:26:5 + --> $DIR/needless_return.rs:27:5 | LL | return true; | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:30:5 + --> $DIR/needless_return.rs:31:5 | LL | return true; | ^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:35:9 + --> $DIR/needless_return.rs:36:9 | LL | return true; | ^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:37:9 + --> $DIR/needless_return.rs:38:9 | LL | return false; | ^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | return false; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:43:17 + --> $DIR/needless_return.rs:44:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | true => return false, = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:45:13 + --> $DIR/needless_return.rs:46:13 | LL | return true; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:52:9 + --> $DIR/needless_return.rs:53:9 | LL | return true; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:54:16 + --> $DIR/needless_return.rs:55:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | let _ = || return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:58:5 + --> $DIR/needless_return.rs:59:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | return the_answer!(); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:61:21 + --> $DIR/needless_return.rs:62:21 | LL | fn test_void_fun() { | _____________________^ @@ -82,7 +82,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:66:11 + --> $DIR/needless_return.rs:67:11 | LL | if b { | ___________^ @@ -92,7 +92,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:68:13 + --> $DIR/needless_return.rs:69:13 | LL | } else { | _____________^ @@ -102,7 +102,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:76:14 + --> $DIR/needless_return.rs:77:14 | LL | _ => return, | ^^^^^^ @@ -110,7 +110,7 @@ LL | _ => return, = help: replace `return` with a unit value error: unneeded `return` statement - --> $DIR/needless_return.rs:84:24 + --> $DIR/needless_return.rs:85:24 | LL | let _ = 42; | ________________________^ @@ -120,7 +120,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:87:14 + --> $DIR/needless_return.rs:88:14 | LL | _ => return, | ^^^^^^ @@ -128,7 +128,7 @@ LL | _ => return, = help: replace `return` with a unit value error: unneeded `return` statement - --> $DIR/needless_return.rs:100:9 + --> $DIR/needless_return.rs:101:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | return String::from("test"); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:102:9 + --> $DIR/needless_return.rs:103:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | return String::new(); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:124:32 + --> $DIR/needless_return.rs:125:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ @@ -152,7 +152,7 @@ LL | bar.unwrap_or_else(|_| return) = help: replace `return` with an empty block error: unneeded `return` statement - --> $DIR/needless_return.rs:128:21 + --> $DIR/needless_return.rs:129:21 | LL | let _ = || { | _____________________^ @@ -162,7 +162,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:131:20 + --> $DIR/needless_return.rs:132:20 | LL | let _ = || return; | ^^^^^^ @@ -170,7 +170,7 @@ LL | let _ = || return; = help: replace `return` with an empty block error: unneeded `return` statement - --> $DIR/needless_return.rs:137:32 + --> $DIR/needless_return.rs:138:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ @@ -178,7 +178,7 @@ LL | res.unwrap_or_else(|_| return Foo) = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:146:5 + --> $DIR/needless_return.rs:147:5 | LL | return true; | ^^^^^^^^^^^ @@ -186,7 +186,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:150:5 + --> $DIR/needless_return.rs:151:5 | LL | return true; | ^^^^^^^^^^^ @@ -194,7 +194,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:155:9 + --> $DIR/needless_return.rs:156:9 | LL | return true; | ^^^^^^^^^^^ @@ -202,7 +202,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:157:9 + --> $DIR/needless_return.rs:158:9 | LL | return false; | ^^^^^^^^^^^^ @@ -210,7 +210,7 @@ LL | return false; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:163:17 + --> $DIR/needless_return.rs:164:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -218,7 +218,7 @@ LL | true => return false, = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:165:13 + --> $DIR/needless_return.rs:166:13 | LL | return true; | ^^^^^^^^^^^ @@ -226,7 +226,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:172:9 + --> $DIR/needless_return.rs:173:9 | LL | return true; | ^^^^^^^^^^^ @@ -234,7 +234,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:174:16 + --> $DIR/needless_return.rs:175:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -242,7 +242,7 @@ LL | let _ = || return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:178:5 + --> $DIR/needless_return.rs:179:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -250,7 +250,7 @@ LL | return the_answer!(); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:181:33 + --> $DIR/needless_return.rs:182:33 | LL | async fn async_test_void_fun() { | _________________________________^ @@ -260,7 +260,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:186:11 + --> $DIR/needless_return.rs:187:11 | LL | if b { | ___________^ @@ -270,7 +270,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:188:13 + --> $DIR/needless_return.rs:189:13 | LL | } else { | _____________^ @@ -280,7 +280,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:196:14 + --> $DIR/needless_return.rs:197:14 | LL | _ => return, | ^^^^^^ @@ -288,7 +288,7 @@ LL | _ => return, = help: replace `return` with a unit value error: unneeded `return` statement - --> $DIR/needless_return.rs:209:9 + --> $DIR/needless_return.rs:210:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -296,7 +296,7 @@ LL | return String::from("test"); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:211:9 + --> $DIR/needless_return.rs:212:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -304,7 +304,7 @@ LL | return String::new(); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:227:5 + --> $DIR/needless_return.rs:228:5 | LL | return format!("Hello {}", "world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -312,7 +312,7 @@ LL | return format!("Hello {}", "world!"); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:238:9 + --> $DIR/needless_return.rs:239:9 | LL | return true; | ^^^^^^^^^^^ @@ -320,7 +320,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:240:9 + --> $DIR/needless_return.rs:241:9 | LL | return false; | ^^^^^^^^^^^^ @@ -328,7 +328,7 @@ LL | return false; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:247:13 + --> $DIR/needless_return.rs:248:13 | LL | return 10; | ^^^^^^^^^ @@ -336,7 +336,7 @@ LL | return 10; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:250:13 + --> $DIR/needless_return.rs:251:13 | LL | return 100; | ^^^^^^^^^^ @@ -344,7 +344,7 @@ LL | return 100; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:258:9 + --> $DIR/needless_return.rs:259:9 | LL | return 0; | ^^^^^^^^ @@ -352,7 +352,7 @@ LL | return 0; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:265:13 + --> $DIR/needless_return.rs:266:13 | LL | return *(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -360,7 +360,7 @@ LL | return *(x as *const isize); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:267:13 + --> $DIR/needless_return.rs:268:13 | LL | return !*(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -368,7 +368,7 @@ LL | return !*(x as *const isize); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:274:20 + --> $DIR/needless_return.rs:275:20 | LL | let _ = 42; | ____________________^ @@ -379,7 +379,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:281:20 + --> $DIR/needless_return.rs:282:20 | LL | let _ = 42; return; | ^^^^^^^ diff --git a/tests/ui/new_ret_no_self.rs b/tests/ui/new_ret_no_self.rs index f69982d63a8..beec42f08bb 100644 --- a/tests/ui/new_ret_no_self.rs +++ b/tests/ui/new_ret_no_self.rs @@ -1,3 +1,4 @@ +#![feature(type_alias_impl_trait)] #![warn(clippy::new_ret_no_self)] #![allow(dead_code)] @@ -400,3 +401,25 @@ mod issue7344 { } } } + +mod issue10041 { + struct Bomb; + + impl Bomb { + // Hidden <Rhs = Self> default generic paramter. + pub fn new() -> impl PartialOrd { + 0i32 + } + } + + // TAIT with self-referencing bounds + type X = impl std::ops::Add<Output = X>; + + struct Bomb2; + + impl Bomb2 { + pub fn new() -> X { + 0i32 + } + } +} diff --git a/tests/ui/new_ret_no_self.stderr b/tests/ui/new_ret_no_self.stderr index bc13be47927..2eaebfb5cac 100644 --- a/tests/ui/new_ret_no_self.stderr +++ b/tests/ui/new_ret_no_self.stderr @@ -1,5 +1,5 @@ error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:49:5 + --> $DIR/new_ret_no_self.rs:50:5 | LL | / pub fn new(_: String) -> impl R<Item = u32> { LL | | S3 @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:81:5 + --> $DIR/new_ret_no_self.rs:82:5 | LL | / pub fn new() -> u32 { LL | | unimplemented!(); @@ -17,7 +17,7 @@ LL | | } | |_____^ error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:90:5 + --> $DIR/new_ret_no_self.rs:91:5 | LL | / pub fn new(_: String) -> u32 { LL | | unimplemented!(); @@ -25,7 +25,7 @@ LL | | } | |_____^ error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:126:5 + --> $DIR/new_ret_no_self.rs:127:5 | LL | / pub fn new() -> (u32, u32) { LL | | unimplemented!(); @@ -33,7 +33,7 @@ LL | | } | |_____^ error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:153:5 + --> $DIR/new_ret_no_self.rs:154:5 | LL | / pub fn new() -> *mut V { LL | | unimplemented!(); @@ -41,7 +41,7 @@ LL | | } | |_____^ error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:171:5 + --> $DIR/new_ret_no_self.rs:172:5 | LL | / pub fn new() -> Option<u32> { LL | | unimplemented!(); @@ -49,19 +49,19 @@ LL | | } | |_____^ error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:224:9 + --> $DIR/new_ret_no_self.rs:225:9 | LL | fn new() -> String; | ^^^^^^^^^^^^^^^^^^^ error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:236:9 + --> $DIR/new_ret_no_self.rs:237:9 | LL | fn new(_: String) -> String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:271:9 + --> $DIR/new_ret_no_self.rs:272:9 | LL | / fn new() -> (u32, u32) { LL | | unimplemented!(); @@ -69,7 +69,7 @@ LL | | } | |_________^ error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:298:9 + --> $DIR/new_ret_no_self.rs:299:9 | LL | / fn new() -> *mut V { LL | | unimplemented!(); @@ -77,7 +77,7 @@ LL | | } | |_________^ error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:368:9 + --> $DIR/new_ret_no_self.rs:369:9 | LL | / fn new(t: T) -> impl Into<i32> { LL | | 1 @@ -85,12 +85,28 @@ LL | | } | |_________^ error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:389:9 + --> $DIR/new_ret_no_self.rs:390:9 | LL | / fn new(t: T) -> impl Trait2<(), i32> { LL | | unimplemented!() LL | | } | |_________^ -error: aborting due to 12 previous errors +error: methods called `new` usually return `Self` + --> $DIR/new_ret_no_self.rs:410:9 + | +LL | / pub fn new() -> impl PartialOrd { +LL | | 0i32 +LL | | } + | |_________^ + +error: methods called `new` usually return `Self` + --> $DIR/new_ret_no_self.rs:421:9 + | +LL | / pub fn new() -> X { +LL | | 0i32 +LL | | } + | |_________^ + +error: aborting due to 14 previous errors diff --git a/tests/ui/permissions_set_readonly_false.rs b/tests/ui/permissions_set_readonly_false.rs new file mode 100644 index 00000000000..28c00d10094 --- /dev/null +++ b/tests/ui/permissions_set_readonly_false.rs @@ -0,0 +1,29 @@ +#![allow(unused)] +#![warn(clippy::permissions_set_readonly_false)] + +use std::fs::File; + +struct A; + +impl A { + pub fn set_readonly(&mut self, b: bool) {} +} + +fn set_readonly(b: bool) {} + +fn main() { + let f = File::create("foo.txt").unwrap(); + let metadata = f.metadata().unwrap(); + let mut permissions = metadata.permissions(); + // lint here + permissions.set_readonly(false); + // no lint + permissions.set_readonly(true); + + let mut a = A; + // no lint here - a is not of type std::fs::Permissions + a.set_readonly(false); + + // no lint here - plain function + set_readonly(false); +} diff --git a/tests/ui/permissions_set_readonly_false.stderr b/tests/ui/permissions_set_readonly_false.stderr new file mode 100644 index 00000000000..e7a8ee6cb19 --- /dev/null +++ b/tests/ui/permissions_set_readonly_false.stderr @@ -0,0 +1,13 @@ +error: call to `set_readonly` with argument `false` + --> $DIR/permissions_set_readonly_false.rs:19:5 + | +LL | permissions.set_readonly(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: on Unix platforms this results in the file being world writable + = help: you can set the desired permissions using `PermissionsExt`. For more information, see + https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html + = note: `-D clippy::permissions-set-readonly-false` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/seek_to_start_instead_of_rewind.fixed b/tests/ui/seek_to_start_instead_of_rewind.fixed index 9d0d1124c46..713cff604a1 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.fixed +++ b/tests/ui/seek_to_start_instead_of_rewind.fixed @@ -70,6 +70,12 @@ fn seek_to_end<T: Seek>(t: &mut T) { t.seek(SeekFrom::End(0)); } +// This should NOT trigger clippy warning because +// expr is used here +fn seek_to_start_in_let<T: Seek>(t: &mut T) { + let a = t.seek(SeekFrom::Start(0)).unwrap(); +} + fn main() { let mut f = OpenOptions::new() .write(true) diff --git a/tests/ui/seek_to_start_instead_of_rewind.rs b/tests/ui/seek_to_start_instead_of_rewind.rs index c5bc57cc3a7..467003a1a66 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.rs +++ b/tests/ui/seek_to_start_instead_of_rewind.rs @@ -70,6 +70,12 @@ fn seek_to_end<T: Seek>(t: &mut T) { t.seek(SeekFrom::End(0)); } +// This should NOT trigger clippy warning because +// expr is used here +fn seek_to_start_in_let<T: Seek>(t: &mut T) { + let a = t.seek(SeekFrom::Start(0)).unwrap(); +} + fn main() { let mut f = OpenOptions::new() .write(true) diff --git a/tests/ui/seek_to_start_instead_of_rewind.stderr b/tests/ui/seek_to_start_instead_of_rewind.stderr index 6cce025359f..342ec00fe72 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.stderr +++ b/tests/ui/seek_to_start_instead_of_rewind.stderr @@ -13,7 +13,7 @@ LL | t.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` error: used `seek` to go to the start of the stream - --> $DIR/seek_to_start_instead_of_rewind.rs:128:7 + --> $DIR/seek_to_start_instead_of_rewind.rs:134:7 | LL | f.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` diff --git a/tests/ui/transmute_null_to_fn.rs b/tests/ui/transmute_null_to_fn.rs new file mode 100644 index 00000000000..b3ea3d9039e --- /dev/null +++ b/tests/ui/transmute_null_to_fn.rs @@ -0,0 +1,28 @@ +#![allow(dead_code)] +#![warn(clippy::transmute_null_to_fn)] +#![allow(clippy::zero_ptr)] + +// Easy to lint because these only span one line. +fn one_liners() { + unsafe { + let _: fn() = std::mem::transmute(0 as *const ()); + let _: fn() = std::mem::transmute(std::ptr::null::<()>()); + } +} + +pub const ZPTR: *const usize = 0 as *const _; +pub const NOT_ZPTR: *const usize = 1 as *const _; + +fn transmute_const() { + unsafe { + // Should raise a lint. + let _: fn() = std::mem::transmute(ZPTR); + // Should NOT raise a lint. + let _: fn() = std::mem::transmute(NOT_ZPTR); + } +} + +fn main() { + one_liners(); + transmute_const(); +} diff --git a/tests/ui/transmute_null_to_fn.stderr b/tests/ui/transmute_null_to_fn.stderr new file mode 100644 index 00000000000..f0c65497d75 --- /dev/null +++ b/tests/ui/transmute_null_to_fn.stderr @@ -0,0 +1,27 @@ +error: transmuting a known null pointer into a function pointer + --> $DIR/transmute_null_to_fn.rs:8:23 + | +LL | let _: fn() = std::mem::transmute(0 as *const ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior + | + = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value + = note: `-D clippy::transmute-null-to-fn` implied by `-D warnings` + +error: transmuting a known null pointer into a function pointer + --> $DIR/transmute_null_to_fn.rs:9:23 + | +LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior + | + = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value + +error: transmuting a known null pointer into a function pointer + --> $DIR/transmute_null_to_fn.rs:19:23 + | +LL | let _: fn() = std::mem::transmute(ZPTR); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior + | + = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value + +error: aborting due to 3 previous errors + diff --git a/tests/ui/uninlined_format_args_panic.edition2018.fixed b/tests/ui/uninlined_format_args_panic.edition2018.fixed index 96cc0877960..52b5343c351 100644 --- a/tests/ui/uninlined_format_args_panic.edition2018.fixed +++ b/tests/ui/uninlined_format_args_panic.edition2018.fixed @@ -26,4 +26,7 @@ fn main() { panic!("p4 {var}"); } } + + assert!(var == 1, "p5 {}", var); + debug_assert!(var == 1, "p6 {}", var); } diff --git a/tests/ui/uninlined_format_args_panic.edition2021.fixed b/tests/ui/uninlined_format_args_panic.edition2021.fixed index faf8ca4d3a7..ee72065e28a 100644 --- a/tests/ui/uninlined_format_args_panic.edition2021.fixed +++ b/tests/ui/uninlined_format_args_panic.edition2021.fixed @@ -26,4 +26,7 @@ fn main() { panic!("p4 {var}"); } } + + assert!(var == 1, "p5 {var}"); + debug_assert!(var == 1, "p6 {var}"); } diff --git a/tests/ui/uninlined_format_args_panic.edition2021.stderr b/tests/ui/uninlined_format_args_panic.edition2021.stderr index 0f09c45f413..fc7b125080e 100644 --- a/tests/ui/uninlined_format_args_panic.edition2021.stderr +++ b/tests/ui/uninlined_format_args_panic.edition2021.stderr @@ -47,5 +47,29 @@ LL - panic!("p3 {var}", var = var); LL + panic!("p3 {var}"); | -error: aborting due to 4 previous errors +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args_panic.rs:30:5 + | +LL | assert!(var == 1, "p5 {}", var); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - assert!(var == 1, "p5 {}", var); +LL + assert!(var == 1, "p5 {var}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args_panic.rs:31:5 + | +LL | debug_assert!(var == 1, "p6 {}", var); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - debug_assert!(var == 1, "p6 {}", var); +LL + debug_assert!(var == 1, "p6 {var}"); + | + +error: aborting due to 6 previous errors diff --git a/tests/ui/uninlined_format_args_panic.rs b/tests/ui/uninlined_format_args_panic.rs index 6421c5bbed2..b4a0a0f496e 100644 --- a/tests/ui/uninlined_format_args_panic.rs +++ b/tests/ui/uninlined_format_args_panic.rs @@ -26,4 +26,7 @@ fn main() { panic!("p4 {var}"); } } + + assert!(var == 1, "p5 {}", var); + debug_assert!(var == 1, "p6 {}", var); } diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index 70ff08f3655..94b206d8e58 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -33,12 +33,71 @@ fn test_issue_3913() -> Result<(), std::io::Error> { Ok(()) } -fn test_issue_5833() -> Result<(), ()> { +fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() { let text = "foo\r\nbar\n\nbaz\n"; let lines = text.lines(); if Some("ok") == lines.into_iter().next() {} +} - Ok(()) +fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() { + let text = "foo\r\nbar\n\nbaz\n"; + let mut lines = text.lines(); + if Some("ok") == lines.next() {} +} + +fn lint_into_iter_on_expr_implementing_iterator() { + let text = "foo\r\nbar\n\nbaz\n"; + let mut lines = text.lines(); + if Some("ok") == lines.next() {} +} + +fn lint_into_iter_on_expr_implementing_iterator_2() { + let text = "foo\r\nbar\n\nbaz\n"; + if Some("ok") == text.lines().next() {} +} + +#[allow(const_item_mutation)] +fn lint_into_iter_on_const_implementing_iterator() { + const NUMBERS: std::ops::Range<i32> = 0..10; + let _ = NUMBERS.next(); +} + +fn lint_into_iter_on_const_implementing_iterator_2() { + const NUMBERS: std::ops::Range<i32> = 0..10; + let mut n = NUMBERS; + n.next(); +} + +#[derive(Clone, Copy)] +struct CopiableCounter { + counter: u32, +} + +impl Iterator for CopiableCounter { + type Item = u32; + + fn next(&mut self) -> Option<Self::Item> { + self.counter = self.counter.wrapping_add(1); + Some(self.counter) + } +} + +fn dont_lint_into_iter_on_copy_iter() { + let mut c = CopiableCounter { counter: 0 }; + assert_eq!(c.into_iter().next(), Some(1)); + assert_eq!(c.into_iter().next(), Some(1)); + assert_eq!(c.next(), Some(1)); + assert_eq!(c.next(), Some(2)); +} + +fn dont_lint_into_iter_on_static_copy_iter() { + static mut C: CopiableCounter = CopiableCounter { counter: 0 }; + unsafe { + assert_eq!(C.into_iter().next(), Some(1)); + assert_eq!(C.into_iter().next(), Some(1)); + assert_eq!(C.next(), Some(1)); + assert_eq!(C.next(), Some(2)); + } } fn main() { @@ -46,7 +105,15 @@ fn main() { test_generic2::<i32, i32>(10i32); test_questionmark().unwrap(); test_issue_3913().unwrap(); - test_issue_5833().unwrap(); + + dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr(); + lint_into_iter_on_mutable_local_implementing_iterator_in_expr(); + lint_into_iter_on_expr_implementing_iterator(); + lint_into_iter_on_expr_implementing_iterator_2(); + lint_into_iter_on_const_implementing_iterator(); + lint_into_iter_on_const_implementing_iterator_2(); + dont_lint_into_iter_on_copy_iter(); + dont_lint_into_iter_on_static_copy_iter(); let _: String = "foo".into(); let _: String = From::from("foo"); diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index f2444a8f436..c7ae927941b 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -33,12 +33,71 @@ fn test_issue_3913() -> Result<(), std::io::Error> { Ok(()) } -fn test_issue_5833() -> Result<(), ()> { +fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() { let text = "foo\r\nbar\n\nbaz\n"; let lines = text.lines(); if Some("ok") == lines.into_iter().next() {} +} - Ok(()) +fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() { + let text = "foo\r\nbar\n\nbaz\n"; + let mut lines = text.lines(); + if Some("ok") == lines.into_iter().next() {} +} + +fn lint_into_iter_on_expr_implementing_iterator() { + let text = "foo\r\nbar\n\nbaz\n"; + let mut lines = text.lines().into_iter(); + if Some("ok") == lines.next() {} +} + +fn lint_into_iter_on_expr_implementing_iterator_2() { + let text = "foo\r\nbar\n\nbaz\n"; + if Some("ok") == text.lines().into_iter().next() {} +} + +#[allow(const_item_mutation)] +fn lint_into_iter_on_const_implementing_iterator() { + const NUMBERS: std::ops::Range<i32> = 0..10; + let _ = NUMBERS.into_iter().next(); +} + +fn lint_into_iter_on_const_implementing_iterator_2() { + const NUMBERS: std::ops::Range<i32> = 0..10; + let mut n = NUMBERS.into_iter(); + n.next(); +} + +#[derive(Clone, Copy)] +struct CopiableCounter { + counter: u32, +} + +impl Iterator for CopiableCounter { + type Item = u32; + + fn next(&mut self) -> Option<Self::Item> { + self.counter = self.counter.wrapping_add(1); + Some(self.counter) + } +} + +fn dont_lint_into_iter_on_copy_iter() { + let mut c = CopiableCounter { counter: 0 }; + assert_eq!(c.into_iter().next(), Some(1)); + assert_eq!(c.into_iter().next(), Some(1)); + assert_eq!(c.next(), Some(1)); + assert_eq!(c.next(), Some(2)); +} + +fn dont_lint_into_iter_on_static_copy_iter() { + static mut C: CopiableCounter = CopiableCounter { counter: 0 }; + unsafe { + assert_eq!(C.into_iter().next(), Some(1)); + assert_eq!(C.into_iter().next(), Some(1)); + assert_eq!(C.next(), Some(1)); + assert_eq!(C.next(), Some(2)); + } } fn main() { @@ -46,7 +105,15 @@ fn main() { test_generic2::<i32, i32>(10i32); test_questionmark().unwrap(); test_issue_3913().unwrap(); - test_issue_5833().unwrap(); + + dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr(); + lint_into_iter_on_mutable_local_implementing_iterator_in_expr(); + lint_into_iter_on_expr_implementing_iterator(); + lint_into_iter_on_expr_implementing_iterator_2(); + lint_into_iter_on_const_implementing_iterator(); + lint_into_iter_on_const_implementing_iterator_2(); + dont_lint_into_iter_on_copy_iter(); + dont_lint_into_iter_on_static_copy_iter(); let _: String = "foo".into(); let _: String = From::from("foo"); diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 65ee3807fa9..be067c6843a 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -22,71 +22,101 @@ error: useless conversion to the same type: `i32` LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` +error: useless conversion to the same type: `std::str::Lines<'_>` + --> $DIR/useless_conversion.rs:45:22 + | +LL | if Some("ok") == lines.into_iter().next() {} + | ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines` + +error: useless conversion to the same type: `std::str::Lines<'_>` + --> $DIR/useless_conversion.rs:50:21 + | +LL | let mut lines = text.lines().into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` + +error: useless conversion to the same type: `std::str::Lines<'_>` + --> $DIR/useless_conversion.rs:56:22 + | +LL | if Some("ok") == text.lines().into_iter().next() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` + +error: useless conversion to the same type: `std::ops::Range<i32>` + --> $DIR/useless_conversion.rs:62:13 + | +LL | let _ = NUMBERS.into_iter().next(); + | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` + +error: useless conversion to the same type: `std::ops::Range<i32>` + --> $DIR/useless_conversion.rs:67:17 + | +LL | let mut n = NUMBERS.into_iter(); + | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` + error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:61:21 + --> $DIR/useless_conversion.rs:128:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:62:21 + --> $DIR/useless_conversion.rs:129:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:63:13 + --> $DIR/useless_conversion.rs:130:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:64:13 + --> $DIR/useless_conversion.rs:131:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:65:13 + --> $DIR/useless_conversion.rs:132:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter<i32>` - --> $DIR/useless_conversion.rs:66:13 + --> $DIR/useless_conversion.rs:133:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:67:21 + --> $DIR/useless_conversion.rs:134:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> $DIR/useless_conversion.rs:72:13 + --> $DIR/useless_conversion.rs:139:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` error: useless conversion to the same type: `Foo<'a'>` - --> $DIR/useless_conversion.rs:78:23 + --> $DIR/useless_conversion.rs:145:23 | LL | let _: Foo<'a'> = s2.into(); | ^^^^^^^^^ help: consider removing `.into()`: `s2` error: useless conversion to the same type: `Foo<'a'>` - --> $DIR/useless_conversion.rs:80:13 + --> $DIR/useless_conversion.rs:147:13 | LL | let _ = Foo::<'a'>::from(s3); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3` error: useless conversion to the same type: `std::vec::IntoIter<Foo<'a'>>` - --> $DIR/useless_conversion.rs:82:13 + --> $DIR/useless_conversion.rs:149:13 | LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` -error: aborting due to 14 previous errors +error: aborting due to 19 previous errors diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index ef55f1c31a8..0baec6f0b64 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -5,7 +5,6 @@ // the 2015 edition here is needed because edition 2018 changed the module system // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint // no longer detects some of the cases starting with Rust 2018. -// FIXME: We should likely add another edition 2021 test case for this lint #![warn(clippy::wildcard_imports)] #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index b8128514206..db591d56ab4 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -5,7 +5,6 @@ // the 2015 edition here is needed because edition 2018 changed the module system // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint // no longer detects some of the cases starting with Rust 2018. -// FIXME: We should likely add another edition 2021 test case for this lint #![warn(clippy::wildcard_imports)] #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index 626c1754fc8..6b469cdfc44 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -1,5 +1,5 @@ error: usage of wildcard import - --> $DIR/wildcard_imports.rs:16:5 + --> $DIR/wildcard_imports.rs:15:5 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` @@ -7,85 +7,85 @@ LL | use crate::fn_mod::*; = note: `-D clippy::wildcard-imports` implied by `-D warnings` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:17:5 + --> $DIR/wildcard_imports.rs:16:5 | LL | use crate::mod_mod::*; | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:18:5 + --> $DIR/wildcard_imports.rs:17:5 | LL | use crate::multi_fn_mod::*; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:20:5 + --> $DIR/wildcard_imports.rs:19:5 | LL | use crate::struct_mod::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:24:5 + --> $DIR/wildcard_imports.rs:23:5 | LL | use wildcard_imports_helper::inner::inner_for_self_import::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:25:5 + --> $DIR/wildcard_imports.rs:24:5 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:96:13 + --> $DIR/wildcard_imports.rs:95:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:102:75 + --> $DIR/wildcard_imports.rs:101:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:103:13 + --> $DIR/wildcard_imports.rs:102:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:114:20 + --> $DIR/wildcard_imports.rs:113:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:114:30 + --> $DIR/wildcard_imports.rs:113:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:121:13 + --> $DIR/wildcard_imports.rs:120:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:150:9 + --> $DIR/wildcard_imports.rs:149:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:159:9 + --> $DIR/wildcard_imports.rs:158:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:160:9 + --> $DIR/wildcard_imports.rs:159:9 | LL | use crate:: fn_mod:: | _________^ @@ -93,37 +93,37 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:171:13 + --> $DIR/wildcard_imports.rs:170:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:206:17 + --> $DIR/wildcard_imports.rs:205:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:214:13 + --> $DIR/wildcard_imports.rs:213:13 | LL | use super_imports::*; | ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:223:17 + --> $DIR/wildcard_imports.rs:222:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:232:13 + --> $DIR/wildcard_imports.rs:231:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:240:13 + --> $DIR/wildcard_imports.rs:239:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/tests/ui/wildcard_imports_2021.edition2018.fixed b/tests/ui/wildcard_imports_2021.edition2018.fixed new file mode 100644 index 00000000000..6d534a10edc --- /dev/null +++ b/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -0,0 +1,240 @@ +// revisions: edition2018 edition2021 +//[edition2018] edition:2018 +//[edition2021] edition:2021 +// run-rustfix +// aux-build:wildcard_imports_helper.rs + +#![warn(clippy::wildcard_imports)] +#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] +#![warn(unused_imports)] + +extern crate wildcard_imports_helper; + +use crate::fn_mod::foo; +use crate::mod_mod::inner_mod; +use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}; +use crate::struct_mod::{A, inner_struct_mod}; + +#[allow(unused_imports)] +use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; +use wildcard_imports_helper::prelude::v1::*; +use wildcard_imports_helper::{ExternA, extern_foo}; + +use std::io::prelude::*; + +struct ReadFoo; + +impl Read for ReadFoo { + fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> { + Ok(0) + } +} + +mod fn_mod { + pub fn foo() {} +} + +mod mod_mod { + pub mod inner_mod { + pub fn foo() {} + } +} + +mod multi_fn_mod { + pub fn multi_foo() {} + pub fn multi_bar() {} + pub fn multi_baz() {} + pub mod multi_inner_mod { + pub fn foo() {} + } +} + +mod struct_mod { + pub struct A; + pub struct B; + pub mod inner_struct_mod { + pub struct C; + } + + #[macro_export] + macro_rules! double_struct_import_test { + () => { + let _ = A; + }; + } +} + +fn main() { + foo(); + multi_foo(); + multi_bar(); + multi_inner_mod::foo(); + inner_mod::foo(); + extern_foo(); + inner_extern_bar(); + + let _ = A; + let _ = inner_struct_mod::C; + let _ = ExternA; + let _ = PreludeModAnywhere; + + double_struct_import_test!(); + double_struct_import_test!(); +} + +mod in_fn_test { + pub use self::inner_exported::*; + #[allow(unused_imports)] + pub(crate) use self::inner_exported2::*; + + fn test_intern() { + use crate::fn_mod::foo; + + foo(); + } + + fn test_extern() { + use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo}; + use wildcard_imports_helper::{ExternA, extern_foo}; + + inner_for_self_import::inner_extern_foo(); + inner_extern_foo(); + + extern_foo(); + + let _ = ExternA; + } + + fn test_inner_nested() { + use self::{inner::inner_foo, inner2::inner_bar}; + + inner_foo(); + inner_bar(); + } + + fn test_extern_reexported() { + use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}; + + extern_exported(); + let _ = ExternExportedStruct; + let _ = ExternExportedEnum::A; + } + + mod inner_exported { + pub fn exported() {} + pub struct ExportedStruct; + pub enum ExportedEnum { + A, + } + } + + mod inner_exported2 { + pub(crate) fn exported2() {} + } + + mod inner { + pub fn inner_foo() {} + } + + mod inner2 { + pub fn inner_bar() {} + } +} + +fn test_reexported() { + use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}; + + exported(); + let _ = ExportedStruct; + let _ = ExportedEnum::A; +} + +#[rustfmt::skip] +fn test_weird_formatting() { + use crate:: in_fn_test::exported; + use crate:: fn_mod::foo; + + exported(); + foo(); +} + +mod super_imports { + fn foofoo() {} + + mod should_be_replaced { + use super::foofoo; + + fn with_super() { + let _ = foofoo(); + } + } + + mod test_should_pass { + use super::*; + + fn with_super() { + let _ = foofoo(); + } + } + + mod test_should_pass_inside_function { + fn with_super_inside_function() { + use super::*; + let _ = foofoo(); + } + } + + mod test_should_pass_further_inside { + fn insidefoo() {} + mod inner { + use super::*; + fn with_super() { + let _ = insidefoo(); + } + } + } + + mod should_be_replaced_further_inside { + fn insidefoo() {} + mod inner { + use super::insidefoo; + fn with_super() { + let _ = insidefoo(); + } + } + } + + mod use_explicit_should_be_replaced { + use crate::super_imports::foofoo; + + fn with_explicit() { + let _ = foofoo(); + } + } + + mod use_double_super_should_be_replaced { + mod inner { + use super::super::foofoo; + + fn with_double_super() { + let _ = foofoo(); + } + } + } + + mod use_super_explicit_should_be_replaced { + use super::super::super_imports::foofoo; + + fn with_super_explicit() { + let _ = foofoo(); + } + } + + mod attestation_should_be_replaced { + use super::foofoo; + + fn with_explicit() { + let _ = foofoo(); + } + } +} diff --git a/tests/ui/wildcard_imports_2021.edition2018.stderr b/tests/ui/wildcard_imports_2021.edition2018.stderr new file mode 100644 index 00000000000..acca9f651b4 --- /dev/null +++ b/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -0,0 +1,132 @@ +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:13:5 + | +LL | use crate::fn_mod::*; + | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` + | + = note: `-D clippy::wildcard-imports` implied by `-D warnings` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:14:5 + | +LL | use crate::mod_mod::*; + | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:15:5 + | +LL | use crate::multi_fn_mod::*; + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:16:5 + | +LL | use crate::struct_mod::*; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:19:5 + | +LL | use wildcard_imports_helper::inner::inner_for_self_import::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:21:5 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:91:13 + | +LL | use crate::fn_mod::*; + | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:97:75 + | +LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; + | ^ help: try: `inner_extern_foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:98:13 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:109:20 + | +LL | use self::{inner::*, inner2::*}; + | ^^^^^^^^ help: try: `inner::inner_foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:109:30 + | +LL | use self::{inner::*, inner2::*}; + | ^^^^^^^^^ help: try: `inner2::inner_bar` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:116:13 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:145:9 + | +LL | use crate::in_fn_test::*; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:154:9 + | +LL | use crate:: in_fn_test:: * ; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:155:9 + | +LL | use crate:: fn_mod:: + | _________^ +LL | | *; + | |_________^ help: try: `crate:: fn_mod::foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:166:13 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:201:17 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::insidefoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:209:13 + | +LL | use crate::super_imports::*; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:218:17 + | +LL | use super::super::*; + | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:227:13 + | +LL | use super::super::super_imports::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:235:13 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::foofoo` + +error: aborting due to 21 previous errors + diff --git a/tests/ui/wildcard_imports_2021.edition2021.fixed b/tests/ui/wildcard_imports_2021.edition2021.fixed new file mode 100644 index 00000000000..6d534a10edc --- /dev/null +++ b/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -0,0 +1,240 @@ +// revisions: edition2018 edition2021 +//[edition2018] edition:2018 +//[edition2021] edition:2021 +// run-rustfix +// aux-build:wildcard_imports_helper.rs + +#![warn(clippy::wildcard_imports)] +#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] +#![warn(unused_imports)] + +extern crate wildcard_imports_helper; + +use crate::fn_mod::foo; +use crate::mod_mod::inner_mod; +use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}; +use crate::struct_mod::{A, inner_struct_mod}; + +#[allow(unused_imports)] +use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; +use wildcard_imports_helper::prelude::v1::*; +use wildcard_imports_helper::{ExternA, extern_foo}; + +use std::io::prelude::*; + +struct ReadFoo; + +impl Read for ReadFoo { + fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> { + Ok(0) + } +} + +mod fn_mod { + pub fn foo() {} +} + +mod mod_mod { + pub mod inner_mod { + pub fn foo() {} + } +} + +mod multi_fn_mod { + pub fn multi_foo() {} + pub fn multi_bar() {} + pub fn multi_baz() {} + pub mod multi_inner_mod { + pub fn foo() {} + } +} + +mod struct_mod { + pub struct A; + pub struct B; + pub mod inner_struct_mod { + pub struct C; + } + + #[macro_export] + macro_rules! double_struct_import_test { + () => { + let _ = A; + }; + } +} + +fn main() { + foo(); + multi_foo(); + multi_bar(); + multi_inner_mod::foo(); + inner_mod::foo(); + extern_foo(); + inner_extern_bar(); + + let _ = A; + let _ = inner_struct_mod::C; + let _ = ExternA; + let _ = PreludeModAnywhere; + + double_struct_import_test!(); + double_struct_import_test!(); +} + +mod in_fn_test { + pub use self::inner_exported::*; + #[allow(unused_imports)] + pub(crate) use self::inner_exported2::*; + + fn test_intern() { + use crate::fn_mod::foo; + + foo(); + } + + fn test_extern() { + use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo}; + use wildcard_imports_helper::{ExternA, extern_foo}; + + inner_for_self_import::inner_extern_foo(); + inner_extern_foo(); + + extern_foo(); + + let _ = ExternA; + } + + fn test_inner_nested() { + use self::{inner::inner_foo, inner2::inner_bar}; + + inner_foo(); + inner_bar(); + } + + fn test_extern_reexported() { + use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}; + + extern_exported(); + let _ = ExternExportedStruct; + let _ = ExternExportedEnum::A; + } + + mod inner_exported { + pub fn exported() {} + pub struct ExportedStruct; + pub enum ExportedEnum { + A, + } + } + + mod inner_exported2 { + pub(crate) fn exported2() {} + } + + mod inner { + pub fn inner_foo() {} + } + + mod inner2 { + pub fn inner_bar() {} + } +} + +fn test_reexported() { + use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}; + + exported(); + let _ = ExportedStruct; + let _ = ExportedEnum::A; +} + +#[rustfmt::skip] +fn test_weird_formatting() { + use crate:: in_fn_test::exported; + use crate:: fn_mod::foo; + + exported(); + foo(); +} + +mod super_imports { + fn foofoo() {} + + mod should_be_replaced { + use super::foofoo; + + fn with_super() { + let _ = foofoo(); + } + } + + mod test_should_pass { + use super::*; + + fn with_super() { + let _ = foofoo(); + } + } + + mod test_should_pass_inside_function { + fn with_super_inside_function() { + use super::*; + let _ = foofoo(); + } + } + + mod test_should_pass_further_inside { + fn insidefoo() {} + mod inner { + use super::*; + fn with_super() { + let _ = insidefoo(); + } + } + } + + mod should_be_replaced_further_inside { + fn insidefoo() {} + mod inner { + use super::insidefoo; + fn with_super() { + let _ = insidefoo(); + } + } + } + + mod use_explicit_should_be_replaced { + use crate::super_imports::foofoo; + + fn with_explicit() { + let _ = foofoo(); + } + } + + mod use_double_super_should_be_replaced { + mod inner { + use super::super::foofoo; + + fn with_double_super() { + let _ = foofoo(); + } + } + } + + mod use_super_explicit_should_be_replaced { + use super::super::super_imports::foofoo; + + fn with_super_explicit() { + let _ = foofoo(); + } + } + + mod attestation_should_be_replaced { + use super::foofoo; + + fn with_explicit() { + let _ = foofoo(); + } + } +} diff --git a/tests/ui/wildcard_imports_2021.edition2021.stderr b/tests/ui/wildcard_imports_2021.edition2021.stderr new file mode 100644 index 00000000000..acca9f651b4 --- /dev/null +++ b/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -0,0 +1,132 @@ +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:13:5 + | +LL | use crate::fn_mod::*; + | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` + | + = note: `-D clippy::wildcard-imports` implied by `-D warnings` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:14:5 + | +LL | use crate::mod_mod::*; + | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:15:5 + | +LL | use crate::multi_fn_mod::*; + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:16:5 + | +LL | use crate::struct_mod::*; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:19:5 + | +LL | use wildcard_imports_helper::inner::inner_for_self_import::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:21:5 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:91:13 + | +LL | use crate::fn_mod::*; + | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:97:75 + | +LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; + | ^ help: try: `inner_extern_foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:98:13 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:109:20 + | +LL | use self::{inner::*, inner2::*}; + | ^^^^^^^^ help: try: `inner::inner_foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:109:30 + | +LL | use self::{inner::*, inner2::*}; + | ^^^^^^^^^ help: try: `inner2::inner_bar` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:116:13 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:145:9 + | +LL | use crate::in_fn_test::*; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:154:9 + | +LL | use crate:: in_fn_test:: * ; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:155:9 + | +LL | use crate:: fn_mod:: + | _________^ +LL | | *; + | |_________^ help: try: `crate:: fn_mod::foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:166:13 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:201:17 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::insidefoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:209:13 + | +LL | use crate::super_imports::*; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:218:17 + | +LL | use super::super::*; + | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:227:13 + | +LL | use super::super::super_imports::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:235:13 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::foofoo` + +error: aborting due to 21 previous errors + diff --git a/tests/ui/wildcard_imports_2021.rs b/tests/ui/wildcard_imports_2021.rs new file mode 100644 index 00000000000..b5ed58e6813 --- /dev/null +++ b/tests/ui/wildcard_imports_2021.rs @@ -0,0 +1,241 @@ +// revisions: edition2018 edition2021 +//[edition2018] edition:2018 +//[edition2021] edition:2021 +// run-rustfix +// aux-build:wildcard_imports_helper.rs + +#![warn(clippy::wildcard_imports)] +#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] +#![warn(unused_imports)] + +extern crate wildcard_imports_helper; + +use crate::fn_mod::*; +use crate::mod_mod::*; +use crate::multi_fn_mod::*; +use crate::struct_mod::*; + +#[allow(unused_imports)] +use wildcard_imports_helper::inner::inner_for_self_import::*; +use wildcard_imports_helper::prelude::v1::*; +use wildcard_imports_helper::*; + +use std::io::prelude::*; + +struct ReadFoo; + +impl Read for ReadFoo { + fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> { + Ok(0) + } +} + +mod fn_mod { + pub fn foo() {} +} + +mod mod_mod { + pub mod inner_mod { + pub fn foo() {} + } +} + +mod multi_fn_mod { + pub fn multi_foo() {} + pub fn multi_bar() {} + pub fn multi_baz() {} + pub mod multi_inner_mod { + pub fn foo() {} + } +} + +mod struct_mod { + pub struct A; + pub struct B; + pub mod inner_struct_mod { + pub struct C; + } + + #[macro_export] + macro_rules! double_struct_import_test { + () => { + let _ = A; + }; + } +} + +fn main() { + foo(); + multi_foo(); + multi_bar(); + multi_inner_mod::foo(); + inner_mod::foo(); + extern_foo(); + inner_extern_bar(); + + let _ = A; + let _ = inner_struct_mod::C; + let _ = ExternA; + let _ = PreludeModAnywhere; + + double_struct_import_test!(); + double_struct_import_test!(); +} + +mod in_fn_test { + pub use self::inner_exported::*; + #[allow(unused_imports)] + pub(crate) use self::inner_exported2::*; + + fn test_intern() { + use crate::fn_mod::*; + + foo(); + } + + fn test_extern() { + use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; + use wildcard_imports_helper::*; + + inner_for_self_import::inner_extern_foo(); + inner_extern_foo(); + + extern_foo(); + + let _ = ExternA; + } + + fn test_inner_nested() { + use self::{inner::*, inner2::*}; + + inner_foo(); + inner_bar(); + } + + fn test_extern_reexported() { + use wildcard_imports_helper::*; + + extern_exported(); + let _ = ExternExportedStruct; + let _ = ExternExportedEnum::A; + } + + mod inner_exported { + pub fn exported() {} + pub struct ExportedStruct; + pub enum ExportedEnum { + A, + } + } + + mod inner_exported2 { + pub(crate) fn exported2() {} + } + + mod inner { + pub fn inner_foo() {} + } + + mod inner2 { + pub fn inner_bar() {} + } +} + +fn test_reexported() { + use crate::in_fn_test::*; + + exported(); + let _ = ExportedStruct; + let _ = ExportedEnum::A; +} + +#[rustfmt::skip] +fn test_weird_formatting() { + use crate:: in_fn_test:: * ; + use crate:: fn_mod:: + *; + + exported(); + foo(); +} + +mod super_imports { + fn foofoo() {} + + mod should_be_replaced { + use super::*; + + fn with_super() { + let _ = foofoo(); + } + } + + mod test_should_pass { + use super::*; + + fn with_super() { + let _ = foofoo(); + } + } + + mod test_should_pass_inside_function { + fn with_super_inside_function() { + use super::*; + let _ = foofoo(); + } + } + + mod test_should_pass_further_inside { + fn insidefoo() {} + mod inner { + use super::*; + fn with_super() { + let _ = insidefoo(); + } + } + } + + mod should_be_replaced_further_inside { + fn insidefoo() {} + mod inner { + use super::*; + fn with_super() { + let _ = insidefoo(); + } + } + } + + mod use_explicit_should_be_replaced { + use crate::super_imports::*; + + fn with_explicit() { + let _ = foofoo(); + } + } + + mod use_double_super_should_be_replaced { + mod inner { + use super::super::*; + + fn with_double_super() { + let _ = foofoo(); + } + } + } + + mod use_super_explicit_should_be_replaced { + use super::super::super_imports::*; + + fn with_super_explicit() { + let _ = foofoo(); + } + } + + mod attestation_should_be_replaced { + use super::*; + + fn with_explicit() { + let _ = foofoo(); + } + } +} diff --git a/tests/ui/wildcard_imports_2021.stderr b/tests/ui/wildcard_imports_2021.stderr new file mode 100644 index 00000000000..92f6d31530f --- /dev/null +++ b/tests/ui/wildcard_imports_2021.stderr @@ -0,0 +1,132 @@ +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:9:5 + | +LL | use crate::fn_mod::*; + | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` + | + = note: `-D clippy::wildcard-imports` implied by `-D warnings` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:10:5 + | +LL | use crate::mod_mod::*; + | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:11:5 + | +LL | use crate::multi_fn_mod::*; + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:12:5 + | +LL | use crate::struct_mod::*; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:15:5 + | +LL | use wildcard_imports_helper::inner::inner_for_self_import::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:17:5 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:87:13 + | +LL | use crate::fn_mod::*; + | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:93:75 + | +LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; + | ^ help: try: `inner_extern_foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:94:13 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:105:20 + | +LL | use self::{inner::*, inner2::*}; + | ^^^^^^^^ help: try: `inner::inner_foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:105:30 + | +LL | use self::{inner::*, inner2::*}; + | ^^^^^^^^^ help: try: `inner2::inner_bar` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:112:13 + | +LL | use wildcard_imports_helper::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:141:9 + | +LL | use crate::in_fn_test::*; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:150:9 + | +LL | use crate:: in_fn_test:: * ; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:151:9 + | +LL | use crate:: fn_mod:: + | _________^ +LL | | *; + | |_________^ help: try: `crate:: fn_mod::foo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:162:13 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:197:17 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::insidefoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:205:13 + | +LL | use crate::super_imports::*; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:214:17 + | +LL | use super::super::*; + | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:223:13 + | +LL | use super::super::super_imports::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:231:13 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::foofoo` + +error: aborting due to 21 previous errors + diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index 7a85386a3df..c721e9969c9 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -2,7 +2,6 @@ #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::single_match_else)] -use rustc_tools_util::VersionInfo; use std::fs; #[test] |
