Rollup merge of #106259 - flip1995:clippyup, r=matthiaskrgr

Update Clippy

r? `@Manishearth`

I think this was the very first sync with no conflicts whatsoever. I love this time of the year :D
This commit is contained in:
Matthias Krüger 2022-12-29 18:24:32 +01:00 committed by GitHub
commit d8365f9864
97 changed files with 2558 additions and 359 deletions

View file

@ -4203,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
@ -4460,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
@ -4545,6 +4547,7 @@ Released 2018-09-13
[`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
[`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
[`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count
[`size_of_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_ref
[`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
[`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
[`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
@ -4590,6 +4593,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

View file

@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv
diag.span_suggestion(
expr.span,
&format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
sugg,
rustc_errors::Applicability::HasPlaceholders,
);

View file

@ -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,
@ -535,6 +537,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
crate::size_of_ref::SIZE_OF_REF_INFO,
crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO,
crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO,
crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO,
@ -568,6 +571,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,

View file

@ -1282,10 +1282,10 @@ fn referent_used_exactly_once<'tcx>(
possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
}
let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
// If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
// that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
// itself. See the comment in that method for an explanation as to why.
possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
// If `place.local` were not included here, the `copyable_iterator::warn` test would fail. The
// reason is that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible
// borrower of itself. See the comment in that method for an explanation as to why.
possible_borrower.at_most_borrowers(cx, &[local, place.local], place.local, location)
&& used_exactly_once(mir, place.local).unwrap_or(false)
} else {
false

View file

@ -324,7 +324,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
let maybe_neg_sugg = |expr, hir_id| {
let sugg = Sugg::hir(cx, expr, "..");
if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id {
format!("-{sugg}")
format!("-{}", sugg.maybe_par())
} else {
sugg.to_string()
}

View file

@ -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);
},
_ => {},
}
},
_ => {},
}
}
}

View file

@ -382,7 +382,7 @@ fn check_format_in_format_args(
call_site,
&format!("`format!` in `{name}!` args"),
|diag| {
diag.help(&format!(
diag.help(format!(
"combine the `format!(..)` arguments with the outer `{name}!(..)` call"
));
diag.help("or consider changing `format!` to `format_args!`");

View file

@ -63,23 +63,40 @@ declare_clippy_lint! {
/// arguments but are not marked `unsafe`.
///
/// ### Why is this bad?
/// The function should probably be marked `unsafe`, since
/// for an arbitrary raw pointer, there is no way of telling for sure if it is
/// valid.
/// The function should almost definitely be marked `unsafe`, since for an
/// arbitrary raw pointer, there is no way of telling for sure if it is valid.
///
/// In general, this lint should **never be disabled** unless it is definitely a
/// false positive (please submit an issue if so) since it breaks Rust's
/// soundness guarantees, directly exposing API users to potentially dangerous
/// program behavior. This is also true for internal APIs, as it is easy to leak
/// unsoundness.
///
/// ### Context
/// In Rust, an `unsafe {...}` block is used to indicate that the code in that
/// section has been verified in some way that the compiler can not. For a
/// function that accepts a raw pointer then accesses the pointer's data, this is
/// generally impossible as the incoming pointer could point anywhere, valid or
/// not. So, the signature should be marked `unsafe fn`: this indicates that the
/// function's caller must provide some verification that the arguments it sends
/// are valid (and then call the function within an `unsafe` block).
///
/// ### Known problems
/// * It does not check functions recursively so if the pointer is passed to a
/// private non-`unsafe` function which does the dereferencing, the lint won't
/// trigger.
/// trigger (false negative).
/// * It only checks for arguments whose type are raw pointers, not raw pointers
/// got from an argument in some other way (`fn foo(bar: &[*const u8])` or
/// `some_argument.get_raw_ptr()`).
/// `some_argument.get_raw_ptr()`) (false negative).
///
/// ### Example
/// ```rust,ignore
/// pub fn foo(x: *const u8) {
/// println!("{}", unsafe { *x });
/// }
///
/// // this call "looks" safe but will segfault or worse!
/// // foo(invalid_ptr);
/// ```
///
/// Use instead:
@ -87,6 +104,12 @@ declare_clippy_lint! {
/// pub unsafe fn foo(x: *const u8) {
/// println!("{}", unsafe { *x });
/// }
///
/// // this would cause a compiler error for calling without `unsafe`
/// // foo(invalid_ptr);
///
/// // sound call if the caller knows the pointer is valid
/// unsafe { foo(valid_ptr); }
/// ```
#[clippy::version = "pre 1.29.0"]
pub NOT_UNSAFE_PTR_ARG_DEREF,

View file

@ -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);

View file

@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
);
diag.span_label(
def.variants[variants_size[1].ind].span,
&if variants_size[1].fields_size.is_empty() {
if variants_size[1].fields_size.is_empty() {
"the second-largest variant carries no data at all".to_owned()
} else {
format!(

View file

@ -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,

View file

@ -361,7 +361,7 @@ fn check_for_is_empty<'tcx>(
db.span_note(span, "`is_empty` defined here");
}
if let Some(self_kind) = self_kind {
db.note(&output.expected_sig(self_kind));
db.note(output.expected_sig(self_kind));
}
});
}

View file

@ -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;
@ -263,6 +265,7 @@ mod shadow;
mod single_char_lifetime_names;
mod single_component_path_imports;
mod size_of_in_element_count;
mod size_of_ref;
mod slow_vector_initialization;
mod std_instead_of_core;
mod strings;
@ -334,7 +337,7 @@ pub fn read_conf(sess: &Session, path: &io::Result<Option<PathBuf>>) -> Conf {
Ok(Some(path)) => path,
Ok(None) => return Conf::default(),
Err(error) => {
sess.struct_err(&format!("error finding Clippy's configuration file: {error}"))
sess.struct_err(format!("error finding Clippy's configuration file: {error}"))
.emit();
return Conf::default();
},
@ -902,6 +905,9 @@ 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));
store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
// add lints here, do not remove this comment, it's used in `new_lint`
}

View file

@ -77,7 +77,7 @@ pub(super) fn check<'tcx>(
applicability,
);
diag.note(&format!(
diag.note(format!(
"`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`"
));
},

View file

@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
let help = format!("make the function `async` and {ret_sugg}");
diag.span_suggestion(
header_span,
&help,
help,
format!("async {}{ret_snip}", &header_snip[..ret_pos]),
Applicability::MachineApplicable
);

View file

@ -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]);

View file

@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
let test_span = expr.span.until(then.span);
span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| {
diag.span_note(test_span, &format!("the {kind_word} was tested here"));
diag.span_note(test_span, format!("the {kind_word} was tested here"));
multispan_sugg(
diag,
&format!("try using the `strip_{kind_word}` method"),

View file

@ -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 {

View file

@ -31,19 +31,11 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
};
// Do we need to add ';' to suggestion ?
match match_body.kind {
ExprKind::Block(block, _) => {
// macro + expr_ty(body) == ()
if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
snippet_body.push(';');
}
},
_ => {
// expr_ty(body) == ()
if cx.typeck_results().expr_ty(match_body).is_unit() {
snippet_body.push(';');
}
},
if let ExprKind::Block(block, _) = match_body.kind {
// macro + expr_ty(body) == ()
if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
snippet_body.push(';');
}
}
let mut applicability = Applicability::MaybeIncorrect;

View file

@ -30,7 +30,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
let mut has_non_wild = false;
for arm in arms {
match peel_hir_pat_refs(arm.pat).0.kind {
PatKind::Wild => wildcard_span = Some(arm.pat.span),
PatKind::Wild if arm.guard.is_none() => wildcard_span = Some(arm.pat.span),
PatKind::Binding(_, _, ident, None) => {
wildcard_span = Some(arm.pat.span);
wildcard_ident = Some(ident);

View file

@ -36,7 +36,7 @@ pub fn check(
expr.span,
&format!("calling `to_string` on `{arg_ty}`"),
|diag| {
diag.help(&format!(
diag.help(format!(
"`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`"
));
let mut applicability = Applicability::MachineApplicable;

View file

@ -29,7 +29,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
application = Applicability::Unspecified;
diag.span_help(
pat.span,
&format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
);
}
}

View file

@ -84,7 +84,7 @@ pub(super) fn check<'tcx>(
suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, ")));
}
diag.multipart_suggestion(&format!("use `{suggest}` instead"), suggestion, applicability);
diag.multipart_suggestion(format!("use `{suggest}` instead"), suggestion, applicability);
});
}
}

View file

@ -167,7 +167,7 @@ fn check_manual_split_once_indirect(
};
diag.span_suggestion_verbose(
local.span,
&format!("try `{r}split_once`"),
format!("try `{r}split_once`"),
format!("let ({lhs}, {rhs}) = {self_snip}.{r}split_once({pat_snip}){unwrap};"),
app,
);

View file

@ -62,7 +62,7 @@ pub(super) fn check<'tcx>(
span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
diag.span_suggestion(
span,
&format!("use `{simplify_using}(..)` instead"),
format!("use `{simplify_using}(..)` instead"),
format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")),
applicability,
);

View file

@ -284,7 +284,7 @@ fn check<'tcx>(
diag.span_suggestion(
assign.lhs_span,
&format!("declare `{binding_name}` here"),
format!("declare `{binding_name}` here"),
let_snippet,
Applicability::MachineApplicable,
);
@ -304,7 +304,7 @@ fn check<'tcx>(
diag.span_suggestion_verbose(
usage.stmt.span.shrink_to_lo(),
&format!("declare `{binding_name}` here"),
format!("declare `{binding_name}` here"),
format!("{let_snippet} = "),
applicability,
);
@ -335,7 +335,7 @@ fn check<'tcx>(
diag.span_suggestion_verbose(
usage.stmt.span.shrink_to_lo(),
&format!("declare `{binding_name}` here"),
format!("declare `{binding_name}` here"),
format!("{let_snippet} = "),
applicability,
);

View file

@ -125,7 +125,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
if is_string { "string" } else { "byte string" }
),
|diag| {
diag.help(&format!(
diag.help(format!(
"octal escapes are not supported, `\\0` is always a null {}",
if is_string { "character" } else { "byte" }
));
@ -139,7 +139,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
// suggestion 2: unambiguous null byte
diag.span_suggestion(
span,
&format!(
format!(
"if the null {} is intended, disambiguate using",
if is_string { "character" } else { "byte" }
),

View file

@ -50,7 +50,7 @@ fn lint_misrefactored_assign_op(
let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r));
diag.span_suggestion(
expr.span,
&format!(
format!(
"did you mean `{snip_a} = {snip_a} {} {snip_r}` or `{long}`? Consider replacing it with",
op.as_str()
),

View file

@ -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");
}
);
}
}
}

View file

@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
// `res = clone(arg)` can be turned into `res = move arg;`
// if `arg` is the only borrow of `cloned` at this point.
if cannot_move_out || !possible_borrower.only_borrowers(&[arg], cloned, loc) {
if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg], cloned, loc) {
continue;
}
@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
// StorageDead(pred_arg);
// res = to_path_buf(cloned);
// ```
if cannot_move_out || !possible_borrower.only_borrowers(&[arg, cloned], local, loc) {
if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg, cloned], local, loc) {
continue;
}

View file

@ -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 {

View file

@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
|diag| {
diag.span_note(
trait_method_span,
&format!("existing `{method_name}` defined here"),
format!("existing `{method_name}` defined here"),
);
},
);
@ -151,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
// iterate on trait_spans?
diag.span_note(
trait_spans[0],
&format!("existing `{method_name}` defined here"),
format!("existing `{method_name}` defined here"),
);
},
);

View file

@ -0,0 +1,73 @@
use clippy_utils::{diagnostics::span_lint_and_help, path_def_id, ty::peel_mid_ty_refs};
use rustc_hir::{Expr, ExprKind};
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 calls to `std::mem::size_of_val()` where the argument is
/// a reference to a reference.
///
/// ### Why is this bad?
///
/// Calling `size_of_val()` with a reference to a reference as the argument
/// yields the size of the reference-type, not the size of the value behind
/// the reference.
///
/// ### Example
/// ```rust
/// struct Foo {
/// buffer: [u8],
/// }
///
/// impl Foo {
/// fn size(&self) -> usize {
/// // Note that `&self` as an argument is a `&&Foo`: Because `self`
/// // is already a reference, `&self` is a double-reference.
/// // The return value of `size_of_val()` therefor is the
/// // size of the reference-type, not the size of `self`.
/// std::mem::size_of_val(&self)
/// }
/// }
/// ```
/// Use instead:
/// ```rust
/// struct Foo {
/// buffer: [u8],
/// }
///
/// impl Foo {
/// fn size(&self) -> usize {
/// // Correct
/// std::mem::size_of_val(self)
/// }
/// }
/// ```
#[clippy::version = "1.67.0"]
pub SIZE_OF_REF,
suspicious,
"Argument to `std::mem::size_of_val()` is a double-reference, which is almost certainly unintended"
}
declare_lint_pass!(SizeOfRef => [SIZE_OF_REF]);
impl LateLintPass<'_> for SizeOfRef {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
if let ExprKind::Call(path, [arg]) = expr.kind
&& let Some(def_id) = path_def_id(cx, path)
&& cx.tcx.is_diagnostic_item(sym::mem_size_of_val, def_id)
&& let arg_ty = cx.typeck_results().expr_ty(arg)
&& peel_mid_ty_refs(arg_ty).1 > 1
{
span_lint_and_help(
cx,
SIZE_OF_REF,
expr.span,
"argument to `std::mem::size_of_val()` is a reference to a reference",
None,
"dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type",
);
}
}
}

View file

@ -132,7 +132,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
applicability,
);
if !is_xor_based {
diag.note(&format!("or maybe you should use `{sugg}::mem::replace`?"));
diag.note(format!("or maybe you should use `{sugg}::mem::replace`?"));
}
},
);
@ -214,7 +214,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
Applicability::MaybeIncorrect,
);
diag.note(
&format!("or maybe you should use `{sugg}::mem::replace`?")
format!("or maybe you should use `{sugg}::mem::replace`?")
);
}
});

View file

@ -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)

View file

@ -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
},
}
}

View file

@ -77,7 +77,7 @@ pub(super) fn check<'tcx>(
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|diag| {
if from_ty_orig.peel_refs() != from_ty.peel_refs() {
diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
}
},
);
@ -91,7 +91,7 @@ pub(super) fn check<'tcx>(
&format!("transmute to `{to_ty_orig}` which has an undefined layout"),
|diag| {
if to_ty_orig.peel_refs() != to_ty.peel_refs() {
diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
}
},
);
@ -119,16 +119,16 @@ pub(super) fn check<'tcx>(
),
|diag| {
if let Some(same_adt_did) = same_adt_did {
diag.note(&format!(
diag.note(format!(
"two instances of the same generic type (`{}`) may have different layouts",
cx.tcx.item_name(same_adt_did)
));
} else {
if from_ty_orig.peel_refs() != from_ty {
diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
}
if to_ty_orig.peel_refs() != to_ty {
diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
}
}
},
@ -146,7 +146,7 @@ pub(super) fn check<'tcx>(
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|diag| {
if from_ty_orig.peel_refs() != from_ty {
diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
}
},
);
@ -163,7 +163,7 @@ pub(super) fn check<'tcx>(
&format!("transmute into `{to_ty_orig}` which has an undefined layout"),
|diag| {
if to_ty_orig.peel_refs() != to_ty {
diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
}
},
);

View file

@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
&format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
|diag| {
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
let sugg = arg.as_ty(&to_ty.to_string()).to_string();
let sugg = arg.as_ty(to_ty.to_string()).to_string();
diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
}
},

View file

@ -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;

View file

@ -61,7 +61,7 @@ pub(super) fn check<'tcx>(
"transmute from an integer to a pointer",
|diag| {
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
diag.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()), Applicability::Unspecified);
diag.span_suggestion(e.span, "try", arg.as_ty(to_ty.to_string()), Applicability::Unspecified);
}
},
);

View file

@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
&format!("usage of `{outer_sym}<{generic_snippet}>`"),
|diag| {
diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability);
diag.note(&format!(
diag.note(format!(
"`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap"
));
},
@ -78,7 +78,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
format!("{outer_sym}<{generic_snippet}>"),
applicability,
);
diag.note(&format!(
diag.note(format!(
"`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
));
},
@ -91,10 +91,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
hir_ty.span,
&format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
|diag| {
diag.note(&format!(
diag.note(format!(
"`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
));
diag.help(&format!(
diag.help(format!(
"consider using just `{outer_sym}<{generic_snippet}>` or `{inner_sym}<{generic_snippet}>`"
));
},

View file

@ -129,7 +129,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
if arg_snippets_without_empty_blocks.is_empty() {
db.multipart_suggestion(
&format!("use {singular}unit literal{plural} instead"),
format!("use {singular}unit literal{plural} instead"),
args_to_recover
.iter()
.map(|arg| (arg.span, "()".to_string()))
@ -142,7 +142,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
let it_or_them = if plural { "them" } else { "it" };
db.span_suggestion(
expr.span,
&format!(
format!(
"{or}move the expression{empty_or_s} in front of the call and replace {it_or_them} with the unit literal `()`"
),
sugg,

View file

@ -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,

View file

@ -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

View file

@ -558,8 +558,8 @@ impl fmt::Display for ClippyConfiguration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
writeln!(
f,
"* `{}`: `{}`: {} (defaults to `{}`)",
self.name, self.config_type, self.doc, self.default
"* `{}`: `{}`(defaults to `{}`): {}",
self.name, self.config_type, self.default, self.doc
)
}
}

View file

@ -377,7 +377,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c
// print!("\n"), write!(f, "\n")
diag.multipart_suggestion(
&format!("use `{name}ln!` instead"),
format!("use `{name}ln!` instead"),
vec![(name_span, format!("{name}ln")), (format_string_span, String::new())],
Applicability::MachineApplicable,
);
@ -388,7 +388,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c
let newline_span = format_string_span.with_lo(hi - BytePos(3)).with_hi(hi - BytePos(1));
diag.multipart_suggestion(
&format!("use `{name}ln!` instead"),
format!("use `{name}ln!` instead"),
vec![(name_span, format!("{name}ln")), (newline_span, String::new())],
Applicability::MachineApplicable,
);

View file

@ -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,
}

View file

@ -17,7 +17,7 @@ use std::env;
fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) {
if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
if let Some(lint) = lint.name_lower().strip_prefix("clippy::") {
diag.help(&format!(
diag.help(format!(
"for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}",
&option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
// extract just major + minor version and ignore patch versions

View file

@ -1,52 +0,0 @@
use rustc_index::bit_set::BitSet;
use rustc_middle::mir;
use rustc_mir_dataflow::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis};
/// Determines liveness of each local purely based on `StorageLive`/`Dead`.
#[derive(Copy, Clone)]
pub(super) struct MaybeStorageLive;
impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
type Domain = BitSet<mir::Local>;
const NAME: &'static str = "maybe_storage_live";
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
// bottom = dead
BitSet::new_empty(body.local_decls.len())
}
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
for arg in body.args_iter() {
state.insert(arg);
}
}
}
impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
type Idx = mir::Local;
fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) {
match stmt.kind {
mir::StatementKind::StorageLive(l) => trans.gen(l),
mir::StatementKind::StorageDead(l) => trans.kill(l),
_ => (),
}
}
fn terminator_effect(
&self,
_trans: &mut impl GenKill<Self::Idx>,
_terminator: &mir::Terminator<'tcx>,
_loc: mir::Location,
) {
}
fn call_return_effect(
&self,
_trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
// Nothing to do when a call returns successfully
}
}

View file

@ -5,8 +5,6 @@ use rustc_middle::mir::{
};
use rustc_middle::ty::TyCtxt;
mod maybe_storage_live;
mod possible_borrower;
pub use possible_borrower::PossibleBorrowerMap;

View file

@ -1,92 +1,137 @@
use super::{
maybe_storage_live::MaybeStorageLive, possible_origin::PossibleOriginVisitor,
transitive_relation::TransitiveRelation,
};
use super::possible_origin::PossibleOriginVisitor;
use crate::ty::is_copy;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_index::bit_set::{BitSet, HybridBitSet};
use rustc_lint::LateContext;
use rustc_middle::mir::{self, visit::Visitor as _, Mutability};
use rustc_middle::ty::{self, visit::TypeVisitor};
use rustc_mir_dataflow::{Analysis, ResultsCursor};
use rustc_middle::mir::{
self, visit::Visitor as _, BasicBlock, Local, Location, Mutability, Statement, StatementKind, Terminator,
};
use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt};
use rustc_mir_dataflow::{
fmt::DebugWithContext, impls::MaybeStorageLive, lattice::JoinSemiLattice, Analysis, AnalysisDomain,
CallReturnPlaces, ResultsCursor,
};
use std::borrow::Cow;
use std::ops::ControlFlow;
/// Collects the possible borrowers of each local.
/// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
/// possible borrowers of `a`.
#[allow(clippy::module_name_repetitions)]
struct PossibleBorrowerVisitor<'a, 'b, 'tcx> {
possible_borrower: TransitiveRelation,
struct PossibleBorrowerAnalysis<'b, 'tcx> {
tcx: TyCtxt<'tcx>,
body: &'b mir::Body<'tcx>,
cx: &'a LateContext<'tcx>,
possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
}
impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
#[derive(Clone, Debug, Eq, PartialEq)]
struct PossibleBorrowerState {
map: FxIndexMap<Local, BitSet<Local>>,
domain_size: usize,
}
impl PossibleBorrowerState {
fn new(domain_size: usize) -> Self {
Self {
map: FxIndexMap::default(),
domain_size,
}
}
#[allow(clippy::similar_names)]
fn add(&mut self, borrowed: Local, borrower: Local) {
self.map
.entry(borrowed)
.or_insert(BitSet::new_empty(self.domain_size))
.insert(borrower);
}
}
impl<C> DebugWithContext<C> for PossibleBorrowerState {
fn fmt_with(&self, _ctxt: &C, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<_ as std::fmt::Debug>::fmt(self, f)
}
fn fmt_diff_with(&self, _old: &Self, _ctxt: &C, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unimplemented!()
}
}
impl JoinSemiLattice for PossibleBorrowerState {
fn join(&mut self, other: &Self) -> bool {
let mut changed = false;
for (&borrowed, borrowers) in other.map.iter() {
if !borrowers.is_empty() {
changed |= self
.map
.entry(borrowed)
.or_insert(BitSet::new_empty(self.domain_size))
.union(borrowers);
}
}
changed
}
}
impl<'b, 'tcx> AnalysisDomain<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
type Domain = PossibleBorrowerState;
const NAME: &'static str = "possible_borrower";
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
PossibleBorrowerState::new(body.local_decls.len())
}
fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _entry_set: &mut Self::Domain) {}
}
impl<'b, 'tcx> PossibleBorrowerAnalysis<'b, 'tcx> {
fn new(
cx: &'a LateContext<'tcx>,
tcx: TyCtxt<'tcx>,
body: &'b mir::Body<'tcx>,
possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
) -> Self {
Self {
possible_borrower: TransitiveRelation::default(),
cx,
tcx,
body,
possible_origin,
}
}
fn into_map(
self,
cx: &'a LateContext<'tcx>,
maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
) -> PossibleBorrowerMap<'b, 'tcx> {
let mut map = FxHashMap::default();
for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
if is_copy(cx, self.body.local_decls[row].ty) {
continue;
}
let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
borrowers.remove(mir::Local::from_usize(0));
if !borrowers.is_empty() {
map.insert(row, borrowers);
}
}
let bs = BitSet::new_empty(self.body.local_decls.len());
PossibleBorrowerMap {
map,
maybe_live,
bitset: (bs.clone(), bs),
}
}
}
impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> {
fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
let lhs = place.local;
match rvalue {
mir::Rvalue::Ref(_, _, borrowed) => {
self.possible_borrower.add(borrowed.local, lhs);
},
other => {
if ContainsRegion
.visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
.is_continue()
{
return;
}
rvalue_locals(other, |rhs| {
if lhs != rhs {
self.possible_borrower.add(rhs, lhs);
impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
fn apply_call_return_effect(
&self,
_state: &mut Self::Domain,
_block: BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
}
fn apply_statement_effect(&self, state: &mut Self::Domain, statement: &Statement<'tcx>, _location: Location) {
if let StatementKind::Assign(box (place, rvalue)) = &statement.kind {
let lhs = place.local;
match rvalue {
mir::Rvalue::Ref(_, _, borrowed) => {
state.add(borrowed.local, lhs);
},
other => {
if ContainsRegion
.visit_ty(place.ty(&self.body.local_decls, self.tcx).ty)
.is_continue()
{
return;
}
});
},
rvalue_locals(other, |rhs| {
if lhs != rhs {
state.add(rhs, lhs);
}
});
},
}
}
}
fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) {
fn apply_terminator_effect(&self, state: &mut Self::Domain, terminator: &Terminator<'tcx>, _location: Location) {
if let mir::TerminatorKind::Call {
args,
destination: mir::Place { local: dest, .. },
@ -126,10 +171,10 @@ impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b,
for y in mutable_variables {
for x in &immutable_borrowers {
self.possible_borrower.add(*x, y);
state.add(*x, y);
}
for x in &mutable_borrowers {
self.possible_borrower.add(*x, y);
state.add(*x, y);
}
}
}
@ -165,73 +210,98 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
}
}
/// Result of `PossibleBorrowerVisitor`.
/// Result of `PossibleBorrowerAnalysis`.
#[allow(clippy::module_name_repetitions)]
pub struct PossibleBorrowerMap<'b, 'tcx> {
/// Mapping `Local -> its possible borrowers`
pub map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
// Caches to avoid allocation of `BitSet` on every query
pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
body: &'b mir::Body<'tcx>,
possible_borrower: ResultsCursor<'b, 'tcx, PossibleBorrowerAnalysis<'b, 'tcx>>,
maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'b>>,
pushed: BitSet<Local>,
stack: Vec<Local>,
}
impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
let possible_origin = {
let mut vis = PossibleOriginVisitor::new(mir);
vis.visit_body(mir);
vis.into_map(cx)
};
let maybe_storage_live_result = MaybeStorageLive
let possible_borrower = PossibleBorrowerAnalysis::new(cx.tcx, mir, possible_origin)
.into_engine(cx.tcx, mir)
.pass_name("redundant_clone")
.pass_name("possible_borrower")
.iterate_to_fixpoint()
.into_results_cursor(mir);
let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
vis.visit_body(mir);
vis.into_map(cx, maybe_storage_live_result)
let maybe_live = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
.into_engine(cx.tcx, mir)
.pass_name("possible_borrower")
.iterate_to_fixpoint()
.into_results_cursor(mir);
PossibleBorrowerMap {
body: mir,
possible_borrower,
maybe_live,
pushed: BitSet::new_empty(mir.local_decls.len()),
stack: Vec::with_capacity(mir.local_decls.len()),
}
}
/// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`.
pub fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool {
self.bounded_borrowers(borrowers, borrowers, borrowed, at)
}
/// Returns true if the set of borrowers of `borrowed` living at `at` includes at least `below`
/// but no more than `above`.
pub fn bounded_borrowers(
/// Returns true if the set of borrowers of `borrowed` living at `at` includes no more than
/// `borrowers`.
/// Notes:
/// 1. It would be nice if `PossibleBorrowerMap` could store `cx` so that `at_most_borrowers`
/// would not require it to be passed in. But a `PossibleBorrowerMap` is stored in `LintPass`
/// `Dereferencing`, which outlives any `LateContext`.
/// 2. In all current uses of `at_most_borrowers`, `borrowers` is a slice of at most two
/// elements. Thus, `borrowers.contains(...)` is effectively a constant-time operation. If
/// `at_most_borrowers`'s uses were to expand beyond this, its implementation might have to be
/// adjusted.
pub fn at_most_borrowers(
&mut self,
below: &[mir::Local],
above: &[mir::Local],
cx: &LateContext<'tcx>,
borrowers: &[mir::Local],
borrowed: mir::Local,
at: mir::Location,
) -> bool {
self.maybe_live.seek_after_primary_effect(at);
if is_copy(cx, self.body.local_decls[borrowed].ty) {
return true;
}
self.bitset.0.clear();
let maybe_live = &mut self.maybe_live;
if let Some(bitset) = self.map.get(&borrowed) {
for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) {
self.bitset.0.insert(b);
self.possible_borrower.seek_before_primary_effect(at);
self.maybe_live.seek_before_primary_effect(at);
let possible_borrower = &self.possible_borrower.get().map;
let maybe_live = &self.maybe_live;
self.pushed.clear();
self.stack.clear();
if let Some(borrowers) = possible_borrower.get(&borrowed) {
for b in borrowers.iter() {
if self.pushed.insert(b) {
self.stack.push(b);
}
}
} else {
return false;
// Nothing borrows `borrowed` at `at`.
return true;
}
self.bitset.1.clear();
for b in below {
self.bitset.1.insert(*b);
while let Some(borrower) = self.stack.pop() {
if maybe_live.contains(borrower) && !borrowers.contains(&borrower) {
return false;
}
if let Some(borrowers) = possible_borrower.get(&borrower) {
for b in borrowers.iter() {
if self.pushed.insert(b) {
self.stack.push(b);
}
}
}
}
if !self.bitset.0.superset(&self.bitset.1) {
return false;
}
for b in above {
self.bitset.0.remove(*b);
}
self.bitset.0.is_empty()
true
}
pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {

View file

@ -185,7 +185,6 @@ impl<'a> Sugg<'a> {
) -> Self {
use rustc_ast::ast::RangeLimits;
#[expect(clippy::match_wildcard_for_single_variants)]
match expr.kind {
_ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0),
ast::ExprKind::AddrOf(..)

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2022-12-17"
channel = "nightly-2022-12-29"
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]

View file

@ -0,0 +1,3 @@
fn main() {
[0; usize::MAX];
}

View file

@ -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

View file

@ -14,6 +14,15 @@ fn main() {
let _ = (y as f32).mul_add(y as f32, x);
let _ = x.mul_add(x, y).sqrt();
let _ = y.mul_add(y, x).sqrt();
let _ = (x - 1.0).mul_add(x - 1.0, -y);
let _ = (x - 1.0).mul_add(x - 1.0, -y) + 3.0;
let _ = (x - 1.0).mul_add(x - 1.0, -(y + 3.0));
let _ = (y + 1.0).mul_add(-(y + 1.0), x);
let _ = (3.0 * y).mul_add(-(3.0 * y), x);
let _ = (y + 1.0 + x).mul_add(-(y + 1.0 + x), x);
let _ = (y + 1.0 + 2.0).mul_add(-(y + 1.0 + 2.0), x);
// Cases where the lint shouldn't be applied
let _ = x.powi(2);
let _ = x.powi(1 + 1);

View file

@ -14,6 +14,15 @@ fn main() {
let _ = x + (y as f32).powi(2);
let _ = (x.powi(2) + y).sqrt();
let _ = (x + y.powi(2)).sqrt();
let _ = (x - 1.0).powi(2) - y;
let _ = (x - 1.0).powi(2) - y + 3.0;
let _ = (x - 1.0).powi(2) - (y + 3.0);
let _ = x - (y + 1.0).powi(2);
let _ = x - (3.0 * y).powi(2);
let _ = x - (y + 1.0 + x).powi(2);
let _ = x - (y + 1.0 + 2.0).powi(2);
// Cases where the lint shouldn't be applied
let _ = x.powi(2);
let _ = x.powi(1 + 1);

View file

@ -42,5 +42,47 @@ error: multiply and add expressions can be calculated more efficiently and accur
LL | let _ = (x + y.powi(2)).sqrt();
| ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
error: aborting due to 7 previous errors
error: multiply and add expressions can be calculated more efficiently and accurately
--> $DIR/floating_point_powi.rs:18:13
|
LL | let _ = (x - 1.0).powi(2) - y;
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -y)`
error: multiply and add expressions can be calculated more efficiently and accurately
--> $DIR/floating_point_powi.rs:19:13
|
LL | let _ = (x - 1.0).powi(2) - y + 3.0;
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -y)`
error: multiply and add expressions can be calculated more efficiently and accurately
--> $DIR/floating_point_powi.rs:20:13
|
LL | let _ = (x - 1.0).powi(2) - (y + 3.0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -(y + 3.0))`
error: multiply and add expressions can be calculated more efficiently and accurately
--> $DIR/floating_point_powi.rs:21:13
|
LL | let _ = x - (y + 1.0).powi(2);
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0).mul_add(-(y + 1.0), x)`
error: multiply and add expressions can be calculated more efficiently and accurately
--> $DIR/floating_point_powi.rs:22:13
|
LL | let _ = x - (3.0 * y).powi(2);
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(3.0 * y).mul_add(-(3.0 * y), x)`
error: multiply and add expressions can be calculated more efficiently and accurately
--> $DIR/floating_point_powi.rs:23:13
|
LL | let _ = x - (y + 1.0 + x).powi(2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0 + x).mul_add(-(y + 1.0 + x), x)`
error: multiply and add expressions can be calculated more efficiently and accurately
--> $DIR/floating_point_powi.rs:24:13
|
LL | let _ = x - (y + 1.0 + 2.0).powi(2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0 + 2.0).mul_add(-(y + 1.0 + 2.0), x)`
error: aborting due to 14 previous errors

21
tests/ui/fn_null_check.rs Normal file
View file

@ -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 {}
}

View file

@ -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

View file

@ -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)
}

View file

@ -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)
}

View file

@ -1,6 +1,6 @@
// run-rustfix
#![warn(clippy::manual_retain)]
#![allow(unused)]
#![allow(unused, clippy::redundant_clone)]
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::BinaryHeap;

View file

@ -1,6 +1,6 @@
// run-rustfix
#![warn(clippy::manual_retain)]
#![allow(unused)]
#![allow(unused, clippy::redundant_clone)]
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::BinaryHeap;

View file

@ -133,3 +133,16 @@ fn issue_9575() {
println!("Needs curlies");
};
}
#[allow(dead_code)]
fn issue_9725(r: Option<u32>) {
let x = r;
match x {
Some(_) => {
println!("Some");
},
None => {
println!("None");
},
};
}

View file

@ -148,3 +148,17 @@ fn issue_9575() {
_ => println!("Needs curlies"),
};
}
#[allow(dead_code)]
fn issue_9725(r: Option<u32>) {
match r {
x => match x {
Some(_) => {
println!("Some");
},
None => {
println!("None");
},
},
};
}

View file

@ -213,5 +213,30 @@ LL + println!("Needs curlies");
LL ~ };
|
error: aborting due to 14 previous errors
error: this match could be written as a `let` statement
--> $DIR/match_single_binding.rs:154:5
|
LL | / match r {
LL | | x => match x {
LL | | Some(_) => {
LL | | println!("Some");
... |
LL | | },
LL | | };
| |_____^
|
help: consider using a `let` statement
|
LL ~ let x = r;
LL + match x {
LL + Some(_) => {
LL + println!("Some");
LL + },
LL + None => {
LL + println!("None");
LL + },
LL ~ };
|
error: aborting due to 15 previous errors

View file

@ -132,3 +132,25 @@ fn main() {
}
}
}
mod issue9993 {
enum Foo {
A(bool),
B,
}
fn test() {
let _ = match Foo::A(true) {
_ if false => 0,
Foo::A(true) => 1,
Foo::A(false) => 2,
Foo::B => 3,
};
let _ = match Foo::B {
_ if false => 0,
Foo::A(_) => 1,
Foo::B => 2,
};
}
}

View file

@ -132,3 +132,25 @@ fn main() {
}
}
}
mod issue9993 {
enum Foo {
A(bool),
B,
}
fn test() {
let _ = match Foo::A(true) {
_ if false => 0,
Foo::A(true) => 1,
Foo::A(false) => 2,
Foo::B => 3,
};
let _ = match Foo::B {
_ if false => 0,
Foo::A(_) => 1,
_ => 2,
};
}
}

View file

@ -48,5 +48,11 @@ error: wildcard matches only a single variant and will also match any future add
LL | _ => (),
| ^ help: try this: `Color::Blue`
error: aborting due to 8 previous errors
error: wildcard matches only a single variant and will also match any future added variants
--> $DIR/match_wildcard_for_single_variants.rs:153:13
|
LL | _ => 2,
| ^ help: try this: `Foo::B`
error: aborting due to 9 previous errors

View file

@ -1,5 +1,5 @@
// run-rustfix
#![feature(lint_reasons)]
#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
#![allow(
unused,
clippy::uninlined_format_args,
@ -491,3 +491,14 @@ mod issue_9782_method_variant {
S.foo::<&[u8; 100]>(&a);
}
}
extern crate rustc_lint;
extern crate rustc_span;
#[allow(dead_code)]
mod span_lint {
use rustc_lint::{LateContext, Lint, LintContext};
fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(String::new()));
}
}

View file

@ -1,5 +1,5 @@
// run-rustfix
#![feature(lint_reasons)]
#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
#![allow(
unused,
clippy::uninlined_format_args,
@ -491,3 +491,14 @@ mod issue_9782_method_variant {
S.foo::<&[u8; 100]>(&a);
}
}
extern crate rustc_lint;
extern crate rustc_span;
#[allow(dead_code)]
mod span_lint {
use rustc_lint::{LateContext, Lint, LintContext};
fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
}
}

View file

@ -216,5 +216,11 @@ error: the borrowed expression implements the required traits
LL | foo(&a);
| ^^ help: change this to: `a`
error: aborting due to 36 previous errors
error: the borrowed expression implements the required traits
--> $DIR/needless_borrow.rs:502:85
|
LL | cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
| ^^^^^^^^^^^^^^ help: change this to: `String::new()`
error: aborting due to 37 previous errors

View file

@ -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() {}

View file

@ -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() {}

View file

@ -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;
| ^^^^^^^

View file

@ -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);
}

View file

@ -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

View file

@ -239,3 +239,9 @@ fn false_negative_5707() {
let _z = x.clone(); // pr 7346 can't lint on `x`
drop(y);
}
#[allow(unused, clippy::manual_retain)]
fn possible_borrower_improvements() {
let mut s = String::from("foobar");
s = s.chars().filter(|&c| c != 'o').collect();
}

View file

@ -239,3 +239,9 @@ fn false_negative_5707() {
let _z = x.clone(); // pr 7346 can't lint on `x`
drop(y);
}
#[allow(unused, clippy::manual_retain)]
fn possible_borrower_improvements() {
let mut s = String::from("foobar");
s = s.chars().filter(|&c| c != 'o').to_owned().collect();
}

View file

@ -179,5 +179,17 @@ note: this value is dropped without further use
LL | foo(&x.clone(), move || {
| ^
error: aborting due to 15 previous errors
error: redundant clone
--> $DIR/redundant_clone.rs:246:40
|
LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect();
| ^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
--> $DIR/redundant_clone.rs:246:9
|
LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 16 previous errors

27
tests/ui/size_of_ref.rs Normal file
View file

@ -0,0 +1,27 @@
#![allow(unused)]
#![warn(clippy::size_of_ref)]
use std::mem::size_of_val;
fn main() {
let x = 5;
let y = &x;
size_of_val(&x); // no lint
size_of_val(y); // no lint
size_of_val(&&x);
size_of_val(&y);
}
struct S {
field: u32,
data: Vec<u8>,
}
impl S {
/// Get size of object including `self`, in bytes.
pub fn size(&self) -> usize {
std::mem::size_of_val(&self) + (std::mem::size_of::<u8>() * self.data.capacity())
}
}

View file

@ -0,0 +1,27 @@
error: argument to `std::mem::size_of_val()` is a reference to a reference
--> $DIR/size_of_ref.rs:13:5
|
LL | size_of_val(&&x);
| ^^^^^^^^^^^^^^^^
|
= help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type
= note: `-D clippy::size-of-ref` implied by `-D warnings`
error: argument to `std::mem::size_of_val()` is a reference to a reference
--> $DIR/size_of_ref.rs:14:5
|
LL | size_of_val(&y);
| ^^^^^^^^^^^^^^^
|
= help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type
error: argument to `std::mem::size_of_val()` is a reference to a reference
--> $DIR/size_of_ref.rs:25:9
|
LL | std::mem::size_of_val(&self) + (std::mem::size_of::<u8>() * self.data.capacity())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type
error: aborting due to 3 previous errors

View file

@ -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();
}

View file

@ -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

View file

@ -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");

View file

@ -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");

View file

@ -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

View file

@ -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)]

View file

@ -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)]

View file

@ -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`

View file

@ -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();
}
}
}

View file

@ -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

View file

@ -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();
}
}
}

View file

@ -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

View file

@ -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();
}
}
}

View file

@ -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