mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-27 07:00:55 +00:00
Auto merge of #106266 - matthiaskrgr:rollup-cxrdbzy, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #104531 (Provide a better error and a suggestion for `Fn` traits with lifetime params) - #105899 (`./x doc library --open` opens `std`) - #106190 (Account for multiple multiline spans with empty padding) - #106202 (Trim more paths in obligation types) - #106234 (rustdoc: simplify settings, help, and copy button CSS by not reusing) - #106236 (docs/test: add docs and a UI test for `E0514` and `E0519`) - #106259 (Update Clippy) - #106260 (Fix index out of bounds issues in rustdoc) - #106263 (Formatter should not try to format non-Rust files) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
cd579d69ec
99 changed files with 2561 additions and 367 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
106
clippy_lints/src/fn_null_check.rs
Normal file
106
clippy_lints/src/fn_null_check.rs
Normal 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);
|
||||
},
|
||||
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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!`");
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
}
|
||||
|
||||
|
|
|
@ -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`"
|
||||
));
|
||||
},
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, "..")),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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" }
|
||||
),
|
||||
|
|
|
@ -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()
|
||||
),
|
||||
|
|
52
clippy_lints/src/permissions_set_readonly_false.rs
Normal file
52
clippy_lints/src/permissions_set_readonly_false.rs
Normal 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");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
73
clippy_lints/src/size_of_ref.rs
Normal file
73
clippy_lints/src/size_of_ref.rs
Normal 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",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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`?")
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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)
|
||||
|
|
64
clippy_lints/src/transmute/transmute_null_to_fn.rs
Normal file
64
clippy_lints/src/transmute/transmute_null_to_fn.rs
Normal 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
|
||||
},
|
||||
}
|
||||
}
|
|
@ -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"));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
@ -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}>`"
|
||||
));
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(..)
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -3,8 +3,7 @@ error: an async construct yields a type which is itself awaitable
|
|||
|
|
||||
LL | let _h = async {
|
||||
| _____________________-
|
||||
LL | | async {
|
||||
| | _________^
|
||||
LL | |/ async {
|
||||
LL | || 3
|
||||
LL | || }
|
||||
| ||_________^ awaitable value not awaited
|
||||
|
@ -37,8 +36,7 @@ error: an async construct yields a type which is itself awaitable
|
|||
|
|
||||
LL | let _j = async || {
|
||||
| ________________________-
|
||||
LL | | async {
|
||||
| | _________^
|
||||
LL | |/ async {
|
||||
LL | || 3
|
||||
LL | || }
|
||||
| ||_________^ awaitable value not awaited
|
||||
|
|
3
tests/ui/crashes/ice-10044.rs
Normal file
3
tests/ui/crashes/ice-10044.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
[0; usize::MAX];
|
||||
}
|
10
tests/ui/crashes/ice-10044.stderr
Normal file
10
tests/ui/crashes/ice-10044.stderr
Normal 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
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
21
tests/ui/fn_null_check.rs
Normal 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 {}
|
||||
}
|
43
tests/ui/fn_null_check.stderr
Normal file
43
tests/ui/fn_null_check.stderr
Normal 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
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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;
|
||||
| ^^^^^^^
|
||||
|
|
29
tests/ui/permissions_set_readonly_false.rs
Normal file
29
tests/ui/permissions_set_readonly_false.rs
Normal 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);
|
||||
}
|
13
tests/ui/permissions_set_readonly_false.stderr
Normal file
13
tests/ui/permissions_set_readonly_false.stderr
Normal 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
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -19,10 +19,7 @@ LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value)
|
|||
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/result_map_unit_fn_unfixable.rs:29:5
|
||||
|
|
||||
LL | x.field.map(|value| {
|
||||
| ______^
|
||||
| | _____|
|
||||
| ||
|
||||
LL | // x.field.map(|value| {
|
||||
LL | || do_nothing(value);
|
||||
LL | || do_nothing(value)
|
||||
LL | || });
|
||||
|
|
27
tests/ui/size_of_ref.rs
Normal file
27
tests/ui/size_of_ref.rs
Normal 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())
|
||||
}
|
||||
}
|
27
tests/ui/size_of_ref.stderr
Normal file
27
tests/ui/size_of_ref.stderr
Normal 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
|
||||
|
28
tests/ui/transmute_null_to_fn.rs
Normal file
28
tests/ui/transmute_null_to_fn.rs
Normal 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();
|
||||
}
|
27
tests/ui/transmute_null_to_fn.stderr
Normal file
27
tests/ui/transmute_null_to_fn.stderr
Normal 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
|
||||
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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`
|
||||
|
|
240
tests/ui/wildcard_imports_2021.edition2018.fixed
Normal file
240
tests/ui/wildcard_imports_2021.edition2018.fixed
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
132
tests/ui/wildcard_imports_2021.edition2018.stderr
Normal file
132
tests/ui/wildcard_imports_2021.edition2018.stderr
Normal 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
|
||||
|
240
tests/ui/wildcard_imports_2021.edition2021.fixed
Normal file
240
tests/ui/wildcard_imports_2021.edition2021.fixed
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
132
tests/ui/wildcard_imports_2021.edition2021.stderr
Normal file
132
tests/ui/wildcard_imports_2021.edition2021.stderr
Normal 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
|
||||
|
241
tests/ui/wildcard_imports_2021.rs
Normal file
241
tests/ui/wildcard_imports_2021.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
132
tests/ui/wildcard_imports_2021.stderr
Normal file
132
tests/ui/wildcard_imports_2021.stderr
Normal 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
|
||||
|
Loading…
Reference in a new issue