Rollup merge of #136645 - flip1995:clippy-subtree-update, r=Manishearth
Clippy subtree update r? `@Manishearth`
This commit is contained in:
commit
b1be2d5494
106 changed files with 2681 additions and 566 deletions
|
@ -5765,6 +5765,7 @@ Released 2018-09-13
|
|||
[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
|
||||
[`manual_ok_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_err
|
||||
[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
|
||||
[`manual_option_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_option_as_slice
|
||||
[`manual_pattern_char_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison
|
||||
[`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
|
||||
[`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns
|
||||
|
@ -5773,6 +5774,7 @@ Released 2018-09-13
|
|||
[`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain
|
||||
[`manual_rotate`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rotate
|
||||
[`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
|
||||
[`manual_slice_fill`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_fill
|
||||
[`manual_slice_size_calculation`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation
|
||||
[`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once
|
||||
[`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat
|
||||
|
@ -5954,6 +5956,7 @@ Released 2018-09-13
|
|||
[`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
|
||||
[`precedence_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence_bits
|
||||
[`print_in_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_in_format_impl
|
||||
[`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal
|
||||
[`print_stderr`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr
|
||||
|
@ -6026,6 +6029,7 @@ Released 2018-09-13
|
|||
[`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else
|
||||
[`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
|
||||
[`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used
|
||||
[`return_and_then`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_and_then
|
||||
[`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
|
||||
[`reverse_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#reverse_range_loop
|
||||
[`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
|
||||
|
|
|
@ -5,7 +5,7 @@ To do this, Clippy provides attributes that can be applied to items in the 3rd p
|
|||
|
||||
## `#[clippy::format_args]`
|
||||
|
||||
_Available since Clippy v1.84_
|
||||
_Available since Clippy v1.85_
|
||||
|
||||
This attribute can be added to a macro that supports `format!`, `println!`, or similar syntax.
|
||||
It tells Clippy that the macro is a formatting macro, and that the arguments to the macro
|
||||
|
|
|
@ -752,6 +752,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
|
|||
* [`manual_rem_euclid`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid)
|
||||
* [`manual_repeat_n`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n)
|
||||
* [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain)
|
||||
* [`manual_slice_fill`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_fill)
|
||||
* [`manual_split_once`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once)
|
||||
* [`manual_str_repeat`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat)
|
||||
* [`manual_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip)
|
||||
|
|
|
@ -101,5 +101,18 @@ The `clippy::cargo` group gives you suggestions on how to improve your
|
|||
your crate and are not sure if you have all useful information in your
|
||||
`Cargo.toml`.
|
||||
|
||||
## Nursery
|
||||
|
||||
The `clippy::nursery` group contains lints which are buggy or need more work. It is **not**
|
||||
recommended to enable the whole group, but rather cherry-pick lints that are useful for your
|
||||
code base and your use case.
|
||||
|
||||
## Deprecated
|
||||
|
||||
The `clippy::deprecated` is empty lints that exist to ensure that `#[allow(lintname)]` still
|
||||
compiles after the lint was deprecated. Deprecation "removes" lints by removing their
|
||||
functionality and marking them as deprecated, which may cause further warnings but cannot
|
||||
cause a compiler error.
|
||||
|
||||
[Clippy lint documentation]: https://rust-lang.github.io/rust-clippy/
|
||||
[Clippy 1.0 RFC]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories
|
||||
|
|
|
@ -621,6 +621,7 @@ define_Conf! {
|
|||
manual_rem_euclid,
|
||||
manual_repeat_n,
|
||||
manual_retain,
|
||||
manual_slice_fill,
|
||||
manual_split_once,
|
||||
manual_str_repeat,
|
||||
manual_strip,
|
||||
|
|
|
@ -255,8 +255,9 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
|
|||
let name_camel = to_camel_case(lint.name);
|
||||
let name_upper = lint_name.to_uppercase();
|
||||
|
||||
result.push_str(&if enable_msrv {
|
||||
formatdoc!(
|
||||
if enable_msrv {
|
||||
let _: fmt::Result = writedoc!(
|
||||
result,
|
||||
r"
|
||||
use clippy_utils::msrvs::{{self, Msrv}};
|
||||
use clippy_config::Conf;
|
||||
|
@ -265,22 +266,24 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
|
|||
use rustc_session::impl_lint_pass;
|
||||
|
||||
"
|
||||
)
|
||||
);
|
||||
} else {
|
||||
formatdoc!(
|
||||
let _: fmt::Result = writedoc!(
|
||||
result,
|
||||
r"
|
||||
{pass_import}
|
||||
use rustc_lint::{{{context_import}, {pass_type}}};
|
||||
use rustc_session::declare_lint_pass;
|
||||
|
||||
"
|
||||
)
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
let _: fmt::Result = writeln!(result, "{}", get_lint_declaration(&name_upper, category));
|
||||
|
||||
result.push_str(&if enable_msrv {
|
||||
formatdoc!(
|
||||
if enable_msrv {
|
||||
let _: fmt::Result = writedoc!(
|
||||
result,
|
||||
r"
|
||||
pub struct {name_camel} {{
|
||||
msrv: Msrv,
|
||||
|
@ -301,16 +304,17 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
|
|||
// TODO: Add MSRV level to `clippy_config/src/msrvs.rs` if needed.
|
||||
// TODO: Update msrv config comment in `clippy_config/src/conf.rs`
|
||||
"
|
||||
)
|
||||
);
|
||||
} else {
|
||||
formatdoc!(
|
||||
let _: fmt::Result = writedoc!(
|
||||
result,
|
||||
r"
|
||||
declare_lint_pass!({name_camel} => [{name_upper}]);
|
||||
|
||||
impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
|
||||
"
|
||||
)
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
|
|
@ -985,17 +985,23 @@ mod tests {
|
|||
Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
];
|
||||
let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
|
||||
expected.insert("group1".to_string(), vec![
|
||||
Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
]);
|
||||
expected.insert("group2".to_string(), vec![Lint::new(
|
||||
"should_assert_eq2",
|
||||
"group2",
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
)]);
|
||||
expected.insert(
|
||||
"group1".to_string(),
|
||||
vec![
|
||||
Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
],
|
||||
);
|
||||
expected.insert(
|
||||
"group2".to_string(),
|
||||
vec![Lint::new(
|
||||
"should_assert_eq2",
|
||||
"group2",
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
)],
|
||||
);
|
||||
assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -292,6 +292,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::loops::MANUAL_FIND_INFO,
|
||||
crate::loops::MANUAL_FLATTEN_INFO,
|
||||
crate::loops::MANUAL_MEMCPY_INFO,
|
||||
crate::loops::MANUAL_SLICE_FILL_INFO,
|
||||
crate::loops::MANUAL_WHILE_LET_SOME_INFO,
|
||||
crate::loops::MISSING_SPIN_LOOP_INFO,
|
||||
crate::loops::MUT_RANGE_BOUND_INFO,
|
||||
|
@ -321,6 +322,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
|
||||
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
|
||||
crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
|
||||
crate::manual_option_as_slice::MANUAL_OPTION_AS_SLICE_INFO,
|
||||
crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO,
|
||||
crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
|
||||
crate::manual_retain::MANUAL_RETAIN_INFO,
|
||||
|
@ -463,6 +465,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::methods::REPEAT_ONCE_INFO,
|
||||
crate::methods::RESULT_FILTER_MAP_INFO,
|
||||
crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
|
||||
crate::methods::RETURN_AND_THEN_INFO,
|
||||
crate::methods::SEARCH_IS_SOME_INFO,
|
||||
crate::methods::SEEK_FROM_CURRENT_INFO,
|
||||
crate::methods::SEEK_TO_START_INSTEAD_OF_REWIND_INFO,
|
||||
|
@ -626,6 +629,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO,
|
||||
crate::pointers_in_nomem_asm_block::POINTERS_IN_NOMEM_ASM_BLOCK_INFO,
|
||||
crate::precedence::PRECEDENCE_INFO,
|
||||
crate::precedence::PRECEDENCE_BITS_INFO,
|
||||
crate::ptr::CMP_NULL_INFO,
|
||||
crate::ptr::INVALID_NULL_PTR_USAGE_INFO,
|
||||
crate::ptr::MUT_FROM_REF_INFO,
|
||||
|
|
|
@ -291,10 +291,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
|
|||
&& let Some(ty) = use_node.defined_ty(cx)
|
||||
&& TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return()).is_deref_stable()
|
||||
{
|
||||
self.state = Some((State::ExplicitDeref { mutability: None }, StateData {
|
||||
first_expr: expr,
|
||||
adjusted_ty,
|
||||
}));
|
||||
self.state = Some((
|
||||
State::ExplicitDeref { mutability: None },
|
||||
StateData {
|
||||
first_expr: expr,
|
||||
adjusted_ty,
|
||||
},
|
||||
));
|
||||
}
|
||||
},
|
||||
RefOp::Method { mutbl, is_ufcs }
|
||||
|
@ -456,10 +459,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
|
|||
&& next_adjust.is_none_or(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
|
||||
&& iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
|
||||
{
|
||||
self.state = Some((State::Borrow { mutability }, StateData {
|
||||
first_expr: expr,
|
||||
adjusted_ty,
|
||||
}));
|
||||
self.state = Some((
|
||||
State::Borrow { mutability },
|
||||
StateData {
|
||||
first_expr: expr,
|
||||
adjusted_ty,
|
||||
},
|
||||
));
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
|
@ -503,10 +509,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
|
|||
let stability = state.stability;
|
||||
report(cx, expr, State::DerefedBorrow(state), data, typeck);
|
||||
if stability.is_deref_stable() {
|
||||
self.state = Some((State::Borrow { mutability }, StateData {
|
||||
first_expr: expr,
|
||||
adjusted_ty,
|
||||
}));
|
||||
self.state = Some((
|
||||
State::Borrow { mutability },
|
||||
StateData {
|
||||
first_expr: expr,
|
||||
adjusted_ty,
|
||||
},
|
||||
));
|
||||
}
|
||||
},
|
||||
(Some((State::DerefedBorrow(state), data)), RefOp::Deref) => {
|
||||
|
@ -531,10 +540,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
|
|||
} else if stability.is_deref_stable()
|
||||
&& let Some(parent) = get_parent_expr(cx, expr)
|
||||
{
|
||||
self.state = Some((State::ExplicitDeref { mutability: None }, StateData {
|
||||
first_expr: parent,
|
||||
adjusted_ty,
|
||||
}));
|
||||
self.state = Some((
|
||||
State::ExplicitDeref { mutability: None },
|
||||
StateData {
|
||||
first_expr: parent,
|
||||
adjusted_ty,
|
||||
},
|
||||
));
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1124,17 +1136,20 @@ impl<'tcx> Dereferencing<'tcx> {
|
|||
if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
|
||||
if let Some(pat) = outer_pat {
|
||||
// Check for auto-deref
|
||||
if !matches!(cx.typeck_results().expr_adjustments(e), [
|
||||
Adjustment {
|
||||
kind: Adjust::Deref(_),
|
||||
if !matches!(
|
||||
cx.typeck_results().expr_adjustments(e),
|
||||
[
|
||||
Adjustment {
|
||||
kind: Adjust::Deref(_),
|
||||
..
|
||||
},
|
||||
Adjustment {
|
||||
kind: Adjust::Deref(_),
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
Adjustment {
|
||||
kind: Adjust::Deref(_),
|
||||
..
|
||||
},
|
||||
..
|
||||
]) {
|
||||
]
|
||||
) {
|
||||
match get_parent_expr(cx, e) {
|
||||
// Field accesses are the same no matter the number of references.
|
||||
Some(Expr {
|
||||
|
|
|
@ -233,10 +233,13 @@ fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool {
|
|||
if let Some(owner) = cx.last_node_with_lint_attrs.as_owner() {
|
||||
let def_id = owner.to_def_id();
|
||||
let def_descr = cx.tcx.def_descr(def_id);
|
||||
diag.span_label(cx.tcx.def_span(def_id), match kind {
|
||||
StopKind::Attr => format!("the attribute applies to this {def_descr}"),
|
||||
StopKind::Doc(_) => format!("the comment documents this {def_descr}"),
|
||||
});
|
||||
diag.span_label(
|
||||
cx.tcx.def_span(def_id),
|
||||
match kind {
|
||||
StopKind::Attr => format!("the attribute applies to this {def_descr}"),
|
||||
StopKind::Doc(_) => format!("the comment documents this {def_descr}"),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
diag.multipart_suggestion_with_style(
|
||||
|
|
|
@ -6,6 +6,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
|
|||
use rustc_middle::ty::Ty;
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::Symbol;
|
||||
use std::fmt::Write;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -183,7 +184,7 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
|
|||
help_str.push_str("either of ");
|
||||
}
|
||||
|
||||
help_str.push_str(&format!("`{ty}::{}` ", lint.as_name(prefix)));
|
||||
write!(help_str, "`{ty}::{}` ", lint.as_name(prefix)).unwrap();
|
||||
|
||||
if i != len && !only_one {
|
||||
help_str.push_str("or ");
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::higher::VecArgs;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
|
||||
use clippy_utils::ty::get_type_diagnostic_name;
|
||||
use clippy_utils::usage::{local_used_after_expr, local_used_in};
|
||||
use clippy_utils::{
|
||||
get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Safety, TyKind};
|
||||
use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, GenericArgs, Param, PatKind, QPath, Safety, TyKind};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{
|
||||
|
@ -239,6 +239,11 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
|
|||
&& !cx.tcx.has_attr(method_def_id, sym::track_caller)
|
||||
&& check_sig(closure_sig, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
|
||||
{
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let generic_args = match path.args.and_then(GenericArgs::span_ext) {
|
||||
Some(span) => format!("::{}", snippet_with_applicability(cx, span, "<..>", &mut app)),
|
||||
None => String::new(),
|
||||
};
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
|
||||
|
@ -251,8 +256,8 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
|
|||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"replace the closure with the method itself",
|
||||
format!("{}::{}", type_name, path.ident.name),
|
||||
Applicability::MachineApplicable,
|
||||
format!("{}::{}{}", type_name, path.ident.name, generic_args),
|
||||
app,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -124,7 +124,9 @@ struct NestingVisitor<'conf, 'cx> {
|
|||
|
||||
impl NestingVisitor<'_, '_> {
|
||||
fn check_indent(&mut self, span: Span, id: NodeId) -> bool {
|
||||
if self.nest_level > self.conf.excessive_nesting_threshold && !span.in_external_macro(self.cx.sess().source_map()) {
|
||||
if self.nest_level > self.conf.excessive_nesting_threshold
|
||||
&& !span.in_external_macro(self.cx.sess().source_map())
|
||||
{
|
||||
self.conf.nodes.insert(id);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -11,7 +11,7 @@ declare_clippy_lint! {
|
|||
/// Detects cases where the result of a `format!` call is
|
||||
/// appended to an existing `String`.
|
||||
///
|
||||
/// ### Why restrict this?
|
||||
/// ### Why is this bad?
|
||||
/// Introduces an extra, avoidable heap allocation.
|
||||
///
|
||||
/// ### Known problems
|
||||
|
@ -35,7 +35,7 @@ declare_clippy_lint! {
|
|||
/// ```
|
||||
#[clippy::version = "1.62.0"]
|
||||
pub FORMAT_PUSH_STRING,
|
||||
restriction,
|
||||
pedantic,
|
||||
"`format!(..)` appended to existing `String`"
|
||||
}
|
||||
declare_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]);
|
||||
|
|
|
@ -7,8 +7,8 @@ use clippy_utils::macros::macro_backtrace;
|
|||
use clippy_utils::source::snippet;
|
||||
use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::{Span, sym};
|
||||
|
||||
|
|
|
@ -217,6 +217,7 @@ mod manual_is_power_of_two;
|
|||
mod manual_let_else;
|
||||
mod manual_main_separator_str;
|
||||
mod manual_non_exhaustive;
|
||||
mod manual_option_as_slice;
|
||||
mod manual_range_patterns;
|
||||
mod manual_rem_euclid;
|
||||
mod manual_retain;
|
||||
|
@ -976,5 +977,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern));
|
||||
store.register_late_pass(|_| Box::<unnecessary_semicolon::UnnecessarySemicolon>::default());
|
||||
store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(manual_option_as_slice::ManualOptionAsSlice::new(conf)));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
|
111
src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs
Normal file
111
src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs
Normal file
|
@ -0,0 +1,111 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::eager_or_lazy::switch_to_eager_eval;
|
||||
use clippy_utils::macros::span_is_local;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::{HasSession, snippet_with_applicability};
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{higher, peel_blocks_with_stmt, span_contains_comment};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_ast::{RangeLimits, UnOp};
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::QPath::Resolved;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Expr, ExprKind, Pat};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::MANUAL_SLICE_FILL;
|
||||
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
pat: &'tcx Pat<'_>,
|
||||
arg: &'tcx Expr<'_>,
|
||||
body: &'tcx Expr<'_>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
msrv: &Msrv,
|
||||
) {
|
||||
if !msrv.meets(msrvs::SLICE_FILL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// `for _ in 0..slice.len() { slice[_] = value; }`
|
||||
if let Some(higher::Range {
|
||||
start: Some(start),
|
||||
end: Some(end),
|
||||
limits: RangeLimits::HalfOpen,
|
||||
}) = higher::Range::hir(arg)
|
||||
&& let ExprKind::Lit(Spanned {
|
||||
node: LitKind::Int(Pu128(0), _),
|
||||
..
|
||||
}) = start.kind
|
||||
&& let ExprKind::Block(..) = body.kind
|
||||
// Check if the body is an assignment to a slice element.
|
||||
&& let ExprKind::Assign(assignee, assignval, _) = peel_blocks_with_stmt(body).kind
|
||||
&& let ExprKind::Index(slice, _, _) = assignee.kind
|
||||
// Check if `len()` is used for the range end.
|
||||
&& let ExprKind::MethodCall(path, recv,..) = end.kind
|
||||
&& path.ident.name == sym::len
|
||||
// Check if the slice which is being assigned to is the same as the one being iterated over.
|
||||
&& let ExprKind::Path(Resolved(_, recv_path)) = recv.kind
|
||||
&& let ExprKind::Path(Resolved(_, slice_path)) = slice.kind
|
||||
&& recv_path.res == slice_path.res
|
||||
&& !assignval.span.from_expansion()
|
||||
// It is generally not equivalent to use the `fill` method if `assignval` can have side effects
|
||||
&& switch_to_eager_eval(cx, assignval)
|
||||
&& span_is_local(assignval.span)
|
||||
// The `fill` method requires that the slice's element type implements the `Clone` trait.
|
||||
&& let Some(clone_trait) = cx.tcx.lang_items().clone_trait()
|
||||
&& implements_trait(cx, cx.typeck_results().expr_ty(slice), clone_trait, &[])
|
||||
{
|
||||
sugg(cx, body, expr, slice.span, assignval.span);
|
||||
}
|
||||
// `for _ in &mut slice { *_ = value; }`
|
||||
else if let ExprKind::AddrOf(_, _, recv) = arg.kind
|
||||
// Check if the body is an assignment to a slice element.
|
||||
&& let ExprKind::Assign(assignee, assignval, _) = peel_blocks_with_stmt(body).kind
|
||||
&& let ExprKind::Unary(UnOp::Deref, slice_iter) = assignee.kind
|
||||
&& let ExprKind::Path(Resolved(_, recv_path)) = recv.kind
|
||||
// Check if the slice which is being assigned to is the same as the one being iterated over.
|
||||
&& let ExprKind::Path(Resolved(_, slice_path)) = slice_iter.kind
|
||||
&& let Res::Local(local) = slice_path.res
|
||||
&& local == pat.hir_id
|
||||
&& !assignval.span.from_expansion()
|
||||
&& switch_to_eager_eval(cx, assignval)
|
||||
&& span_is_local(assignval.span)
|
||||
// The `fill` method cannot be used if the slice's element type does not implement the `Clone` trait.
|
||||
&& let Some(clone_trait) = cx.tcx.lang_items().clone_trait()
|
||||
&& implements_trait(cx, cx.typeck_results().expr_ty(recv), clone_trait, &[])
|
||||
{
|
||||
sugg(cx, body, expr, recv_path.span, assignval.span);
|
||||
}
|
||||
}
|
||||
|
||||
fn sugg<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
body: &'tcx Expr<'_>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
slice_span: rustc_span::Span,
|
||||
assignval_span: rustc_span::Span,
|
||||
) {
|
||||
let mut app = if span_contains_comment(cx.sess().source_map(), body.span) {
|
||||
Applicability::MaybeIncorrect // Comments may be informational.
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_SLICE_FILL,
|
||||
expr.span,
|
||||
"manually filling a slice",
|
||||
"try",
|
||||
format!(
|
||||
"{}.fill({});",
|
||||
snippet_with_applicability(cx, slice_span, "..", &mut app),
|
||||
snippet_with_applicability(cx, assignval_span, "..", &mut app),
|
||||
),
|
||||
app,
|
||||
);
|
||||
}
|
|
@ -8,6 +8,7 @@ mod iter_next_loop;
|
|||
mod manual_find;
|
||||
mod manual_flatten;
|
||||
mod manual_memcpy;
|
||||
mod manual_slice_fill;
|
||||
mod manual_while_let_some;
|
||||
mod missing_spin_loop;
|
||||
mod mut_range_bound;
|
||||
|
@ -714,6 +715,31 @@ declare_clippy_lint! {
|
|||
"possibly unintended infinite loop"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for manually filling a slice with a value.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Using the `fill` method is more idiomatic and concise.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// let mut some_slice = [1, 2, 3, 4, 5];
|
||||
/// for i in 0..some_slice.len() {
|
||||
/// some_slice[i] = 0;
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// let mut some_slice = [1, 2, 3, 4, 5];
|
||||
/// some_slice.fill(0);
|
||||
/// ```
|
||||
#[clippy::version = "1.86.0"]
|
||||
pub MANUAL_SLICE_FILL,
|
||||
style,
|
||||
"manually filling a slice with a value"
|
||||
}
|
||||
|
||||
pub struct Loops {
|
||||
msrv: Msrv,
|
||||
enforce_iter_loop_reborrow: bool,
|
||||
|
@ -750,6 +776,7 @@ impl_lint_pass!(Loops => [
|
|||
MANUAL_WHILE_LET_SOME,
|
||||
UNUSED_ENUMERATE_INDEX,
|
||||
INFINITE_LOOP,
|
||||
MANUAL_SLICE_FILL,
|
||||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Loops {
|
||||
|
@ -823,6 +850,7 @@ impl Loops {
|
|||
) {
|
||||
let is_manual_memcpy_triggered = manual_memcpy::check(cx, pat, arg, body, expr);
|
||||
if !is_manual_memcpy_triggered {
|
||||
manual_slice_fill::check(cx, pat, arg, body, expr, &self.msrv);
|
||||
needless_range_loop::check(cx, pat, arg, body, expr);
|
||||
explicit_counter_loop::check(cx, pat, arg, body, expr, label);
|
||||
}
|
||||
|
|
|
@ -181,13 +181,16 @@ fn build_suggestion(
|
|||
ExprKind::Lit(Spanned {
|
||||
node: LitKind::Int(_, LitIntType::Unsuffixed),
|
||||
..
|
||||
}) | ExprKind::Unary(UnOp::Neg, Expr {
|
||||
kind: ExprKind::Lit(Spanned {
|
||||
node: LitKind::Int(_, LitIntType::Unsuffixed),
|
||||
}) | ExprKind::Unary(
|
||||
UnOp::Neg,
|
||||
Expr {
|
||||
kind: ExprKind::Lit(Spanned {
|
||||
node: LitKind::Int(_, LitIntType::Unsuffixed),
|
||||
..
|
||||
}),
|
||||
..
|
||||
}),
|
||||
..
|
||||
})
|
||||
}
|
||||
)
|
||||
) {
|
||||
format!("_{}", cx.typeck_results().expr_ty(rhs))
|
||||
} else {
|
||||
|
|
225
src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
Normal file
225
src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
Normal file
|
@ -0,0 +1,225 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// This detects various manual reimplementations of `Option::as_slice`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Those implementations are both more complex than calling `as_slice`
|
||||
/// and unlike that incur a branch, pessimizing performance and leading
|
||||
/// to more generated code.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
///# let opt = Some(1);
|
||||
/// _ = opt.as_ref().map_or(&[][..], std::slice::from_ref);
|
||||
/// _ = match opt.as_ref() {
|
||||
/// Some(f) => std::slice::from_ref(f),
|
||||
/// None => &[],
|
||||
/// };
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
///# let opt = Some(1);
|
||||
/// _ = opt.as_slice();
|
||||
/// _ = opt.as_slice();
|
||||
/// ```
|
||||
#[clippy::version = "1.85.0"]
|
||||
pub MANUAL_OPTION_AS_SLICE,
|
||||
complexity,
|
||||
"manual `Option::as_slice`"
|
||||
}
|
||||
|
||||
pub struct ManualOptionAsSlice {
|
||||
msrv: msrvs::Msrv,
|
||||
}
|
||||
|
||||
impl ManualOptionAsSlice {
|
||||
pub fn new(conf: &Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(ManualOptionAsSlice => [MANUAL_OPTION_AS_SLICE]);
|
||||
|
||||
impl LateLintPass<'_> for ManualOptionAsSlice {
|
||||
extract_msrv_attr!(LateContext);
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
let span = expr.span;
|
||||
if span.from_expansion()
|
||||
|| !self.msrv.meets(if clippy_utils::is_in_const_context(cx) {
|
||||
msrvs::CONST_OPTION_AS_SLICE
|
||||
} else {
|
||||
msrvs::OPTION_AS_SLICE
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
match expr.kind {
|
||||
ExprKind::Match(scrutinee, [arm1, arm2], _) => {
|
||||
if is_none_arm(cx, arm2) && check_arms(cx, arm2, arm1)
|
||||
|| is_none_arm(cx, arm1) && check_arms(cx, arm1, arm2)
|
||||
{
|
||||
check_as_ref(cx, scrutinee, span);
|
||||
}
|
||||
},
|
||||
ExprKind::If(cond, then, Some(other)) => {
|
||||
if let ExprKind::Let(let_expr) = cond.kind
|
||||
&& let Some(binding) = extract_ident_from_some_pat(cx, let_expr.pat)
|
||||
&& check_some_body(cx, binding, then)
|
||||
&& is_empty_slice(cx, other.peel_blocks())
|
||||
{
|
||||
check_as_ref(cx, let_expr.init, span);
|
||||
}
|
||||
},
|
||||
ExprKind::MethodCall(seg, callee, [], _) => {
|
||||
if seg.ident.name.as_str() == "unwrap_or_default" {
|
||||
check_map(cx, callee, span);
|
||||
}
|
||||
},
|
||||
ExprKind::MethodCall(seg, callee, [or], _) => match seg.ident.name.as_str() {
|
||||
"unwrap_or" => {
|
||||
if is_empty_slice(cx, or) {
|
||||
check_map(cx, callee, span);
|
||||
}
|
||||
},
|
||||
"unwrap_or_else" => {
|
||||
if returns_empty_slice(cx, or) {
|
||||
check_map(cx, callee, span);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
ExprKind::MethodCall(seg, callee, [or_else, map], _) => match seg.ident.name.as_str() {
|
||||
"map_or" => {
|
||||
if is_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) {
|
||||
check_as_ref(cx, callee, span);
|
||||
}
|
||||
},
|
||||
"map_or_else" => {
|
||||
if returns_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) {
|
||||
check_as_ref(cx, callee, span);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_map(cx: &LateContext<'_>, map: &Expr<'_>, span: Span) {
|
||||
if let ExprKind::MethodCall(seg, callee, [mapping], _) = map.kind
|
||||
&& seg.ident.name == sym::map
|
||||
&& is_slice_from_ref(cx, mapping)
|
||||
{
|
||||
check_as_ref(cx, callee, span);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_as_ref(cx: &LateContext<'_>, expr: &Expr<'_>, span: Span) {
|
||||
if let ExprKind::MethodCall(seg, callee, [], _) = expr.kind
|
||||
&& seg.ident.name == sym::as_ref
|
||||
&& let ty::Adt(adtdef, ..) = cx.typeck_results().expr_ty(callee).kind()
|
||||
&& cx.tcx.is_diagnostic_item(sym::Option, adtdef.did())
|
||||
{
|
||||
if let Some(snippet) = clippy_utils::source::snippet_opt(cx, callee.span) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_OPTION_AS_SLICE,
|
||||
span,
|
||||
"use `Option::as_slice`",
|
||||
"use",
|
||||
format!("{snippet}.as_slice()"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
span_lint(cx, MANUAL_OPTION_AS_SLICE, span, "use `Option_as_slice`");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_ident_from_some_pat(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<Symbol> {
|
||||
if let PatKind::TupleStruct(QPath::Resolved(None, path), [binding], _) = pat.kind
|
||||
&& let Res::Def(DefKind::Ctor(..), def_id) = path.res
|
||||
&& let PatKind::Binding(_mode, _hir_id, ident, _inner_pat) = binding.kind
|
||||
&& clippy_utils::is_lang_item_or_ctor(cx, def_id, LangItem::OptionSome)
|
||||
{
|
||||
Some(ident.name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if `expr` is `std::slice::from_ref(<name>)`. Used in `if let`s.
|
||||
fn check_some_body(cx: &LateContext<'_>, name: Symbol, expr: &Expr<'_>) -> bool {
|
||||
if let ExprKind::Call(slice_from_ref, [arg]) = expr.peel_blocks().kind
|
||||
&& is_slice_from_ref(cx, slice_from_ref)
|
||||
&& let ExprKind::Path(QPath::Resolved(None, path)) = arg.kind
|
||||
&& let [seg] = path.segments
|
||||
{
|
||||
seg.ident.name == name
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn check_arms(cx: &LateContext<'_>, none_arm: &Arm<'_>, some_arm: &Arm<'_>) -> bool {
|
||||
if none_arm.guard.is_none()
|
||||
&& some_arm.guard.is_none()
|
||||
&& is_empty_slice(cx, none_arm.body)
|
||||
&& let Some(name) = extract_ident_from_some_pat(cx, some_arm.pat)
|
||||
{
|
||||
check_some_body(cx, name, some_arm.body)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn returns_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
ExprKind::Path(_) => clippy_utils::is_path_diagnostic_item(cx, expr, sym::default_fn),
|
||||
ExprKind::Closure(cl) => is_empty_slice(cx, cx.tcx.hir().body(cl.body).value),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns if expr returns an empty slice. If:
|
||||
/// - An indexing operation to an empty array with a built-in range. `[][..]`
|
||||
/// - An indexing operation with a zero-ended range. `expr[..0]`
|
||||
/// - A reference to an empty array. `&[]`
|
||||
/// - Or a call to `Default::default`.
|
||||
fn is_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
let expr = peel_hir_expr_refs(expr.peel_blocks()).0;
|
||||
match expr.kind {
|
||||
ExprKind::Index(arr, range, _) => match arr.kind {
|
||||
ExprKind::Array([]) => is_range_literal(range),
|
||||
ExprKind::Array(_) => {
|
||||
let Some(range) = clippy_utils::higher::Range::hir(range) else {
|
||||
return false;
|
||||
};
|
||||
range.end.is_some_and(|e| clippy_utils::is_integer_const(cx, e, 0))
|
||||
},
|
||||
_ => false,
|
||||
},
|
||||
ExprKind::Array([]) => true,
|
||||
ExprKind::Call(def, []) => clippy_utils::is_path_diagnostic_item(cx, def, sym::default_fn),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_slice_from_ref(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
clippy_utils::is_expr_path_def_path(cx, expr, &["core", "slice", "raw", "from_ref"])
|
||||
}
|
|
@ -9,8 +9,8 @@ use rustc_span::sym;
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher::IfLetOrMatch;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{is_default_equivalent, is_in_const_context, peel_blocks, span_contains_comment};
|
||||
use clippy_utils::ty::{expr_type_is_certain, implements_trait};
|
||||
use clippy_utils::{is_default_equivalent, is_in_const_context, path_res, peel_blocks, span_contains_comment};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -158,6 +158,36 @@ fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, exp
|
|||
} else {
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
|
||||
// We now check if the condition is a None variant, in which case we need to specify the type
|
||||
if path_res(cx, condition)
|
||||
.opt_def_id()
|
||||
.is_some_and(|id| Some(cx.tcx.parent(id)) == cx.tcx.lang_items().option_none_variant())
|
||||
{
|
||||
return span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_UNWRAP_OR_DEFAULT,
|
||||
expr.span,
|
||||
format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
|
||||
"replace it with",
|
||||
format!("{receiver}::<{expr_type}>.unwrap_or_default()"),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
|
||||
// We check if the expression type is still uncertain, in which case we ask the user to specify it
|
||||
if !expr_type_is_certain(cx, condition) {
|
||||
return span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_UNWRAP_OR_DEFAULT,
|
||||
expr.span,
|
||||
format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
|
||||
format!("ascribe the type {expr_type} and replace your expression with"),
|
||||
format!("{receiver}.unwrap_or_default()"),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_UNWRAP_OR_DEFAULT,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks};
|
||||
use clippy_utils::{is_none_arm, is_res_lang_ctor, path_res, peel_blocks};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, LangItem, Mutability, PatExpr, PatExprKind, PatKind, QPath};
|
||||
use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
|
||||
|
@ -55,14 +55,6 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
|
|||
}
|
||||
}
|
||||
|
||||
// Checks if arm has the form `None => None`
|
||||
fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
|
||||
matches!(
|
||||
arm.pat.kind,
|
||||
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. }) if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionNone)
|
||||
)
|
||||
}
|
||||
|
||||
// Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
|
||||
fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
|
||||
if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind
|
||||
|
|
|
@ -95,6 +95,7 @@ mod readonly_write_lock;
|
|||
mod redundant_as_str;
|
||||
mod repeat_once;
|
||||
mod result_map_or_else_none;
|
||||
mod return_and_then;
|
||||
mod search_is_some;
|
||||
mod seek_from_current;
|
||||
mod seek_to_start_instead_of_rewind;
|
||||
|
@ -3517,7 +3518,7 @@ declare_clippy_lint! {
|
|||
/// ```
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub FORMAT_COLLECT,
|
||||
perf,
|
||||
pedantic,
|
||||
"`format!`ing every element in a collection, then collecting the strings into a new `String`"
|
||||
}
|
||||
|
||||
|
@ -4365,7 +4366,7 @@ declare_clippy_lint! {
|
|||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for string slices immediantly followed by `as_bytes`.
|
||||
/// Checks for string slices immediately followed by `as_bytes`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// It involves doing an unnecessary UTF-8 alignment check which is less efficient, and can cause a panic.
|
||||
|
@ -4391,6 +4392,46 @@ declare_clippy_lint! {
|
|||
"slicing a string and immediately calling as_bytes is less efficient and can lead to panics"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
///
|
||||
/// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using a question mark (`?`) instead.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// The `and_then` method is used to chain a computation that returns an `Option` or a `Result`.
|
||||
/// This can be replaced with the `?` operator, which is more concise and idiomatic.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// fn test(opt: Option<i32>) -> Option<i32> {
|
||||
/// opt.and_then(|n| {
|
||||
/// if n > 1 {
|
||||
/// Some(n + 1)
|
||||
/// } else {
|
||||
/// None
|
||||
/// }
|
||||
/// })
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// fn test(opt: Option<i32>) -> Option<i32> {
|
||||
/// let n = opt?;
|
||||
/// if n > 1 {
|
||||
/// Some(n + 1)
|
||||
/// } else {
|
||||
/// None
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.86.0"]
|
||||
pub RETURN_AND_THEN,
|
||||
restriction,
|
||||
"using `Option::and_then` or `Result::and_then` to chain a computation that returns an `Option` or a `Result`"
|
||||
}
|
||||
|
||||
pub struct Methods {
|
||||
avoid_breaking_exported_api: bool,
|
||||
msrv: Msrv,
|
||||
|
@ -4560,6 +4601,7 @@ impl_lint_pass!(Methods => [
|
|||
USELESS_NONZERO_NEW_UNCHECKED,
|
||||
MANUAL_REPEAT_N,
|
||||
SLICED_STRING_AS_BYTES,
|
||||
RETURN_AND_THEN,
|
||||
]);
|
||||
|
||||
/// Extracts a method call name, args, and `Span` of the method name.
|
||||
|
@ -4789,7 +4831,10 @@ impl Methods {
|
|||
let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg);
|
||||
let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg);
|
||||
if !biom_option_linted && !biom_result_linted {
|
||||
unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
|
||||
let ule_and_linted = unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
|
||||
if !ule_and_linted {
|
||||
return_and_then::check(cx, expr, recv, arg);
|
||||
}
|
||||
}
|
||||
},
|
||||
("any", [arg]) => {
|
||||
|
@ -5003,7 +5048,9 @@ impl Methods {
|
|||
get_first::check(cx, expr, recv, arg);
|
||||
get_last_with_len::check(cx, expr, recv, arg);
|
||||
},
|
||||
("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
|
||||
("get_or_insert_with", [arg]) => {
|
||||
unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert");
|
||||
},
|
||||
("hash", [arg]) => {
|
||||
unit_hash::check(cx, expr, recv, arg);
|
||||
},
|
||||
|
@ -5144,7 +5191,9 @@ impl Methods {
|
|||
},
|
||||
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
|
||||
},
|
||||
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
|
||||
("ok_or_else", [arg]) => {
|
||||
unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or");
|
||||
},
|
||||
("open", [_]) => {
|
||||
open_options::check(cx, expr, recv);
|
||||
},
|
||||
|
@ -5437,9 +5486,12 @@ impl ShouldImplTraitCase {
|
|||
fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool {
|
||||
self.lint_explicit_lifetime
|
||||
|| !impl_item.generics.params.iter().any(|p| {
|
||||
matches!(p.kind, hir::GenericParamKind::Lifetime {
|
||||
kind: hir::LifetimeParamKind::Explicit
|
||||
})
|
||||
matches!(
|
||||
p.kind,
|
||||
hir::GenericParamKind::Lifetime {
|
||||
kind: hir::LifetimeParamKind::Explicit
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_note;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
@ -10,13 +11,22 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
|
|||
// Checks if expression type is equal to sym::Option and if the expr is not a syntactic place
|
||||
if !recv.is_syntactic_place_expr() && is_expr_option(cx, recv) {
|
||||
if let Some(function_name) = source_of_temporary_value(recv) {
|
||||
span_lint_and_note(
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_OPTION_TAKE,
|
||||
expr.span,
|
||||
"called `Option::take()` on a temporary value",
|
||||
None,
|
||||
format!("`{function_name}` creates a temporary value, so calling take() has no effect"),
|
||||
|diag| {
|
||||
diag.note(format!(
|
||||
"`{function_name}` creates a temporary value, so calling take() has no effect"
|
||||
));
|
||||
diag.span_suggestion(
|
||||
expr.span.with_lo(recv.span.hi()),
|
||||
"remove",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
67
src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
Normal file
67
src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, GenericArg, Ty};
|
||||
use rustc_span::sym;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability};
|
||||
use clippy_utils::ty::get_type_diagnostic_name;
|
||||
use clippy_utils::visitors::for_each_unconsumed_temporary;
|
||||
use clippy_utils::{is_expr_final_block_expr, peel_blocks};
|
||||
|
||||
use super::RETURN_AND_THEN;
|
||||
|
||||
/// lint if `and_then` is the last expression in a block, and
|
||||
/// there are no references or temporaries in the receiver
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &hir::Expr<'_>,
|
||||
recv: &'tcx hir::Expr<'tcx>,
|
||||
arg: &'tcx hir::Expr<'_>,
|
||||
) {
|
||||
if !is_expr_final_block_expr(cx.tcx, expr) {
|
||||
return;
|
||||
}
|
||||
|
||||
let recv_type = cx.typeck_results().expr_ty(recv);
|
||||
if !matches!(get_type_diagnostic_name(cx, recv_type), Some(sym::Option | sym::Result)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let has_ref_type = matches!(recv_type.kind(), ty::Adt(_, args) if args
|
||||
.first()
|
||||
.and_then(|arg0: &GenericArg<'tcx>| GenericArg::as_type(*arg0))
|
||||
.is_some_and(Ty::is_ref));
|
||||
let has_temporaries = for_each_unconsumed_temporary(cx, recv, |_| ControlFlow::Break(())).is_break();
|
||||
if has_ref_type && has_temporaries {
|
||||
return;
|
||||
}
|
||||
|
||||
let hir::ExprKind::Closure(&hir::Closure { body, fn_decl, .. }) = arg.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
let closure_arg = fn_decl.inputs[0];
|
||||
let closure_expr = peel_blocks(cx.tcx.hir().body(body).value);
|
||||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let arg_snip = snippet_with_applicability(cx, closure_arg.span, "_", &mut applicability);
|
||||
let recv_snip = snippet_with_applicability(cx, recv.span, "_", &mut applicability);
|
||||
let body_snip = snippet_with_applicability(cx, closure_expr.span, "..", &mut applicability);
|
||||
let inner = match body_snip.strip_prefix('{').and_then(|s| s.strip_suffix('}')) {
|
||||
Some(s) => s.trim_start_matches('\n').trim_end(),
|
||||
None => &body_snip,
|
||||
};
|
||||
|
||||
let msg = "use the question mark operator instead of an `and_then` call";
|
||||
let sugg = format!(
|
||||
"let {} = {}?;\n{}",
|
||||
arg_snip,
|
||||
recv_snip,
|
||||
reindent_multiline(inner.into(), false, indent_of(cx, expr.span))
|
||||
);
|
||||
|
||||
span_lint_and_sugg(cx, RETURN_AND_THEN, expr.span, msg, "try", sugg, applicability);
|
||||
}
|
|
@ -123,32 +123,60 @@ pub(super) fn check(
|
|||
if let hir::ExprKind::Lit(lit) = init.kind {
|
||||
match lit.node {
|
||||
ast::LitKind::Bool(false) => {
|
||||
check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, Replacement {
|
||||
method_name: "any",
|
||||
has_args: true,
|
||||
has_generic_return: false,
|
||||
});
|
||||
check_fold_with_op(
|
||||
cx,
|
||||
expr,
|
||||
acc,
|
||||
fold_span,
|
||||
hir::BinOpKind::Or,
|
||||
Replacement {
|
||||
method_name: "any",
|
||||
has_args: true,
|
||||
has_generic_return: false,
|
||||
},
|
||||
);
|
||||
},
|
||||
ast::LitKind::Bool(true) => {
|
||||
check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, Replacement {
|
||||
method_name: "all",
|
||||
has_args: true,
|
||||
has_generic_return: false,
|
||||
});
|
||||
check_fold_with_op(
|
||||
cx,
|
||||
expr,
|
||||
acc,
|
||||
fold_span,
|
||||
hir::BinOpKind::And,
|
||||
Replacement {
|
||||
method_name: "all",
|
||||
has_args: true,
|
||||
has_generic_return: false,
|
||||
},
|
||||
);
|
||||
},
|
||||
ast::LitKind::Int(Pu128(0), _) => {
|
||||
check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, Replacement {
|
||||
method_name: "sum",
|
||||
has_args: false,
|
||||
has_generic_return: needs_turbofish(cx, expr),
|
||||
});
|
||||
check_fold_with_op(
|
||||
cx,
|
||||
expr,
|
||||
acc,
|
||||
fold_span,
|
||||
hir::BinOpKind::Add,
|
||||
Replacement {
|
||||
method_name: "sum",
|
||||
has_args: false,
|
||||
has_generic_return: needs_turbofish(cx, expr),
|
||||
},
|
||||
);
|
||||
},
|
||||
ast::LitKind::Int(Pu128(1), _) => {
|
||||
check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, Replacement {
|
||||
method_name: "product",
|
||||
has_args: false,
|
||||
has_generic_return: needs_turbofish(cx, expr),
|
||||
});
|
||||
check_fold_with_op(
|
||||
cx,
|
||||
expr,
|
||||
acc,
|
||||
fold_span,
|
||||
hir::BinOpKind::Mul,
|
||||
Replacement {
|
||||
method_name: "product",
|
||||
has_args: false,
|
||||
has_generic_return: needs_turbofish(cx, expr),
|
||||
},
|
||||
);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ pub(super) fn check<'tcx>(
|
|||
recv: &'tcx hir::Expr<'_>,
|
||||
arg: &'tcx hir::Expr<'_>,
|
||||
simplify_using: &str,
|
||||
) {
|
||||
) -> bool {
|
||||
let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option);
|
||||
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
|
||||
let is_bool = cx.typeck_results().expr_ty(recv).is_bool();
|
||||
|
@ -29,7 +29,7 @@ pub(super) fn check<'tcx>(
|
|||
let body_expr = &body.value;
|
||||
|
||||
if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if eager_or_lazy::switch_to_eager_eval(cx, body_expr) {
|
||||
|
@ -71,8 +71,10 @@ pub(super) fn check<'tcx>(
|
|||
applicability,
|
||||
);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
|
|||
TOPLEVEL_REF_ARG,
|
||||
arg.hir_id,
|
||||
arg.pat.span,
|
||||
"`ref` directly on a function argument is ignored. \
|
||||
"`ref` directly on a function parameter does not prevent taking ownership of the passed argument. \
|
||||
Consider using a reference type instead",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -152,16 +152,19 @@ fn collect_unsafe_exprs<'tcx>(
|
|||
ExprKind::AssignOp(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => {
|
||||
if matches!(
|
||||
lhs.kind,
|
||||
ExprKind::Path(QPath::Resolved(_, hir::Path {
|
||||
res: Res::Def(
|
||||
DefKind::Static {
|
||||
mutability: Mutability::Mut,
|
||||
..
|
||||
},
|
||||
_
|
||||
),
|
||||
..
|
||||
}))
|
||||
ExprKind::Path(QPath::Resolved(
|
||||
_,
|
||||
hir::Path {
|
||||
res: Res::Def(
|
||||
DefKind::Static {
|
||||
mutability: Mutability::Mut,
|
||||
..
|
||||
},
|
||||
_
|
||||
),
|
||||
..
|
||||
}
|
||||
))
|
||||
) {
|
||||
unsafe_ops.push(("modification of a mutable static occurs here", expr.span));
|
||||
collect_unsafe_exprs(cx, rhs, unsafe_ops);
|
||||
|
|
|
@ -18,11 +18,14 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// On the other hand, `Mutex`es are, in general, easier to
|
||||
/// verify correctness. An atomic does not behave the same as
|
||||
/// an equivalent mutex. See [this issue](https://github.com/rust-lang/rust-clippy/issues/4295)'s commentary for more details.
|
||||
/// an equivalent mutex. See [this issue](https://github.com/rust-lang/rust-clippy/issues/4295)'s
|
||||
/// commentary for more details.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// This lint cannot detect if the mutex is actually used
|
||||
/// for waiting before a critical section.
|
||||
/// * This lint cannot detect if the mutex is actually used
|
||||
/// for waiting before a critical section.
|
||||
/// * This lint has a false positive that warns without considering the case
|
||||
/// where `Mutex` is used together with `Condvar`.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
|
@ -48,14 +51,23 @@ declare_clippy_lint! {
|
|||
/// Checks for usage of `Mutex<X>` where `X` is an integral
|
||||
/// type.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// ### Why restrict this?
|
||||
/// Using a mutex just to make access to a plain integer
|
||||
/// sequential is
|
||||
/// shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster.
|
||||
///
|
||||
/// On the other hand, `Mutex`es are, in general, easier to
|
||||
/// verify correctness. An atomic does not behave the same as
|
||||
/// an equivalent mutex. See [this issue](https://github.com/rust-lang/rust-clippy/issues/4295)'s
|
||||
/// commentary for more details.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// This lint cannot detect if the mutex is actually used
|
||||
/// for waiting before a critical section.
|
||||
/// * This lint cannot detect if the mutex is actually used
|
||||
/// for waiting before a critical section.
|
||||
/// * This lint has a false positive that warns without considering the case
|
||||
/// where `Mutex` is used together with `Condvar`.
|
||||
/// * This lint suggest using `AtomicU64` instead of `Mutex<u64>`, but
|
||||
/// `AtomicU64` is not available on some 32-bit platforms.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
|
@ -70,7 +82,7 @@ declare_clippy_lint! {
|
|||
/// ```
|
||||
#[clippy::version = "pre 1.29.0"]
|
||||
pub MUTEX_INTEGER,
|
||||
nursery,
|
||||
restriction,
|
||||
"using a mutex for an integer type"
|
||||
}
|
||||
|
||||
|
@ -108,7 +120,7 @@ fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> {
|
|||
UintTy::U32 => Some("AtomicU32"),
|
||||
UintTy::U64 => Some("AtomicU64"),
|
||||
UintTy::Usize => Some("AtomicUsize"),
|
||||
// There's no `AtomicU128`.
|
||||
// `AtomicU128` is unstable and only available on a few platforms: https://github.com/rust-lang/rust/issues/99069
|
||||
UintTy::U128 => None,
|
||||
}
|
||||
},
|
||||
|
@ -119,7 +131,7 @@ fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> {
|
|||
IntTy::I32 => Some("AtomicI32"),
|
||||
IntTy::I64 => Some("AtomicI64"),
|
||||
IntTy::Isize => Some("AtomicIsize"),
|
||||
// There's no `AtomicI128`.
|
||||
// `AtomicU128` is unstable and only available on a few platforms: https://github.com/rust-lang/rust/issues/99069
|
||||
IntTy::I128 => None,
|
||||
}
|
||||
},
|
||||
|
|
|
@ -181,9 +181,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
|
|||
&& !is_copy(cx, ty)
|
||||
&& ty.is_sized(cx.tcx, cx.typing_env())
|
||||
&& !allowed_traits.iter().any(|&t| {
|
||||
implements_trait_with_env_from_iter(cx.tcx, cx.typing_env(), ty, t, None, [None::<
|
||||
ty::GenericArg<'tcx>,
|
||||
>])
|
||||
implements_trait_with_env_from_iter(
|
||||
cx.tcx,
|
||||
cx.typing_env(),
|
||||
ty,
|
||||
t,
|
||||
None,
|
||||
[None::<ty::GenericArg<'tcx>>],
|
||||
)
|
||||
})
|
||||
&& !implements_borrow_trait
|
||||
&& !all_borrowable_trait
|
||||
|
|
|
@ -265,9 +265,6 @@ declare_clippy_lint! {
|
|||
/// `x.trailing_zeros() >= 4` is much clearer than `x & 15
|
||||
/// == 0`
|
||||
///
|
||||
/// ### Known problems
|
||||
/// llvm generates better code for `x & 15 == 0` on x86
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// # let x = 1;
|
||||
|
|
|
@ -3,17 +3,14 @@ use clippy_utils::source::snippet_with_applicability;
|
|||
use rustc_ast::ast::BinOpKind::{Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Shl, Shr, Sub};
|
||||
use rustc_ast::ast::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, Lint};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::source_map::Spanned;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for operations where precedence may be unclear
|
||||
/// and suggests to add parentheses. Currently it catches the following:
|
||||
/// * mixed usage of arithmetic and bit shifting/combining operators without
|
||||
/// parentheses
|
||||
/// * mixed usage of bitmasking and bit shifting operators without parentheses
|
||||
/// Checks for operations where precedence may be unclear and suggests to add parentheses.
|
||||
/// It catches a mixed usage of arithmetic and bit shifting/combining operators without parentheses
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Not everyone knows the precedence of those operators by
|
||||
|
@ -21,15 +18,32 @@ declare_clippy_lint! {
|
|||
/// code.
|
||||
///
|
||||
/// ### Example
|
||||
/// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7
|
||||
/// * `0x2345 & 0xF000 >> 12` equals 5, while `(0x2345 & 0xF000) >> 12` equals 2
|
||||
/// `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7
|
||||
#[clippy::version = "pre 1.29.0"]
|
||||
pub PRECEDENCE,
|
||||
complexity,
|
||||
"operations where precedence may be unclear"
|
||||
}
|
||||
|
||||
declare_lint_pass!(Precedence => [PRECEDENCE]);
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for bit shifting operations combined with bit masking/combining operators
|
||||
/// and suggest using parentheses.
|
||||
///
|
||||
/// ### Why restrict this?
|
||||
/// Not everyone knows the precedence of those operators by
|
||||
/// heart, so expressions like these may trip others trying to reason about the
|
||||
/// code.
|
||||
///
|
||||
/// ### Example
|
||||
/// `0x2345 & 0xF000 >> 12` equals 5, while `(0x2345 & 0xF000) >> 12` equals 2
|
||||
#[clippy::version = "1.86.0"]
|
||||
pub PRECEDENCE_BITS,
|
||||
restriction,
|
||||
"operations mixing bit shifting with bit combining/masking"
|
||||
}
|
||||
|
||||
declare_lint_pass!(Precedence => [PRECEDENCE, PRECEDENCE_BITS]);
|
||||
|
||||
impl EarlyLintPass for Precedence {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
|
@ -38,10 +52,10 @@ impl EarlyLintPass for Precedence {
|
|||
}
|
||||
|
||||
if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.kind {
|
||||
let span_sugg = |expr: &Expr, sugg, appl| {
|
||||
let span_sugg = |lint: &'static Lint, expr: &Expr, sugg, appl| {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
PRECEDENCE,
|
||||
lint,
|
||||
expr.span,
|
||||
"operator precedence might not be obvious",
|
||||
"consider parenthesizing your expression",
|
||||
|
@ -57,37 +71,41 @@ impl EarlyLintPass for Precedence {
|
|||
match (op, get_bin_opt(left), get_bin_opt(right)) {
|
||||
(
|
||||
BitAnd | BitOr | BitXor,
|
||||
Some(Shl | Shr | Add | Div | Mul | Rem | Sub),
|
||||
Some(Shl | Shr | Add | Div | Mul | Rem | Sub),
|
||||
Some(left_op @ (Shl | Shr | Add | Div | Mul | Rem | Sub)),
|
||||
Some(right_op @ (Shl | Shr | Add | Div | Mul | Rem | Sub)),
|
||||
)
|
||||
| (Shl | Shr, Some(Add | Div | Mul | Rem | Sub), Some(Add | Div | Mul | Rem | Sub)) => {
|
||||
| (
|
||||
Shl | Shr,
|
||||
Some(left_op @ (Add | Div | Mul | Rem | Sub)),
|
||||
Some(right_op @ (Add | Div | Mul | Rem | Sub)),
|
||||
) => {
|
||||
let sugg = format!(
|
||||
"({}) {} ({})",
|
||||
snippet_with_applicability(cx, left.span, "..", &mut applicability),
|
||||
op.as_str(),
|
||||
snippet_with_applicability(cx, right.span, "..", &mut applicability)
|
||||
);
|
||||
span_sugg(expr, sugg, applicability);
|
||||
span_sugg(lint_for(&[op, left_op, right_op]), expr, sugg, applicability);
|
||||
},
|
||||
(BitAnd | BitOr | BitXor, Some(Shl | Shr | Add | Div | Mul | Rem | Sub), _)
|
||||
| (Shl | Shr, Some(Add | Div | Mul | Rem | Sub), _) => {
|
||||
(BitAnd | BitOr | BitXor, Some(side_op @ (Shl | Shr | Add | Div | Mul | Rem | Sub)), _)
|
||||
| (Shl | Shr, Some(side_op @ (Add | Div | Mul | Rem | Sub)), _) => {
|
||||
let sugg = format!(
|
||||
"({}) {} {}",
|
||||
snippet_with_applicability(cx, left.span, "..", &mut applicability),
|
||||
op.as_str(),
|
||||
snippet_with_applicability(cx, right.span, "..", &mut applicability)
|
||||
);
|
||||
span_sugg(expr, sugg, applicability);
|
||||
span_sugg(lint_for(&[op, side_op]), expr, sugg, applicability);
|
||||
},
|
||||
(BitAnd | BitOr | BitXor, _, Some(Shl | Shr | Add | Div | Mul | Rem | Sub))
|
||||
| (Shl | Shr, _, Some(Add | Div | Mul | Rem | Sub)) => {
|
||||
(BitAnd | BitOr | BitXor, _, Some(side_op @ (Shl | Shr | Add | Div | Mul | Rem | Sub)))
|
||||
| (Shl | Shr, _, Some(side_op @ (Add | Div | Mul | Rem | Sub))) => {
|
||||
let sugg = format!(
|
||||
"{} {} ({})",
|
||||
snippet_with_applicability(cx, left.span, "..", &mut applicability),
|
||||
op.as_str(),
|
||||
snippet_with_applicability(cx, right.span, "..", &mut applicability)
|
||||
);
|
||||
span_sugg(expr, sugg, applicability);
|
||||
span_sugg(lint_for(&[op, side_op]), expr, sugg, applicability);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
@ -106,3 +124,11 @@ fn get_bin_opt(expr: &Expr) -> Option<BinOpKind> {
|
|||
fn is_bit_op(op: BinOpKind) -> bool {
|
||||
matches!(op, BitXor | BitAnd | BitOr | Shl | Shr)
|
||||
}
|
||||
|
||||
fn lint_for(ops: &[BinOpKind]) -> &'static Lint {
|
||||
if ops.iter().all(|op| is_bit_op(*op)) {
|
||||
PRECEDENCE_BITS
|
||||
} else {
|
||||
PRECEDENCE
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::visitors::contains_unsafe_block;
|
||||
use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core};
|
||||
use hir::LifetimeName;
|
||||
|
@ -250,15 +251,24 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
|
|||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Binary(ref op, l, r) = expr.kind {
|
||||
if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(cx, l) || is_null_path(cx, r)) {
|
||||
span_lint(
|
||||
cx,
|
||||
CMP_NULL,
|
||||
expr.span,
|
||||
"comparing with null is better expressed by the `.is_null()` method",
|
||||
);
|
||||
}
|
||||
if let ExprKind::Binary(op, l, r) = expr.kind
|
||||
&& (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne)
|
||||
{
|
||||
let non_null_path_snippet = match (is_null_path(cx, l), is_null_path(cx, r)) {
|
||||
(true, false) if let Some(sugg) = Sugg::hir_opt(cx, r) => sugg.maybe_par(),
|
||||
(false, true) if let Some(sugg) = Sugg::hir_opt(cx, l) => sugg.maybe_par(),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
CMP_NULL,
|
||||
expr.span,
|
||||
"comparing with null is better expressed by the `.is_null()` method",
|
||||
"try",
|
||||
format!("{non_null_path_snippet}.is_null()"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
check_invalid_ptr_usage(cx, expr);
|
||||
}
|
||||
|
|
|
@ -349,10 +349,14 @@ fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>,
|
|||
local_use_locs: _,
|
||||
local_consume_or_mutate_locs: clone_consume_or_mutate_locs,
|
||||
},
|
||||
)) = visit_local_usage(&[cloned, clone], mir, mir::Location {
|
||||
block: bb,
|
||||
statement_index: mir.basic_blocks[bb].statements.len(),
|
||||
})
|
||||
)) = visit_local_usage(
|
||||
&[cloned, clone],
|
||||
mir,
|
||||
mir::Location {
|
||||
block: bb,
|
||||
statement_index: mir.basic_blocks[bb].statements.len(),
|
||||
},
|
||||
)
|
||||
.map(|mut vec| (vec.remove(0), vec.remove(0)))
|
||||
{
|
||||
CloneUsage {
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, snippet};
|
||||
use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind};
|
||||
use rustc_ast::visit::{Visitor, walk_expr};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::Span;
|
||||
use std::borrow::Cow;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -75,13 +79,27 @@ impl EarlyLintPass for RedundantElse {
|
|||
_ => break,
|
||||
}
|
||||
}
|
||||
span_lint_and_help(
|
||||
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
if let ExprKind::Block(block, _) = &els.kind {
|
||||
for stmt in &block.stmts {
|
||||
// If the `else` block contains a local binding or a macro invocation, Clippy shouldn't auto-fix it
|
||||
if matches!(&stmt.kind, StmtKind::Let(_) | StmtKind::MacCall(_)) {
|
||||
app = Applicability::Unspecified;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: The indentation of the suggestion would be the same as the one of the macro invocation in this implementation, see https://github.com/rust-lang/rust-clippy/pull/13936#issuecomment-2569548202
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REDUNDANT_ELSE,
|
||||
els.span,
|
||||
els.span.with_lo(then.span.hi()),
|
||||
"redundant else block",
|
||||
None,
|
||||
"remove the `else` block and move the contents out",
|
||||
make_sugg(cx, els.span, "..", Some(expr.span)).to_string(),
|
||||
app,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -136,3 +154,23 @@ impl BreakVisitor {
|
|||
self.check(stmt, Self::visit_stmt)
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the inner contents of an `else` block str
|
||||
// e.g. `{ foo(); bar(); }` -> `foo(); bar();`
|
||||
fn extract_else_block(mut block: &str) -> String {
|
||||
block = block.strip_prefix("{").unwrap_or(block);
|
||||
block = block.strip_suffix("}").unwrap_or(block);
|
||||
block.trim_end().to_string()
|
||||
}
|
||||
|
||||
fn make_sugg<'a>(
|
||||
cx: &EarlyContext<'_>,
|
||||
els_span: Span,
|
||||
default: &'a str,
|
||||
indent_relative_to: Option<Span>,
|
||||
) -> Cow<'a, str> {
|
||||
let extracted = extract_else_block(&snippet(cx, els_span, default));
|
||||
let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
|
||||
|
||||
reindent_multiline(extracted.into(), false, indent)
|
||||
}
|
||||
|
|
|
@ -62,10 +62,13 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
|
|||
&& let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
|
||||
{
|
||||
if !map.contains_key(res) {
|
||||
map.insert(*res, ExistingName {
|
||||
impl_methods: BTreeMap::new(),
|
||||
trait_methods: BTreeMap::new(),
|
||||
});
|
||||
map.insert(
|
||||
*res,
|
||||
ExistingName {
|
||||
impl_methods: BTreeMap::new(),
|
||||
trait_methods: BTreeMap::new(),
|
||||
},
|
||||
);
|
||||
}
|
||||
let existing_name = map.get_mut(res).unwrap();
|
||||
|
||||
|
|
|
@ -63,8 +63,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
|
|||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> {
|
||||
const METHODS: [&str; 11] = [
|
||||
"write_bytes",
|
||||
const METHODS: [&str; 10] = [
|
||||
"copy_to",
|
||||
"copy_from",
|
||||
"copy_to_nonoverlapping",
|
||||
|
@ -79,7 +78,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
|
|||
|
||||
if let ExprKind::Call(func, [.., count]) = expr.kind
|
||||
// Find calls to ptr::{copy, copy_nonoverlapping}
|
||||
// and ptr::{swap_nonoverlapping, write_bytes},
|
||||
// and ptr::swap_nonoverlapping,
|
||||
&& let ExprKind::Path(ref func_qpath) = func.kind
|
||||
&& let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id()
|
||||
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(
|
||||
|
@ -88,7 +87,6 @@ fn get_pointee_ty_and_count_expr<'tcx>(
|
|||
| sym::ptr_slice_from_raw_parts
|
||||
| sym::ptr_slice_from_raw_parts_mut
|
||||
| sym::ptr_swap_nonoverlapping
|
||||
| sym::ptr_write_bytes
|
||||
| sym::slice_from_raw_parts
|
||||
| sym::slice_from_raw_parts_mut
|
||||
))
|
||||
|
@ -99,7 +97,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
|
|||
return Some((pointee_ty, count));
|
||||
}
|
||||
if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind
|
||||
// Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods
|
||||
// Find calls to copy_{from,to}{,_nonoverlapping}
|
||||
&& let method_ident = method_path.ident.as_str()
|
||||
&& METHODS.iter().any(|m| *m == method_ident)
|
||||
|
||||
|
@ -121,6 +119,8 @@ impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount {
|
|||
instead of a count of elements of `T`";
|
||||
|
||||
if let Some((pointee_ty, count_expr)) = get_pointee_ty_and_count_expr(cx, expr)
|
||||
// Using a number of bytes for a byte type isn't suspicious
|
||||
&& pointee_ty != cx.tcx.types.u8
|
||||
// Find calls to functions with an element count parameter and get
|
||||
// the pointee type and count parameter expression
|
||||
|
||||
|
|
|
@ -55,13 +55,11 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
|
|||
if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind
|
||||
&& let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id)
|
||||
&& let Some(to_digits_def_id) = to_digits_call_res.opt_def_id()
|
||||
&& match_def_path(cx, to_digits_def_id, &[
|
||||
"core",
|
||||
"char",
|
||||
"methods",
|
||||
"<impl char>",
|
||||
"to_digit",
|
||||
])
|
||||
&& match_def_path(
|
||||
cx,
|
||||
to_digits_def_id,
|
||||
&["core", "char", "methods", "<impl char>", "to_digit"],
|
||||
)
|
||||
{
|
||||
Some((false, char_arg, radix_arg))
|
||||
} else {
|
||||
|
|
|
@ -386,22 +386,30 @@ impl<'tcx> LateLintPass<'tcx> for Types {
|
|||
|
||||
let is_exported = cx.effective_visibilities.is_exported(def_id);
|
||||
|
||||
self.check_fn_decl(cx, decl, CheckTyContext {
|
||||
is_in_trait_impl,
|
||||
in_body: matches!(fn_kind, FnKind::Closure),
|
||||
is_exported,
|
||||
..CheckTyContext::default()
|
||||
});
|
||||
self.check_fn_decl(
|
||||
cx,
|
||||
decl,
|
||||
CheckTyContext {
|
||||
is_in_trait_impl,
|
||||
in_body: matches!(fn_kind, FnKind::Closure),
|
||||
is_exported,
|
||||
..CheckTyContext::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
|
||||
|
||||
match item.kind {
|
||||
ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty(cx, ty, CheckTyContext {
|
||||
is_exported,
|
||||
..CheckTyContext::default()
|
||||
}),
|
||||
ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty(
|
||||
cx,
|
||||
ty,
|
||||
CheckTyContext {
|
||||
is_exported,
|
||||
..CheckTyContext::default()
|
||||
},
|
||||
),
|
||||
// functions, enums, structs, impls and traits are covered
|
||||
_ => (),
|
||||
}
|
||||
|
@ -419,10 +427,14 @@ impl<'tcx> LateLintPass<'tcx> for Types {
|
|||
false
|
||||
};
|
||||
|
||||
self.check_ty(cx, ty, CheckTyContext {
|
||||
is_in_trait_impl,
|
||||
..CheckTyContext::default()
|
||||
});
|
||||
self.check_ty(
|
||||
cx,
|
||||
ty,
|
||||
CheckTyContext {
|
||||
is_in_trait_impl,
|
||||
..CheckTyContext::default()
|
||||
},
|
||||
);
|
||||
},
|
||||
// Methods are covered by check_fn.
|
||||
// Type aliases are ignored because oftentimes it's impossible to
|
||||
|
@ -438,10 +450,14 @@ impl<'tcx> LateLintPass<'tcx> for Types {
|
|||
|
||||
let is_exported = cx.effective_visibilities.is_exported(field.def_id);
|
||||
|
||||
self.check_ty(cx, field.ty, CheckTyContext {
|
||||
is_exported,
|
||||
..CheckTyContext::default()
|
||||
});
|
||||
self.check_ty(
|
||||
cx,
|
||||
field.ty,
|
||||
CheckTyContext {
|
||||
is_exported,
|
||||
..CheckTyContext::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'tcx>) {
|
||||
|
@ -469,10 +485,14 @@ impl<'tcx> LateLintPass<'tcx> for Types {
|
|||
|
||||
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) {
|
||||
if let Some(ty) = local.ty {
|
||||
self.check_ty(cx, ty, CheckTyContext {
|
||||
in_body: true,
|
||||
..CheckTyContext::default()
|
||||
});
|
||||
self.check_ty(
|
||||
cx,
|
||||
ty,
|
||||
CheckTyContext {
|
||||
in_body: true,
|
||||
..CheckTyContext::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -257,10 +257,13 @@ fn is_default_method_on_current_ty<'tcx>(tcx: TyCtxt<'tcx>, qpath: QPath<'tcx>,
|
|||
}
|
||||
if matches!(
|
||||
ty.kind,
|
||||
TyKind::Path(QPath::Resolved(_, hir::Path {
|
||||
res: Res::SelfTyAlias { .. },
|
||||
..
|
||||
},))
|
||||
TyKind::Path(QPath::Resolved(
|
||||
_,
|
||||
hir::Path {
|
||||
res: Res::SelfTyAlias { .. },
|
||||
..
|
||||
},
|
||||
))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ declare_clippy_lint! {
|
|||
|
||||
#[derive(Default)]
|
||||
pub struct UnnecessarySemicolon {
|
||||
last_statements: Vec<HirId>,
|
||||
last_statements: Vec<(HirId, bool)>,
|
||||
}
|
||||
|
||||
impl_lint_pass!(UnnecessarySemicolon => [UNNECESSARY_SEMICOLON]);
|
||||
|
@ -45,27 +45,25 @@ impl_lint_pass!(UnnecessarySemicolon => [UNNECESSARY_SEMICOLON]);
|
|||
impl UnnecessarySemicolon {
|
||||
/// Enter or leave a block, remembering the last statement of the block.
|
||||
fn handle_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>, enter: bool) {
|
||||
// Up to edition 2021, removing the semicolon of the last statement of a block
|
||||
// may result in the scrutinee temporary values to live longer than the block
|
||||
// variables. To avoid this problem, we do not lint the last statement of an
|
||||
// expressionless block.
|
||||
if cx.tcx.sess.edition() <= Edition2021
|
||||
&& block.expr.is_none()
|
||||
// The last statement of an expressionless block deserves a special treatment.
|
||||
if block.expr.is_none()
|
||||
&& let Some(last_stmt) = block.stmts.last()
|
||||
{
|
||||
if enter {
|
||||
self.last_statements.push(last_stmt.hir_id);
|
||||
let block_ty = cx.typeck_results().node_type(block.hir_id);
|
||||
self.last_statements.push((last_stmt.hir_id, block_ty.is_unit()));
|
||||
} else {
|
||||
self.last_statements.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if `stmt` is the last statement in an expressionless block for edition ≤ 2021.
|
||||
fn is_last_in_block(&self, stmt: &Stmt<'_>) -> bool {
|
||||
/// Checks if `stmt` is the last statement in an expressionless block. In this case,
|
||||
/// return `Some` with a boolean which is `true` if the block type is `()`.
|
||||
fn is_last_in_block(&self, stmt: &Stmt<'_>) -> Option<bool> {
|
||||
self.last_statements
|
||||
.last()
|
||||
.is_some_and(|last_stmt_id| last_stmt_id == &stmt.hir_id)
|
||||
.and_then(|&(stmt_id, is_unit)| (stmt_id == stmt.hir_id).then_some(is_unit))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,8 +88,22 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessarySemicolon {
|
|||
)
|
||||
&& cx.typeck_results().expr_ty(expr) == cx.tcx.types.unit
|
||||
{
|
||||
if self.is_last_in_block(stmt) && leaks_droppable_temporary_with_limited_lifetime(cx, expr) {
|
||||
return;
|
||||
if let Some(block_is_unit) = self.is_last_in_block(stmt) {
|
||||
if cx.tcx.sess.edition() <= Edition2021 && leaks_droppable_temporary_with_limited_lifetime(cx, expr) {
|
||||
// The expression contains temporaries with limited lifetimes in edition lower than 2024. Those may
|
||||
// survive until after the end of the current scope instead of until the end of the statement, so do
|
||||
// not lint this situation.
|
||||
return;
|
||||
}
|
||||
|
||||
if !block_is_unit {
|
||||
// Although the expression returns `()`, the block doesn't. This may happen if the expression
|
||||
// returns early in all code paths, such as a `return value` in the condition of an `if` statement,
|
||||
// in which case the block type would be `!`. Do not lint in this case, as the statement would
|
||||
// become the block expression; the block type would become `()` and this may not type correctly
|
||||
// if the expected type for the block is not `()`.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let semi_span = expr.span.shrink_to_hi().to(stmt.span.shrink_to_hi());
|
||||
|
|
|
@ -32,7 +32,7 @@ declare_clippy_lint! {
|
|||
/// None => 0,
|
||||
/// };
|
||||
/// ```
|
||||
#[clippy::version = "1.83.0"]
|
||||
#[clippy::version = "1.86.0"]
|
||||
pub UNNEEDED_STRUCT_PATTERN,
|
||||
style,
|
||||
"using struct pattern to match against unit variant"
|
||||
|
|
|
@ -522,7 +522,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
|
|||
|
||||
let replacement = match (format_string_is_raw, replace_raw) {
|
||||
(false, false) => Some(replacement),
|
||||
(false, true) => Some(replacement.replace('"', "\\\"").replace('\\', "\\\\")),
|
||||
(false, true) => Some(replacement.replace('\\', "\\\\").replace('"', "\\\"")),
|
||||
(true, false) => match conservative_unescape(&replacement) {
|
||||
Ok(unescaped) => Some(unescaped),
|
||||
Err(UnescapeErr::Lint) => None,
|
||||
|
|
|
@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
|
|||
|
||||
<!-- begin autogenerated nightly -->
|
||||
```
|
||||
nightly-2025-01-28
|
||||
nightly-2025-02-06
|
||||
```
|
||||
<!-- end autogenerated nightly -->
|
||||
|
||||
|
|
|
@ -662,12 +662,12 @@ pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
|
|||
&& eq_ext(&l.ext, &r.ext)
|
||||
}
|
||||
|
||||
#[expect(clippy::ref_option, reason = "This is the type how it is stored in the AST")]
|
||||
pub fn eq_opt_fn_contract(l: &Option<P<FnContract>>, r: &Option<P<FnContract>>) -> bool {
|
||||
match (l, r) {
|
||||
(Some(l), Some(r)) => {
|
||||
eq_expr_opt(l.requires.as_ref(), r.requires.as_ref())
|
||||
&& eq_expr_opt(l.ensures.as_ref(), r.ensures.as_ref())
|
||||
}
|
||||
eq_expr_opt(l.requires.as_ref(), r.requires.as_ref()) && eq_expr_opt(l.ensures.as_ref(), r.ensures.as_ref())
|
||||
},
|
||||
(None, None) => true,
|
||||
(Some(_), None) | (None, Some(_)) => false,
|
||||
}
|
||||
|
|
|
@ -341,6 +341,15 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
|
|||
matches!(pat.kind, PatKind::Wild)
|
||||
}
|
||||
|
||||
// Checks if arm has the form `None => None`
|
||||
pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
|
||||
matches!(
|
||||
arm.pat.kind,
|
||||
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
|
||||
if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone)
|
||||
)
|
||||
}
|
||||
|
||||
/// Checks if the given `QPath` belongs to a type alias.
|
||||
pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
|
||||
match *qpath {
|
||||
|
|
|
@ -112,10 +112,14 @@ pub fn block_in_cycle(body: &Body<'_>, block: BasicBlock) -> bool {
|
|||
|
||||
/// Convenience wrapper around `visit_local_usage`.
|
||||
pub fn used_exactly_once(mir: &Body<'_>, local: Local) -> Option<bool> {
|
||||
visit_local_usage(&[local], mir, Location {
|
||||
block: START_BLOCK,
|
||||
statement_index: 0,
|
||||
})
|
||||
visit_local_usage(
|
||||
&[local],
|
||||
mir,
|
||||
Location {
|
||||
block: START_BLOCK,
|
||||
statement_index: 0,
|
||||
},
|
||||
)
|
||||
.map(|mut vec| {
|
||||
let LocalUsage { local_use_locs, .. } = vec.remove(0);
|
||||
let mut locations = local_use_locs
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_ast::attr::AttributeExt;
|
||||
|
||||
use rustc_attr_parsing::{RustcVersion, parse_version};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
@ -18,12 +19,14 @@ macro_rules! msrv_aliases {
|
|||
|
||||
// names may refer to stabilized feature flags or library items
|
||||
msrv_aliases! {
|
||||
1,84,0 { CONST_OPTION_AS_SLICE }
|
||||
1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
|
||||
1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP }
|
||||
1,81,0 { LINT_REASONS_STABILIZATION, ERROR_IN_CORE, EXPLICIT_SELF_TYPE_ELISION }
|
||||
1,80,0 { BOX_INTO_ITER, LAZY_CELL }
|
||||
1,77,0 { C_STR_LITERALS }
|
||||
1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT }
|
||||
1,75,0 { OPTION_AS_SLICE }
|
||||
1,74,0 { REPR_RUST }
|
||||
1,73,0 { MANUAL_DIV_CEIL }
|
||||
1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
|
||||
|
@ -40,7 +43,7 @@ msrv_aliases! {
|
|||
1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
|
||||
1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST }
|
||||
1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS }
|
||||
1,50,0 { BOOL_THEN, CLAMP }
|
||||
1,50,0 { BOOL_THEN, CLAMP, SLICE_FILL }
|
||||
1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN, SATURATING_SUB_CONST }
|
||||
1,46,0 { CONST_IF_MATCH }
|
||||
1,45,0 { STR_STRIP_PREFIX }
|
||||
|
|
|
@ -179,7 +179,10 @@ fn check_rvalue<'tcx>(
|
|||
))
|
||||
}
|
||||
},
|
||||
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks | NullOp::ContractChecks, _)
|
||||
Rvalue::NullaryOp(
|
||||
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks | NullOp::ContractChecks,
|
||||
_,
|
||||
)
|
||||
| Rvalue::ShallowInitBox(_, _) => Ok(()),
|
||||
Rvalue::UnaryOp(_, operand) => {
|
||||
let ty = operand.ty(body, tcx);
|
||||
|
|
|
@ -727,12 +727,15 @@ pub fn str_literal_to_char_literal(
|
|||
&snip[1..(snip.len() - 1)]
|
||||
};
|
||||
|
||||
let hint = format!("'{}'", match ch {
|
||||
"'" => "\\'",
|
||||
r"\" => "\\\\",
|
||||
"\\\"" => "\"", // no need to escape `"` in `'"'`
|
||||
_ => ch,
|
||||
});
|
||||
let hint = format!(
|
||||
"'{}'",
|
||||
match ch {
|
||||
"'" => "\\'",
|
||||
r"\" => "\\\\",
|
||||
"\\\"" => "\"", // no need to escape `"` in `'"'`
|
||||
_ => ch,
|
||||
}
|
||||
);
|
||||
|
||||
Some(hint)
|
||||
} else {
|
||||
|
|
|
@ -370,11 +370,9 @@ mod test {
|
|||
assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]);
|
||||
assert_eq!(camel_case_split("Abc"), vec!["Abc"]);
|
||||
assert_eq!(camel_case_split("abcDef"), vec!["abc", "Def"]);
|
||||
assert_eq!(camel_case_split("\u{f6}\u{f6}AabABcd"), vec![
|
||||
"\u{f6}\u{f6}",
|
||||
"Aab",
|
||||
"A",
|
||||
"Bcd"
|
||||
]);
|
||||
assert_eq!(
|
||||
camel_case_split("\u{f6}\u{f6}AabABcd"),
|
||||
vec!["\u{f6}\u{f6}", "Aab", "A", "Bcd"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use clap::{Parser, Subcommand, ValueEnum};
|
|||
use std::num::NonZero;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Parser, Clone, Debug)]
|
||||
#[command(args_conflicts_with_subcommands = true)]
|
||||
pub(crate) struct LintcheckConfig {
|
||||
|
@ -11,6 +12,9 @@ pub(crate) struct LintcheckConfig {
|
|||
short = 'j',
|
||||
value_name = "N",
|
||||
default_value_t = 0,
|
||||
default_value_if("perf", "true", Some("1")), // Limit jobs to 1 when benchmarking
|
||||
conflicts_with("perf"),
|
||||
required = false,
|
||||
hide_default_value = true
|
||||
)]
|
||||
pub max_jobs: usize,
|
||||
|
@ -46,6 +50,11 @@ pub(crate) struct LintcheckConfig {
|
|||
/// Run clippy on the dependencies of crates specified in crates-toml
|
||||
#[clap(long, conflicts_with("max_jobs"))]
|
||||
pub recursive: bool,
|
||||
/// Also produce a `perf.data` file, implies --jobs=1,
|
||||
/// the `perf.data` file can be found at
|
||||
/// `target/lintcheck/sources/<package>-<version>/perf.data`
|
||||
#[clap(long)]
|
||||
pub perf: bool,
|
||||
#[command(subcommand)]
|
||||
pub subcommand: Option<Commands>,
|
||||
}
|
||||
|
|
|
@ -116,7 +116,25 @@ impl Crate {
|
|||
|
||||
clippy_args.extend(lint_levels_args.iter().map(String::as_str));
|
||||
|
||||
let mut cmd = Command::new("cargo");
|
||||
let mut cmd;
|
||||
|
||||
if config.perf {
|
||||
cmd = Command::new("perf");
|
||||
cmd.args(&[
|
||||
"record",
|
||||
"-e",
|
||||
"instructions", // Only count instructions
|
||||
"-g", // Enable call-graph, useful for flamegraphs and produces richer reports
|
||||
"--quiet", // Do not tamper with lintcheck's normal output
|
||||
"-o",
|
||||
"perf.data",
|
||||
"--",
|
||||
"cargo",
|
||||
]);
|
||||
} else {
|
||||
cmd = Command::new("cargo");
|
||||
}
|
||||
|
||||
cmd.arg(if config.fix { "fix" } else { "check" })
|
||||
.arg("--quiet")
|
||||
.current_dir(&self.path)
|
||||
|
@ -234,12 +252,22 @@ fn normalize_diag(
|
|||
}
|
||||
|
||||
/// Builds clippy inside the repo to make sure we have a clippy executable we can use.
|
||||
fn build_clippy() -> String {
|
||||
let output = Command::new("cargo")
|
||||
.args(["run", "--bin=clippy-driver", "--", "--version"])
|
||||
.stderr(Stdio::inherit())
|
||||
.output()
|
||||
.unwrap();
|
||||
fn build_clippy(release_build: bool) -> String {
|
||||
let mut build_cmd = Command::new("cargo");
|
||||
build_cmd.args([
|
||||
"run",
|
||||
"--bin=clippy-driver",
|
||||
if release_build { "-r" } else { "" },
|
||||
"--",
|
||||
"--version",
|
||||
]);
|
||||
|
||||
if release_build {
|
||||
build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true");
|
||||
}
|
||||
|
||||
let output = build_cmd.stderr(Stdio::inherit()).output().unwrap();
|
||||
|
||||
if !output.status.success() {
|
||||
eprintln!("Error: Failed to compile Clippy!");
|
||||
std::process::exit(1);
|
||||
|
@ -270,13 +298,18 @@ fn main() {
|
|||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn lintcheck(config: LintcheckConfig) {
|
||||
let clippy_ver = build_clippy();
|
||||
let clippy_driver_path = fs::canonicalize(format!("target/debug/clippy-driver{EXE_SUFFIX}")).unwrap();
|
||||
let clippy_ver = build_clippy(config.perf);
|
||||
let clippy_driver_path = fs::canonicalize(format!(
|
||||
"target/{}/clippy-driver{EXE_SUFFIX}",
|
||||
if config.perf { "release" } else { "debug" }
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// assert that clippy is found
|
||||
assert!(
|
||||
clippy_driver_path.is_file(),
|
||||
"target/debug/clippy-driver binary not found! {}",
|
||||
"target/{}/clippy-driver binary not found! {}",
|
||||
if config.perf { "release" } else { "debug" },
|
||||
clippy_driver_path.display()
|
||||
);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[toolchain]
|
||||
# begin autogenerated nightly
|
||||
channel = "nightly-2025-01-28"
|
||||
channel = "nightly-2025-02-06"
|
||||
# end autogenerated nightly
|
||||
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
||||
profile = "minimal"
|
||||
|
|
32
src/tools/clippy/tests/ui/cmp_null.fixed
Normal file
32
src/tools/clippy/tests/ui/cmp_null.fixed
Normal file
|
@ -0,0 +1,32 @@
|
|||
#![warn(clippy::cmp_null)]
|
||||
#![allow(unused_mut)]
|
||||
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
let x = 0;
|
||||
let p: *const usize = &x;
|
||||
if p.is_null() {
|
||||
//~^ ERROR: comparing with null is better expressed by the `.is_null()` method
|
||||
//~| NOTE: `-D clippy::cmp-null` implied by `-D warnings`
|
||||
println!("This is surprising!");
|
||||
}
|
||||
if p.is_null() {
|
||||
//~^ ERROR: comparing with null is better expressed by the `.is_null()` method
|
||||
println!("This is surprising!");
|
||||
}
|
||||
|
||||
let mut y = 0;
|
||||
let mut m: *mut usize = &mut y;
|
||||
if m.is_null() {
|
||||
//~^ ERROR: comparing with null is better expressed by the `.is_null()` method
|
||||
println!("This is surprising, too!");
|
||||
}
|
||||
if m.is_null() {
|
||||
//~^ ERROR: comparing with null is better expressed by the `.is_null()` method
|
||||
println!("This is surprising, too!");
|
||||
}
|
||||
|
||||
let _ = (x as *const ()).is_null();
|
||||
//~^ ERROR: comparing with null is better expressed by the `.is_null()` method
|
||||
}
|
|
@ -11,10 +11,22 @@ fn main() {
|
|||
//~| NOTE: `-D clippy::cmp-null` implied by `-D warnings`
|
||||
println!("This is surprising!");
|
||||
}
|
||||
if ptr::null() == p {
|
||||
//~^ ERROR: comparing with null is better expressed by the `.is_null()` method
|
||||
println!("This is surprising!");
|
||||
}
|
||||
|
||||
let mut y = 0;
|
||||
let mut m: *mut usize = &mut y;
|
||||
if m == ptr::null_mut() {
|
||||
//~^ ERROR: comparing with null is better expressed by the `.is_null()` method
|
||||
println!("This is surprising, too!");
|
||||
}
|
||||
if ptr::null_mut() == m {
|
||||
//~^ ERROR: comparing with null is better expressed by the `.is_null()` method
|
||||
println!("This is surprising, too!");
|
||||
}
|
||||
|
||||
let _ = x as *const () == ptr::null();
|
||||
//~^ ERROR: comparing with null is better expressed by the `.is_null()` method
|
||||
}
|
||||
|
|
|
@ -2,16 +2,34 @@ error: comparing with null is better expressed by the `.is_null()` method
|
|||
--> tests/ui/cmp_null.rs:9:8
|
||||
|
|
||||
LL | if p == ptr::null() {
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^ help: try: `p.is_null()`
|
||||
|
|
||||
= note: `-D clippy::cmp-null` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::cmp_null)]`
|
||||
|
||||
error: comparing with null is better expressed by the `.is_null()` method
|
||||
--> tests/ui/cmp_null.rs:16:8
|
||||
--> tests/ui/cmp_null.rs:14:8
|
||||
|
|
||||
LL | if ptr::null() == p {
|
||||
| ^^^^^^^^^^^^^^^^ help: try: `p.is_null()`
|
||||
|
||||
error: comparing with null is better expressed by the `.is_null()` method
|
||||
--> tests/ui/cmp_null.rs:21:8
|
||||
|
|
||||
LL | if m == ptr::null_mut() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: try: `m.is_null()`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: comparing with null is better expressed by the `.is_null()` method
|
||||
--> tests/ui/cmp_null.rs:25:8
|
||||
|
|
||||
LL | if ptr::null_mut() == m {
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: try: `m.is_null()`
|
||||
|
||||
error: comparing with null is better expressed by the `.is_null()` method
|
||||
--> tests/ui/cmp_null.rs:30:13
|
||||
|
|
||||
LL | let _ = x as *const () == ptr::null();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(x as *const ()).is_null()`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
|
|
@ -116,6 +116,11 @@ fn test_redundant_closures_containing_method_calls() {
|
|||
t.iter().filter(|x| x.trait_foo_ref());
|
||||
t.iter().map(|x| x.trait_foo_ref());
|
||||
}
|
||||
|
||||
fn issue14096() {
|
||||
let x = Some("42");
|
||||
let _ = x.map(str::parse::<i16>);
|
||||
}
|
||||
}
|
||||
|
||||
struct Thunk<T>(Box<dyn FnMut() -> T>);
|
||||
|
|
|
@ -116,6 +116,11 @@ fn test_redundant_closures_containing_method_calls() {
|
|||
t.iter().filter(|x| x.trait_foo_ref());
|
||||
t.iter().map(|x| x.trait_foo_ref());
|
||||
}
|
||||
|
||||
fn issue14096() {
|
||||
let x = Some("42");
|
||||
let _ = x.map(|x| x.parse::<i16>());
|
||||
}
|
||||
}
|
||||
|
||||
struct Thunk<T>(Box<dyn FnMut() -> T>);
|
||||
|
|
|
@ -71,142 +71,148 @@ LL | let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_as
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:169:22
|
||||
--> tests/ui/eta.rs:122:23
|
||||
|
|
||||
LL | let _ = x.map(|x| x.parse::<i16>());
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `str::parse::<i16>`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:174:22
|
||||
|
|
||||
LL | requires_fn_once(|| x());
|
||||
| ^^^^^^ help: replace the closure with the function itself: `x`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:176:27
|
||||
--> tests/ui/eta.rs:181:27
|
||||
|
|
||||
LL | let a = Some(1u8).map(|a| foo_ptr(a));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:181:27
|
||||
--> tests/ui/eta.rs:186:27
|
||||
|
|
||||
LL | let a = Some(1u8).map(|a| closure(a));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:213:28
|
||||
--> tests/ui/eta.rs:218:28
|
||||
|
|
||||
LL | x.into_iter().for_each(|x| add_to_res(x));
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:214:28
|
||||
--> tests/ui/eta.rs:219:28
|
||||
|
|
||||
LL | y.into_iter().for_each(|x| add_to_res(x));
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:215:28
|
||||
--> tests/ui/eta.rs:220:28
|
||||
|
|
||||
LL | z.into_iter().for_each(|x| add_to_res(x));
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:222:21
|
||||
--> tests/ui/eta.rs:227:21
|
||||
|
|
||||
LL | Some(1).map(|n| closure(n));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:226:21
|
||||
--> tests/ui/eta.rs:231:21
|
||||
|
|
||||
LL | Some(1).map(|n| in_loop(n));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:319:18
|
||||
--> tests/ui/eta.rs:324:18
|
||||
|
|
||||
LL | takes_fn_mut(|| f());
|
||||
| ^^^^^^ help: replace the closure with the function itself: `&mut f`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:322:19
|
||||
--> tests/ui/eta.rs:327:19
|
||||
|
|
||||
LL | takes_fn_once(|| f());
|
||||
| ^^^^^^ help: replace the closure with the function itself: `&mut f`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:326:26
|
||||
--> tests/ui/eta.rs:331:26
|
||||
|
|
||||
LL | move || takes_fn_mut(|| f_used_once())
|
||||
| ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:338:19
|
||||
--> tests/ui/eta.rs:343:19
|
||||
|
|
||||
LL | array_opt.map(|a| a.as_slice());
|
||||
| ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:341:19
|
||||
--> tests/ui/eta.rs:346:19
|
||||
|
|
||||
LL | slice_opt.map(|s| s.len());
|
||||
| ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:344:17
|
||||
--> tests/ui/eta.rs:349:17
|
||||
|
|
||||
LL | ptr_opt.map(|p| p.is_null());
|
||||
| ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:348:17
|
||||
--> tests/ui/eta.rs:353:17
|
||||
|
|
||||
LL | dyn_opt.map(|d| d.method_on_dyn());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:408:19
|
||||
--> tests/ui/eta.rs:413:19
|
||||
|
|
||||
LL | let _ = f(&0, |x, y| f2(x, y));
|
||||
| ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:436:22
|
||||
--> tests/ui/eta.rs:441:22
|
||||
|
|
||||
LL | test.map(|t| t.method())
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:440:22
|
||||
--> tests/ui/eta.rs:445:22
|
||||
|
|
||||
LL | test.map(|t| t.method())
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:453:18
|
||||
--> tests/ui/eta.rs:458:18
|
||||
|
|
||||
LL | test.map(|t| t.method())
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:460:30
|
||||
--> tests/ui/eta.rs:465:30
|
||||
|
|
||||
LL | test.map(|t| t.method())
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:479:38
|
||||
--> tests/ui/eta.rs:484:38
|
||||
|
|
||||
LL | let x = Box::new(|| None.map(|x| f(x)));
|
||||
| ^^^^^^^^ help: replace the closure with the function itself: `&f`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:483:38
|
||||
--> tests/ui/eta.rs:488:38
|
||||
|
|
||||
LL | let x = Box::new(|| None.map(|x| f(x)));
|
||||
| ^^^^^^^^ help: replace the closure with the function itself: `f`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:500:35
|
||||
--> tests/ui/eta.rs:505:35
|
||||
|
|
||||
LL | let _field = bind.or_else(|| get_default()).unwrap();
|
||||
| ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default`
|
||||
|
||||
error: aborting due to 34 previous errors
|
||||
error: aborting due to 35 previous errors
|
||||
|
||||
|
|
|
@ -21,12 +21,15 @@ fn main() {
|
|||
let _ = foo().map_err(|()| todo!());
|
||||
//~^ ERROR: matching over `()` is more explicit
|
||||
|
||||
println!("{:?}", match foo() {
|
||||
Ok(()) => {},
|
||||
//~^ ERROR: matching over `()` is more explicit
|
||||
Err(()) => {},
|
||||
//~^ ERROR: matching over `()` is more explicit
|
||||
});
|
||||
println!(
|
||||
"{:?}",
|
||||
match foo() {
|
||||
Ok(()) => {},
|
||||
//~^ ERROR: matching over `()` is more explicit
|
||||
Err(()) => {},
|
||||
//~^ ERROR: matching over `()` is more explicit
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// ignored_unit_patterns in derive macro should be ok
|
||||
|
|
|
@ -21,12 +21,15 @@ fn main() {
|
|||
let _ = foo().map_err(|_| todo!());
|
||||
//~^ ERROR: matching over `()` is more explicit
|
||||
|
||||
println!("{:?}", match foo() {
|
||||
Ok(_) => {},
|
||||
//~^ ERROR: matching over `()` is more explicit
|
||||
Err(_) => {},
|
||||
//~^ ERROR: matching over `()` is more explicit
|
||||
});
|
||||
println!(
|
||||
"{:?}",
|
||||
match foo() {
|
||||
Ok(_) => {},
|
||||
//~^ ERROR: matching over `()` is more explicit
|
||||
Err(_) => {},
|
||||
//~^ ERROR: matching over `()` is more explicit
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// ignored_unit_patterns in derive macro should be ok
|
||||
|
|
|
@ -26,31 +26,31 @@ LL | let _ = foo().map_err(|_| todo!());
|
|||
| ^ help: use `()` instead of `_`: `()`
|
||||
|
||||
error: matching over `()` is more explicit
|
||||
--> tests/ui/ignored_unit_patterns.rs:25:12
|
||||
--> tests/ui/ignored_unit_patterns.rs:27:16
|
||||
|
|
||||
LL | Ok(_) => {},
|
||||
| ^ help: use `()` instead of `_`: `()`
|
||||
LL | Ok(_) => {},
|
||||
| ^ help: use `()` instead of `_`: `()`
|
||||
|
||||
error: matching over `()` is more explicit
|
||||
--> tests/ui/ignored_unit_patterns.rs:27:13
|
||||
--> tests/ui/ignored_unit_patterns.rs:29:17
|
||||
|
|
||||
LL | Err(_) => {},
|
||||
| ^ help: use `()` instead of `_`: `()`
|
||||
LL | Err(_) => {},
|
||||
| ^ help: use `()` instead of `_`: `()`
|
||||
|
||||
error: matching over `()` is more explicit
|
||||
--> tests/ui/ignored_unit_patterns.rs:38:9
|
||||
--> tests/ui/ignored_unit_patterns.rs:41:9
|
||||
|
|
||||
LL | let _ = foo().unwrap();
|
||||
| ^ help: use `()` instead of `_`: `()`
|
||||
|
||||
error: matching over `()` is more explicit
|
||||
--> tests/ui/ignored_unit_patterns.rs:47:13
|
||||
--> tests/ui/ignored_unit_patterns.rs:50:13
|
||||
|
|
||||
LL | (1, _) => unimplemented!(),
|
||||
| ^ help: use `()` instead of `_`: `()`
|
||||
|
||||
error: matching over `()` is more explicit
|
||||
--> tests/ui/ignored_unit_patterns.rs:54:13
|
||||
--> tests/ui/ignored_unit_patterns.rs:57:13
|
||||
|
|
||||
LL | for (x, _) in v {
|
||||
| ^ help: use `()` instead of `_`: `()`
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
#![warn(clippy::manual_memcpy)]
|
||||
#![allow(clippy::assigning_clones, clippy::useless_vec, clippy::needless_range_loop)]
|
||||
#![allow(
|
||||
clippy::assigning_clones,
|
||||
clippy::useless_vec,
|
||||
clippy::needless_range_loop,
|
||||
clippy::manual_slice_fill
|
||||
)]
|
||||
|
||||
//@no-rustfix
|
||||
const LOOP_OFFSET: usize = 5000;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:9:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:14:5
|
||||
|
|
||||
LL | / for i in 0..src.len() {
|
||||
LL | |
|
||||
|
@ -12,7 +12,7 @@ LL | | }
|
|||
= help: to override `-D warnings` add `#[allow(clippy::manual_memcpy)]`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:16:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:21:5
|
||||
|
|
||||
LL | / for i in 0..src.len() {
|
||||
LL | |
|
||||
|
@ -21,7 +21,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst[10..(src.len() + 10)].copy_from_slice(&src[..]);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:22:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:27:5
|
||||
|
|
||||
LL | / for i in 0..src.len() {
|
||||
LL | |
|
||||
|
@ -30,7 +30,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst[..src.len()].copy_from_slice(&src[10..(src.len() + 10)]);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:28:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:33:5
|
||||
|
|
||||
LL | / for i in 11..src.len() {
|
||||
LL | |
|
||||
|
@ -39,7 +39,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst[11..src.len()].copy_from_slice(&src[(11 - 10)..(src.len() - 10)]);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:34:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:39:5
|
||||
|
|
||||
LL | / for i in 0..dst.len() {
|
||||
LL | |
|
||||
|
@ -48,7 +48,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[..dst.len()]);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:48:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:53:5
|
||||
|
|
||||
LL | / for i in 10..256 {
|
||||
LL | |
|
||||
|
@ -64,7 +64,7 @@ LL + dst2[(10 + 500)..(256 + 500)].copy_from_slice(&src[10..256]);
|
|||
|
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:61:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:66:5
|
||||
|
|
||||
LL | / for i in 10..LOOP_OFFSET {
|
||||
LL | |
|
||||
|
@ -73,7 +73,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].copy_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)]);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:75:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:80:5
|
||||
|
|
||||
LL | / for i in 0..src_vec.len() {
|
||||
LL | |
|
||||
|
@ -82,7 +82,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst_vec[..src_vec.len()].copy_from_slice(&src_vec[..]);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:105:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:110:5
|
||||
|
|
||||
LL | / for i in from..from + src.len() {
|
||||
LL | |
|
||||
|
@ -91,7 +91,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst[from..(from + src.len())].copy_from_slice(&src[..(from + src.len() - from)]);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:110:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:115:5
|
||||
|
|
||||
LL | / for i in from..from + 3 {
|
||||
LL | |
|
||||
|
@ -100,7 +100,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst[from..(from + 3)].copy_from_slice(&src[..(from + 3 - from)]);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:116:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:121:5
|
||||
|
|
||||
LL | / for i in 0..5 {
|
||||
LL | |
|
||||
|
@ -109,7 +109,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst[..5].copy_from_slice(&src);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:122:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:127:5
|
||||
|
|
||||
LL | / for i in 0..0 {
|
||||
LL | |
|
||||
|
@ -118,7 +118,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst[..0].copy_from_slice(&src[..0]);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:146:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:151:5
|
||||
|
|
||||
LL | / for i in 0..4 {
|
||||
LL | |
|
||||
|
@ -127,7 +127,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[..4]);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:152:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:157:5
|
||||
|
|
||||
LL | / for i in 0..5 {
|
||||
LL | |
|
||||
|
@ -136,7 +136,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst[..5].copy_from_slice(&src);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:158:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:163:5
|
||||
|
|
||||
LL | / for i in 0..5 {
|
||||
LL | |
|
||||
|
@ -145,7 +145,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:205:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:210:5
|
||||
|
|
||||
LL | / for i in 0..5 {
|
||||
LL | |
|
||||
|
@ -154,7 +154,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[0]);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:211:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:216:5
|
||||
|
|
||||
LL | / for i in 0..5 {
|
||||
LL | |
|
||||
|
@ -163,7 +163,7 @@ LL | | }
|
|||
| |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[0][1]);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:219:5
|
||||
--> tests/ui/manual_memcpy/without_loop_counters.rs:224:5
|
||||
|
|
||||
LL | / for i in 0..src.len() {
|
||||
LL | |
|
||||
|
|
62
src/tools/clippy/tests/ui/manual_option_as_slice.fixed
Normal file
62
src/tools/clippy/tests/ui/manual_option_as_slice.fixed
Normal file
|
@ -0,0 +1,62 @@
|
|||
#![warn(clippy::manual_option_as_slice)]
|
||||
#![allow(clippy::redundant_closure, clippy::unwrap_or_default)]
|
||||
|
||||
fn check(x: Option<u32>) {
|
||||
_ = x.as_slice();
|
||||
|
||||
_ = x.as_slice();
|
||||
|
||||
_ = x.as_slice();
|
||||
//~^ manual_option_as_slice
|
||||
|
||||
_ = x.as_slice();
|
||||
//~^ manual_option_as_slice
|
||||
|
||||
_ = x.as_slice();
|
||||
//~^ manual_option_as_slice
|
||||
|
||||
_ = x.as_slice();
|
||||
//~^ manual_option_as_slice
|
||||
|
||||
{
|
||||
use std::slice::from_ref;
|
||||
_ = x.as_slice();
|
||||
//~^ manual_option_as_slice
|
||||
}
|
||||
|
||||
// possible false positives
|
||||
let y = x.as_ref();
|
||||
_ = match y {
|
||||
// as_ref outside
|
||||
Some(f) => &[f][..],
|
||||
None => &[][..],
|
||||
};
|
||||
_ = match x.as_ref() {
|
||||
Some(f) => std::slice::from_ref(f),
|
||||
None => &[0],
|
||||
};
|
||||
_ = match x.as_ref() {
|
||||
Some(42) => &[23],
|
||||
Some(f) => std::slice::from_ref(f),
|
||||
None => &[],
|
||||
};
|
||||
let b = &[42];
|
||||
_ = if let Some(_f) = x.as_ref() {
|
||||
std::slice::from_ref(b)
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
_ = x.as_ref().map_or(&[42][..], std::slice::from_ref);
|
||||
_ = x.as_ref().map_or_else(|| &[42][..1], std::slice::from_ref);
|
||||
_ = x.as_ref().map(|f| std::slice::from_ref(f)).unwrap_or_default();
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.74"]
|
||||
fn check_msrv(x: Option<u32>) {
|
||||
_ = x.as_ref().map_or(&[][..], std::slice::from_ref);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
check(Some(1));
|
||||
check_msrv(Some(175));
|
||||
}
|
71
src/tools/clippy/tests/ui/manual_option_as_slice.rs
Normal file
71
src/tools/clippy/tests/ui/manual_option_as_slice.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
#![warn(clippy::manual_option_as_slice)]
|
||||
#![allow(clippy::redundant_closure, clippy::unwrap_or_default)]
|
||||
|
||||
fn check(x: Option<u32>) {
|
||||
_ = match x.as_ref() {
|
||||
//~^ manual_option_as_slice
|
||||
Some(f) => std::slice::from_ref(f),
|
||||
None => &[],
|
||||
};
|
||||
|
||||
_ = if let Some(f) = x.as_ref() {
|
||||
//~^ manual_option_as_slice
|
||||
std::slice::from_ref(f)
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
|
||||
_ = x.as_ref().map_or(&[][..], std::slice::from_ref);
|
||||
//~^ manual_option_as_slice
|
||||
|
||||
_ = x.as_ref().map_or_else(Default::default, std::slice::from_ref);
|
||||
//~^ manual_option_as_slice
|
||||
|
||||
_ = x.as_ref().map(std::slice::from_ref).unwrap_or_default();
|
||||
//~^ manual_option_as_slice
|
||||
|
||||
_ = x.as_ref().map_or_else(|| &[42][..0], std::slice::from_ref);
|
||||
//~^ manual_option_as_slice
|
||||
|
||||
{
|
||||
use std::slice::from_ref;
|
||||
_ = x.as_ref().map_or_else(<&[_]>::default, from_ref);
|
||||
//~^ manual_option_as_slice
|
||||
}
|
||||
|
||||
// possible false positives
|
||||
let y = x.as_ref();
|
||||
_ = match y {
|
||||
// as_ref outside
|
||||
Some(f) => &[f][..],
|
||||
None => &[][..],
|
||||
};
|
||||
_ = match x.as_ref() {
|
||||
Some(f) => std::slice::from_ref(f),
|
||||
None => &[0],
|
||||
};
|
||||
_ = match x.as_ref() {
|
||||
Some(42) => &[23],
|
||||
Some(f) => std::slice::from_ref(f),
|
||||
None => &[],
|
||||
};
|
||||
let b = &[42];
|
||||
_ = if let Some(_f) = x.as_ref() {
|
||||
std::slice::from_ref(b)
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
_ = x.as_ref().map_or(&[42][..], std::slice::from_ref);
|
||||
_ = x.as_ref().map_or_else(|| &[42][..1], std::slice::from_ref);
|
||||
_ = x.as_ref().map(|f| std::slice::from_ref(f)).unwrap_or_default();
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.74"]
|
||||
fn check_msrv(x: Option<u32>) {
|
||||
_ = x.as_ref().map_or(&[][..], std::slice::from_ref);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
check(Some(1));
|
||||
check_msrv(Some(175));
|
||||
}
|
58
src/tools/clippy/tests/ui/manual_option_as_slice.stderr
Normal file
58
src/tools/clippy/tests/ui/manual_option_as_slice.stderr
Normal file
|
@ -0,0 +1,58 @@
|
|||
error: use `Option::as_slice`
|
||||
--> tests/ui/manual_option_as_slice.rs:5:9
|
||||
|
|
||||
LL | _ = match x.as_ref() {
|
||||
| _________^
|
||||
LL | |
|
||||
LL | | Some(f) => std::slice::from_ref(f),
|
||||
LL | | None => &[],
|
||||
LL | | };
|
||||
| |_____^ help: use: `x.as_slice()`
|
||||
|
|
||||
= note: `-D clippy::manual-option-as-slice` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::manual_option_as_slice)]`
|
||||
|
||||
error: use `Option::as_slice`
|
||||
--> tests/ui/manual_option_as_slice.rs:11:9
|
||||
|
|
||||
LL | _ = if let Some(f) = x.as_ref() {
|
||||
| _________^
|
||||
LL | |
|
||||
LL | | std::slice::from_ref(f)
|
||||
LL | | } else {
|
||||
LL | | &[]
|
||||
LL | | };
|
||||
| |_____^ help: use: `x.as_slice()`
|
||||
|
||||
error: use `Option::as_slice`
|
||||
--> tests/ui/manual_option_as_slice.rs:18:9
|
||||
|
|
||||
LL | _ = x.as_ref().map_or(&[][..], std::slice::from_ref);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()`
|
||||
|
||||
error: use `Option::as_slice`
|
||||
--> tests/ui/manual_option_as_slice.rs:21:9
|
||||
|
|
||||
LL | _ = x.as_ref().map_or_else(Default::default, std::slice::from_ref);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()`
|
||||
|
||||
error: use `Option::as_slice`
|
||||
--> tests/ui/manual_option_as_slice.rs:24:9
|
||||
|
|
||||
LL | _ = x.as_ref().map(std::slice::from_ref).unwrap_or_default();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()`
|
||||
|
||||
error: use `Option::as_slice`
|
||||
--> tests/ui/manual_option_as_slice.rs:27:9
|
||||
|
|
||||
LL | _ = x.as_ref().map_or_else(|| &[42][..0], std::slice::from_ref);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()`
|
||||
|
||||
error: use `Option::as_slice`
|
||||
--> tests/ui/manual_option_as_slice.rs:32:13
|
||||
|
|
||||
LL | _ = x.as_ref().map_or_else(<&[_]>::default, from_ref);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
101
src/tools/clippy/tests/ui/manual_slice_fill.fixed
Normal file
101
src/tools/clippy/tests/ui/manual_slice_fill.fixed
Normal file
|
@ -0,0 +1,101 @@
|
|||
#![warn(clippy::manual_slice_fill)]
|
||||
#![allow(clippy::needless_range_loop)]
|
||||
|
||||
macro_rules! assign_element {
|
||||
($slice:ident, $index:expr) => {
|
||||
$slice[$index] = 0;
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! assign_element_2 {
|
||||
($i:expr) => {
|
||||
$i = 0;
|
||||
};
|
||||
}
|
||||
|
||||
struct NoClone;
|
||||
|
||||
fn num() -> usize {
|
||||
5
|
||||
}
|
||||
|
||||
fn should_lint() {
|
||||
let mut some_slice = [1, 2, 3, 4, 5];
|
||||
|
||||
some_slice.fill(0);
|
||||
|
||||
let x = 5;
|
||||
some_slice.fill(x);
|
||||
|
||||
some_slice.fill(0);
|
||||
|
||||
// This should trigger `manual_slice_fill`, but the applicability is `MaybeIncorrect` since comments
|
||||
// within the loop might be purely informational.
|
||||
some_slice.fill(0);
|
||||
}
|
||||
|
||||
fn should_not_lint() {
|
||||
let mut some_slice = [1, 2, 3, 4, 5];
|
||||
|
||||
// Should not lint because we can't determine if the scope of the loop is intended to access all the
|
||||
// elements of the slice.
|
||||
for i in 0..5 {
|
||||
some_slice[i] = 0;
|
||||
}
|
||||
|
||||
// Should not lint, as using a function to assign values to elements might be
|
||||
// intentional. For example, the contents of `num()` could be temporary and subject to change
|
||||
// later.
|
||||
for i in 0..some_slice.len() {
|
||||
some_slice[i] = num();
|
||||
}
|
||||
|
||||
// Should not lint because this loop isn't equivalent to `fill`.
|
||||
for i in 0..some_slice.len() {
|
||||
some_slice[i] = 0;
|
||||
println!("foo");
|
||||
}
|
||||
|
||||
// Should not lint because it may be intentional to use a macro to perform an operation equivalent
|
||||
// to `fill`.
|
||||
for i in 0..some_slice.len() {
|
||||
assign_element!(some_slice, i);
|
||||
}
|
||||
|
||||
let another_slice = [1, 2, 3];
|
||||
// Should not lint because the range is not for `some_slice`.
|
||||
for i in 0..another_slice.len() {
|
||||
some_slice[i] = 0;
|
||||
}
|
||||
|
||||
let mut vec: Vec<Option<NoClone>> = Vec::with_capacity(5);
|
||||
// Should not lint because `NoClone` does not have `Clone` trait.
|
||||
for i in 0..vec.len() {
|
||||
vec[i] = None;
|
||||
}
|
||||
|
||||
// Should not lint, as using a function to assign values to elements might be
|
||||
// intentional. For example, the contents of `num()` could be temporary and subject to change
|
||||
// later.
|
||||
for i in &mut some_slice {
|
||||
*i = num();
|
||||
}
|
||||
|
||||
// Should not lint because this loop isn't equivalent to `fill`.
|
||||
for i in &mut some_slice {
|
||||
*i = 0;
|
||||
println!("foo");
|
||||
}
|
||||
|
||||
// Should not lint because it may be intentional to use a macro to perform an operation equivalent
|
||||
// to `fill`.
|
||||
for i in &mut some_slice {
|
||||
assign_element_2!(*i);
|
||||
}
|
||||
|
||||
let mut vec: Vec<Option<NoClone>> = Vec::with_capacity(5);
|
||||
// Should not lint because `NoClone` does not have `Clone` trait.
|
||||
for i in &mut vec {
|
||||
*i = None;
|
||||
}
|
||||
}
|
110
src/tools/clippy/tests/ui/manual_slice_fill.rs
Normal file
110
src/tools/clippy/tests/ui/manual_slice_fill.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
#![warn(clippy::manual_slice_fill)]
|
||||
#![allow(clippy::needless_range_loop)]
|
||||
|
||||
macro_rules! assign_element {
|
||||
($slice:ident, $index:expr) => {
|
||||
$slice[$index] = 0;
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! assign_element_2 {
|
||||
($i:expr) => {
|
||||
$i = 0;
|
||||
};
|
||||
}
|
||||
|
||||
struct NoClone;
|
||||
|
||||
fn num() -> usize {
|
||||
5
|
||||
}
|
||||
|
||||
fn should_lint() {
|
||||
let mut some_slice = [1, 2, 3, 4, 5];
|
||||
|
||||
for i in 0..some_slice.len() {
|
||||
some_slice[i] = 0;
|
||||
}
|
||||
|
||||
let x = 5;
|
||||
for i in 0..some_slice.len() {
|
||||
some_slice[i] = x;
|
||||
}
|
||||
|
||||
for i in &mut some_slice {
|
||||
*i = 0;
|
||||
}
|
||||
|
||||
// This should trigger `manual_slice_fill`, but the applicability is `MaybeIncorrect` since comments
|
||||
// within the loop might be purely informational.
|
||||
for i in 0..some_slice.len() {
|
||||
some_slice[i] = 0;
|
||||
// foo
|
||||
}
|
||||
}
|
||||
|
||||
fn should_not_lint() {
|
||||
let mut some_slice = [1, 2, 3, 4, 5];
|
||||
|
||||
// Should not lint because we can't determine if the scope of the loop is intended to access all the
|
||||
// elements of the slice.
|
||||
for i in 0..5 {
|
||||
some_slice[i] = 0;
|
||||
}
|
||||
|
||||
// Should not lint, as using a function to assign values to elements might be
|
||||
// intentional. For example, the contents of `num()` could be temporary and subject to change
|
||||
// later.
|
||||
for i in 0..some_slice.len() {
|
||||
some_slice[i] = num();
|
||||
}
|
||||
|
||||
// Should not lint because this loop isn't equivalent to `fill`.
|
||||
for i in 0..some_slice.len() {
|
||||
some_slice[i] = 0;
|
||||
println!("foo");
|
||||
}
|
||||
|
||||
// Should not lint because it may be intentional to use a macro to perform an operation equivalent
|
||||
// to `fill`.
|
||||
for i in 0..some_slice.len() {
|
||||
assign_element!(some_slice, i);
|
||||
}
|
||||
|
||||
let another_slice = [1, 2, 3];
|
||||
// Should not lint because the range is not for `some_slice`.
|
||||
for i in 0..another_slice.len() {
|
||||
some_slice[i] = 0;
|
||||
}
|
||||
|
||||
let mut vec: Vec<Option<NoClone>> = Vec::with_capacity(5);
|
||||
// Should not lint because `NoClone` does not have `Clone` trait.
|
||||
for i in 0..vec.len() {
|
||||
vec[i] = None;
|
||||
}
|
||||
|
||||
// Should not lint, as using a function to assign values to elements might be
|
||||
// intentional. For example, the contents of `num()` could be temporary and subject to change
|
||||
// later.
|
||||
for i in &mut some_slice {
|
||||
*i = num();
|
||||
}
|
||||
|
||||
// Should not lint because this loop isn't equivalent to `fill`.
|
||||
for i in &mut some_slice {
|
||||
*i = 0;
|
||||
println!("foo");
|
||||
}
|
||||
|
||||
// Should not lint because it may be intentional to use a macro to perform an operation equivalent
|
||||
// to `fill`.
|
||||
for i in &mut some_slice {
|
||||
assign_element_2!(*i);
|
||||
}
|
||||
|
||||
let mut vec: Vec<Option<NoClone>> = Vec::with_capacity(5);
|
||||
// Should not lint because `NoClone` does not have `Clone` trait.
|
||||
for i in &mut vec {
|
||||
*i = None;
|
||||
}
|
||||
}
|
38
src/tools/clippy/tests/ui/manual_slice_fill.stderr
Normal file
38
src/tools/clippy/tests/ui/manual_slice_fill.stderr
Normal file
|
@ -0,0 +1,38 @@
|
|||
error: manually filling a slice
|
||||
--> tests/ui/manual_slice_fill.rs:25:5
|
||||
|
|
||||
LL | / for i in 0..some_slice.len() {
|
||||
LL | | some_slice[i] = 0;
|
||||
LL | | }
|
||||
| |_____^ help: try: `some_slice.fill(0);`
|
||||
|
|
||||
= note: `-D clippy::manual-slice-fill` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::manual_slice_fill)]`
|
||||
|
||||
error: manually filling a slice
|
||||
--> tests/ui/manual_slice_fill.rs:30:5
|
||||
|
|
||||
LL | / for i in 0..some_slice.len() {
|
||||
LL | | some_slice[i] = x;
|
||||
LL | | }
|
||||
| |_____^ help: try: `some_slice.fill(x);`
|
||||
|
||||
error: manually filling a slice
|
||||
--> tests/ui/manual_slice_fill.rs:34:5
|
||||
|
|
||||
LL | / for i in &mut some_slice {
|
||||
LL | | *i = 0;
|
||||
LL | | }
|
||||
| |_____^ help: try: `some_slice.fill(0);`
|
||||
|
||||
error: manually filling a slice
|
||||
--> tests/ui/manual_slice_fill.rs:40:5
|
||||
|
|
||||
LL | / for i in 0..some_slice.len() {
|
||||
LL | | some_slice[i] = 0;
|
||||
LL | | // foo
|
||||
LL | | }
|
||||
| |_____^ help: try: `some_slice.fill(0);`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
//@no-rustfix
|
||||
fn issue_12670() {
|
||||
// no auto: type not found
|
||||
#[allow(clippy::match_result_ok)]
|
||||
let _ = if let Some(x) = "1".parse().ok() {
|
||||
x
|
||||
} else {
|
||||
i32::default()
|
||||
};
|
||||
let _ = if let Some(x) = None { x } else { i32::default() };
|
||||
// auto fix with unwrap_or_default
|
||||
let a: Option<i32> = None;
|
||||
let _ = if let Some(x) = a { x } else { i32::default() };
|
||||
let _ = if let Some(x) = Some(99) { x } else { i32::default() };
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
error: if let can be simplified with `.unwrap_or_default()`
|
||||
--> tests/ui/manual_unwrap_or_default_unfixable.rs:5:13
|
||||
|
|
||||
LL | let _ = if let Some(x) = "1".parse().ok() {
|
||||
| _____________^
|
||||
LL | | x
|
||||
LL | | } else {
|
||||
LL | | i32::default()
|
||||
LL | | };
|
||||
| |_____^ help: ascribe the type i32 and replace your expression with: `"1".parse().ok().unwrap_or_default()`
|
||||
|
|
||||
= note: `-D clippy::manual-unwrap-or-default` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::manual_unwrap_or_default)]`
|
||||
|
||||
error: if let can be simplified with `.unwrap_or_default()`
|
||||
--> tests/ui/manual_unwrap_or_default_unfixable.rs:10:13
|
||||
|
|
||||
LL | let _ = if let Some(x) = None { x } else { i32::default() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `None::<i32>.unwrap_or_default()`
|
||||
|
||||
error: if let can be simplified with `.unwrap_or_default()`
|
||||
--> tests/ui/manual_unwrap_or_default_unfixable.rs:13:13
|
||||
|
|
||||
LL | let _ = if let Some(x) = a { x } else { i32::default() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.unwrap_or_default()`
|
||||
|
||||
error: if let can be simplified with `.unwrap_or_default()`
|
||||
--> tests/ui/manual_unwrap_or_default_unfixable.rs:14:13
|
||||
|
|
||||
LL | let _ = if let Some(x) = Some(99) { x } else { i32::default() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `Some(99).unwrap_or_default()`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
58
src/tools/clippy/tests/ui/needless_option_take.fixed
Normal file
58
src/tools/clippy/tests/ui/needless_option_take.fixed
Normal file
|
@ -0,0 +1,58 @@
|
|||
struct MyStruct;
|
||||
|
||||
impl MyStruct {
|
||||
pub fn get_option() -> Option<Self> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn return_option() -> Option<i32> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Testing non erroneous option_take_on_temporary");
|
||||
let mut option = Some(1);
|
||||
let _ = Box::new(move || option.take().unwrap());
|
||||
|
||||
println!("Testing non erroneous option_take_on_temporary");
|
||||
let x = Some(3);
|
||||
x.as_ref();
|
||||
|
||||
let x = Some(3);
|
||||
x.as_ref();
|
||||
//~^ ERROR: called `Option::take()` on a temporary value
|
||||
|
||||
println!("Testing non erroneous option_take_on_temporary");
|
||||
let mut x = Some(3);
|
||||
let y = x.as_mut();
|
||||
|
||||
let mut x = Some(3);
|
||||
let y = x.as_mut();
|
||||
//~^ ERROR: called `Option::take()` on a temporary value
|
||||
let y = x.replace(289);
|
||||
//~^ ERROR: called `Option::take()` on a temporary value
|
||||
|
||||
let y = Some(3).as_mut();
|
||||
//~^ ERROR: called `Option::take()` on a temporary value
|
||||
|
||||
let y = Option::as_mut(&mut x);
|
||||
//~^ ERROR: called `Option::take()` on a temporary value
|
||||
|
||||
let x = return_option();
|
||||
let x = return_option();
|
||||
//~^ ERROR: called `Option::take()` on a temporary value
|
||||
|
||||
let x = MyStruct::get_option();
|
||||
let x = MyStruct::get_option();
|
||||
//~^ ERROR: called `Option::take()` on a temporary value
|
||||
|
||||
let mut my_vec = vec![1, 2, 3];
|
||||
my_vec.push(4);
|
||||
let y = my_vec.first();
|
||||
let y = my_vec.first();
|
||||
//~^ ERROR: called `Option::take()` on a temporary value
|
||||
|
||||
let y = my_vec.first();
|
||||
//~^ ERROR: called `Option::take()` on a temporary value
|
||||
}
|
|
@ -2,7 +2,9 @@ error: called `Option::take()` on a temporary value
|
|||
--> tests/ui/needless_option_take.rs:23:5
|
||||
|
|
||||
LL | x.as_ref().take();
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^-------
|
||||
| |
|
||||
| help: remove
|
||||
|
|
||||
= note: `as_ref` creates a temporary value, so calling take() has no effect
|
||||
= note: `-D clippy::needless-option-take` implied by `-D warnings`
|
||||
|
@ -12,7 +14,9 @@ error: called `Option::take()` on a temporary value
|
|||
--> tests/ui/needless_option_take.rs:31:13
|
||||
|
|
||||
LL | let y = x.as_mut().take();
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^-------
|
||||
| |
|
||||
| help: remove
|
||||
|
|
||||
= note: `as_mut` creates a temporary value, so calling take() has no effect
|
||||
|
||||
|
@ -20,7 +24,9 @@ error: called `Option::take()` on a temporary value
|
|||
--> tests/ui/needless_option_take.rs:33:13
|
||||
|
|
||||
LL | let y = x.replace(289).take();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^-------
|
||||
| |
|
||||
| help: remove
|
||||
|
|
||||
= note: `replace` creates a temporary value, so calling take() has no effect
|
||||
|
||||
|
@ -28,7 +34,9 @@ error: called `Option::take()` on a temporary value
|
|||
--> tests/ui/needless_option_take.rs:36:13
|
||||
|
|
||||
LL | let y = Some(3).as_mut().take();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^-------
|
||||
| |
|
||||
| help: remove
|
||||
|
|
||||
= note: `as_mut` creates a temporary value, so calling take() has no effect
|
||||
|
||||
|
@ -36,7 +44,9 @@ error: called `Option::take()` on a temporary value
|
|||
--> tests/ui/needless_option_take.rs:39:13
|
||||
|
|
||||
LL | let y = Option::as_mut(&mut x).take();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^-------
|
||||
| |
|
||||
| help: remove
|
||||
|
|
||||
= note: `as_mut` creates a temporary value, so calling take() has no effect
|
||||
|
||||
|
@ -44,7 +54,9 @@ error: called `Option::take()` on a temporary value
|
|||
--> tests/ui/needless_option_take.rs:43:13
|
||||
|
|
||||
LL | let x = return_option().take();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^-------
|
||||
| |
|
||||
| help: remove
|
||||
|
|
||||
= note: `return_option` creates a temporary value, so calling take() has no effect
|
||||
|
||||
|
@ -52,7 +64,9 @@ error: called `Option::take()` on a temporary value
|
|||
--> tests/ui/needless_option_take.rs:47:13
|
||||
|
|
||||
LL | let x = MyStruct::get_option().take();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^-------
|
||||
| |
|
||||
| help: remove
|
||||
|
|
||||
= note: `get_option` creates a temporary value, so calling take() has no effect
|
||||
|
||||
|
@ -60,7 +74,9 @@ error: called `Option::take()` on a temporary value
|
|||
--> tests/ui/needless_option_take.rs:53:13
|
||||
|
|
||||
LL | let y = my_vec.first().take();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^-------
|
||||
| |
|
||||
| help: remove
|
||||
|
|
||||
= note: `first` creates a temporary value, so calling take() has no effect
|
||||
|
||||
|
@ -68,7 +84,9 @@ error: called `Option::take()` on a temporary value
|
|||
--> tests/ui/needless_option_take.rs:56:13
|
||||
|
|
||||
LL | let y = my_vec.first().take();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^-------
|
||||
| |
|
||||
| help: remove
|
||||
|
|
||||
= note: `first` creates a temporary value, so calling take() has no effect
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
#![allow(
|
||||
clippy::uninlined_format_args,
|
||||
clippy::unnecessary_literal_unwrap,
|
||||
clippy::useless_vec
|
||||
clippy::useless_vec,
|
||||
clippy::manual_slice_fill
|
||||
)]
|
||||
//@no-rustfix
|
||||
static STATIC: [usize; 4] = [0, 1, 8, 16];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: the loop variable `i` is only used to index `vec`
|
||||
--> tests/ui/needless_range_loop.rs:15:14
|
||||
--> tests/ui/needless_range_loop.rs:16:14
|
||||
|
|
||||
LL | for i in 0..vec.len() {
|
||||
| ^^^^^^^^^^^^
|
||||
|
@ -12,7 +12,7 @@ LL | for <item> in &vec {
|
|||
| ~~~~~~ ~~~~
|
||||
|
||||
error: the loop variable `i` is only used to index `vec`
|
||||
--> tests/ui/needless_range_loop.rs:26:14
|
||||
--> tests/ui/needless_range_loop.rs:27:14
|
||||
|
|
||||
LL | for i in 0..vec.len() {
|
||||
| ^^^^^^^^^^^^
|
||||
|
@ -23,7 +23,7 @@ LL | for <item> in &vec {
|
|||
| ~~~~~~ ~~~~
|
||||
|
||||
error: the loop variable `j` is only used to index `STATIC`
|
||||
--> tests/ui/needless_range_loop.rs:32:14
|
||||
--> tests/ui/needless_range_loop.rs:33:14
|
||||
|
|
||||
LL | for j in 0..4 {
|
||||
| ^^^^
|
||||
|
@ -34,7 +34,7 @@ LL | for <item> in &STATIC {
|
|||
| ~~~~~~ ~~~~~~~
|
||||
|
||||
error: the loop variable `j` is only used to index `CONST`
|
||||
--> tests/ui/needless_range_loop.rs:37:14
|
||||
--> tests/ui/needless_range_loop.rs:38:14
|
||||
|
|
||||
LL | for j in 0..4 {
|
||||
| ^^^^
|
||||
|
@ -45,7 +45,7 @@ LL | for <item> in &CONST {
|
|||
| ~~~~~~ ~~~~~~
|
||||
|
||||
error: the loop variable `i` is used to index `vec`
|
||||
--> tests/ui/needless_range_loop.rs:42:14
|
||||
--> tests/ui/needless_range_loop.rs:43:14
|
||||
|
|
||||
LL | for i in 0..vec.len() {
|
||||
| ^^^^^^^^^^^^
|
||||
|
@ -56,7 +56,7 @@ LL | for (i, <item>) in vec.iter().enumerate() {
|
|||
| ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: the loop variable `i` is only used to index `vec2`
|
||||
--> tests/ui/needless_range_loop.rs:51:14
|
||||
--> tests/ui/needless_range_loop.rs:52:14
|
||||
|
|
||||
LL | for i in 0..vec.len() {
|
||||
| ^^^^^^^^^^^^
|
||||
|
@ -67,7 +67,7 @@ LL | for <item> in vec2.iter().take(vec.len()) {
|
|||
| ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: the loop variable `i` is only used to index `vec`
|
||||
--> tests/ui/needless_range_loop.rs:56:14
|
||||
--> tests/ui/needless_range_loop.rs:57:14
|
||||
|
|
||||
LL | for i in 5..vec.len() {
|
||||
| ^^^^^^^^^^^^
|
||||
|
@ -78,7 +78,7 @@ LL | for <item> in vec.iter().skip(5) {
|
|||
| ~~~~~~ ~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: the loop variable `i` is only used to index `vec`
|
||||
--> tests/ui/needless_range_loop.rs:61:14
|
||||
--> tests/ui/needless_range_loop.rs:62:14
|
||||
|
|
||||
LL | for i in 0..MAX_LEN {
|
||||
| ^^^^^^^^^^
|
||||
|
@ -89,7 +89,7 @@ LL | for <item> in vec.iter().take(MAX_LEN) {
|
|||
| ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: the loop variable `i` is only used to index `vec`
|
||||
--> tests/ui/needless_range_loop.rs:66:14
|
||||
--> tests/ui/needless_range_loop.rs:67:14
|
||||
|
|
||||
LL | for i in 0..=MAX_LEN {
|
||||
| ^^^^^^^^^^^
|
||||
|
@ -100,7 +100,7 @@ LL | for <item> in vec.iter().take(MAX_LEN + 1) {
|
|||
| ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: the loop variable `i` is only used to index `vec`
|
||||
--> tests/ui/needless_range_loop.rs:71:14
|
||||
--> tests/ui/needless_range_loop.rs:72:14
|
||||
|
|
||||
LL | for i in 5..10 {
|
||||
| ^^^^^
|
||||
|
@ -111,7 +111,7 @@ LL | for <item> in vec.iter().take(10).skip(5) {
|
|||
| ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: the loop variable `i` is only used to index `vec`
|
||||
--> tests/ui/needless_range_loop.rs:76:14
|
||||
--> tests/ui/needless_range_loop.rs:77:14
|
||||
|
|
||||
LL | for i in 5..=10 {
|
||||
| ^^^^^^
|
||||
|
@ -122,7 +122,7 @@ LL | for <item> in vec.iter().take(10 + 1).skip(5) {
|
|||
| ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: the loop variable `i` is used to index `vec`
|
||||
--> tests/ui/needless_range_loop.rs:81:14
|
||||
--> tests/ui/needless_range_loop.rs:82:14
|
||||
|
|
||||
LL | for i in 5..vec.len() {
|
||||
| ^^^^^^^^^^^^
|
||||
|
@ -133,7 +133,7 @@ LL | for (i, <item>) in vec.iter().enumerate().skip(5) {
|
|||
| ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: the loop variable `i` is used to index `vec`
|
||||
--> tests/ui/needless_range_loop.rs:86:14
|
||||
--> tests/ui/needless_range_loop.rs:87:14
|
||||
|
|
||||
LL | for i in 5..10 {
|
||||
| ^^^^^
|
||||
|
@ -144,7 +144,7 @@ LL | for (i, <item>) in vec.iter().enumerate().take(10).skip(5) {
|
|||
| ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: the loop variable `i` is used to index `vec`
|
||||
--> tests/ui/needless_range_loop.rs:92:14
|
||||
--> tests/ui/needless_range_loop.rs:93:14
|
||||
|
|
||||
LL | for i in 0..vec.len() {
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
|
@ -20,10 +20,10 @@ fn main() {
|
|||
1 ^ (1 - 1);
|
||||
3 | (2 - 1);
|
||||
3 & (5 - 2);
|
||||
0x0F00 & (0x00F0 << 4);
|
||||
0x0F00 & (0xF000 >> 4);
|
||||
(0x0F00 << 1) ^ 3;
|
||||
(0x0F00 << 1) | 2;
|
||||
0x0F00 & 0x00F0 << 4;
|
||||
0x0F00 & 0xF000 >> 4;
|
||||
0x0F00 << 1 ^ 3;
|
||||
0x0F00 << 1 | 2;
|
||||
|
||||
let b = 3;
|
||||
trip!(b * 8);
|
||||
|
|
|
@ -43,29 +43,5 @@ error: operator precedence might not be obvious
|
|||
LL | 3 & 5 - 2;
|
||||
| ^^^^^^^^^ help: consider parenthesizing your expression: `3 & (5 - 2)`
|
||||
|
||||
error: operator precedence might not be obvious
|
||||
--> tests/ui/precedence.rs:23:5
|
||||
|
|
||||
LL | 0x0F00 & 0x00F0 << 4;
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `0x0F00 & (0x00F0 << 4)`
|
||||
|
||||
error: operator precedence might not be obvious
|
||||
--> tests/ui/precedence.rs:24:5
|
||||
|
|
||||
LL | 0x0F00 & 0xF000 >> 4;
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `0x0F00 & (0xF000 >> 4)`
|
||||
|
||||
error: operator precedence might not be obvious
|
||||
--> tests/ui/precedence.rs:25:5
|
||||
|
|
||||
LL | 0x0F00 << 1 ^ 3;
|
||||
| ^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(0x0F00 << 1) ^ 3`
|
||||
|
||||
error: operator precedence might not be obvious
|
||||
--> tests/ui/precedence.rs:26:5
|
||||
|
|
||||
LL | 0x0F00 << 1 | 2;
|
||||
| ^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(0x0F00 << 1) | 2`
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
|
35
src/tools/clippy/tests/ui/precedence_bits.fixed
Normal file
35
src/tools/clippy/tests/ui/precedence_bits.fixed
Normal file
|
@ -0,0 +1,35 @@
|
|||
#![warn(clippy::precedence_bits)]
|
||||
#![allow(
|
||||
unused_must_use,
|
||||
clippy::no_effect,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::precedence
|
||||
)]
|
||||
#![allow(clippy::identity_op)]
|
||||
#![allow(clippy::eq_op)]
|
||||
|
||||
macro_rules! trip {
|
||||
($a:expr) => {
|
||||
match $a & 0b1111_1111u8 {
|
||||
0 => println!("a is zero ({})", $a),
|
||||
_ => println!("a is {}", $a),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
1 << 2 + 3;
|
||||
1 + 2 << 3;
|
||||
4 >> 1 + 1;
|
||||
1 + 3 >> 2;
|
||||
1 ^ 1 - 1;
|
||||
3 | 2 - 1;
|
||||
3 & 5 - 2;
|
||||
0x0F00 & (0x00F0 << 4);
|
||||
0x0F00 & (0xF000 >> 4);
|
||||
(0x0F00 << 1) ^ 3;
|
||||
(0x0F00 << 1) | 2;
|
||||
|
||||
let b = 3;
|
||||
trip!(b * 8);
|
||||
}
|
35
src/tools/clippy/tests/ui/precedence_bits.rs
Normal file
35
src/tools/clippy/tests/ui/precedence_bits.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
#![warn(clippy::precedence_bits)]
|
||||
#![allow(
|
||||
unused_must_use,
|
||||
clippy::no_effect,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::precedence
|
||||
)]
|
||||
#![allow(clippy::identity_op)]
|
||||
#![allow(clippy::eq_op)]
|
||||
|
||||
macro_rules! trip {
|
||||
($a:expr) => {
|
||||
match $a & 0b1111_1111u8 {
|
||||
0 => println!("a is zero ({})", $a),
|
||||
_ => println!("a is {}", $a),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
1 << 2 + 3;
|
||||
1 + 2 << 3;
|
||||
4 >> 1 + 1;
|
||||
1 + 3 >> 2;
|
||||
1 ^ 1 - 1;
|
||||
3 | 2 - 1;
|
||||
3 & 5 - 2;
|
||||
0x0F00 & 0x00F0 << 4;
|
||||
0x0F00 & 0xF000 >> 4;
|
||||
0x0F00 << 1 ^ 3;
|
||||
0x0F00 << 1 | 2;
|
||||
|
||||
let b = 3;
|
||||
trip!(b * 8);
|
||||
}
|
29
src/tools/clippy/tests/ui/precedence_bits.stderr
Normal file
29
src/tools/clippy/tests/ui/precedence_bits.stderr
Normal file
|
@ -0,0 +1,29 @@
|
|||
error: operator precedence might not be obvious
|
||||
--> tests/ui/precedence_bits.rs:28:5
|
||||
|
|
||||
LL | 0x0F00 & 0x00F0 << 4;
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `0x0F00 & (0x00F0 << 4)`
|
||||
|
|
||||
= note: `-D clippy::precedence-bits` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::precedence_bits)]`
|
||||
|
||||
error: operator precedence might not be obvious
|
||||
--> tests/ui/precedence_bits.rs:29:5
|
||||
|
|
||||
LL | 0x0F00 & 0xF000 >> 4;
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `0x0F00 & (0xF000 >> 4)`
|
||||
|
||||
error: operator precedence might not be obvious
|
||||
--> tests/ui/precedence_bits.rs:30:5
|
||||
|
|
||||
LL | 0x0F00 << 1 ^ 3;
|
||||
| ^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(0x0F00 << 1) ^ 3`
|
||||
|
||||
error: operator precedence might not be obvious
|
||||
--> tests/ui/precedence_bits.rs:31:5
|
||||
|
|
||||
LL | 0x0F00 << 1 | 2;
|
||||
| ^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(0x0F00 << 1) | 2`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
|
@ -66,3 +66,17 @@ fn main() {
|
|||
|
||||
println!("mixed: {{hello}} {world}");
|
||||
}
|
||||
|
||||
fn issue_13959() {
|
||||
println!("\"");
|
||||
println!(
|
||||
"
|
||||
foo
|
||||
\\
|
||||
\\\\
|
||||
\"
|
||||
\\\"
|
||||
bar
|
||||
"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -66,3 +66,18 @@ fn main() {
|
|||
|
||||
println!("mixed: {} {world}", "{hello}");
|
||||
}
|
||||
|
||||
fn issue_13959() {
|
||||
println!("{}", r#"""#);
|
||||
println!(
|
||||
"{}",
|
||||
r#"
|
||||
foo
|
||||
\
|
||||
\\
|
||||
"
|
||||
\"
|
||||
bar
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
|
|
@ -192,5 +192,41 @@ LL - println!("mixed: {} {world}", "{hello}");
|
|||
LL + println!("mixed: {{hello}} {world}");
|
||||
|
|
||||
|
||||
error: aborting due to 16 previous errors
|
||||
error: literal with an empty format string
|
||||
--> tests/ui/print_literal.rs:71:20
|
||||
|
|
||||
LL | println!("{}", r#"""#);
|
||||
| ^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - println!("{}", r#"""#);
|
||||
LL + println!("\"");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> tests/ui/print_literal.rs:74:9
|
||||
|
|
||||
LL | / r#"
|
||||
LL | | foo
|
||||
LL | | \
|
||||
LL | | \\
|
||||
... |
|
||||
LL | | bar
|
||||
LL | | "#
|
||||
| |__^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL ~ "
|
||||
LL + foo
|
||||
LL + \\
|
||||
LL + \\\\
|
||||
LL + \"
|
||||
LL + \\\"
|
||||
LL + bar
|
||||
LL ~ "
|
||||
|
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
|
||||
|
|
154
src/tools/clippy/tests/ui/redundant_else.fixed
Normal file
154
src/tools/clippy/tests/ui/redundant_else.fixed
Normal file
|
@ -0,0 +1,154 @@
|
|||
#![warn(clippy::redundant_else)]
|
||||
#![allow(clippy::needless_return, clippy::if_same_then_else, clippy::needless_late_init)]
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
// break
|
||||
if foo() {
|
||||
println!("Love your neighbor;");
|
||||
break;
|
||||
}
|
||||
//~^ ERROR: redundant else block
|
||||
println!("yet don't pull down your hedge.");
|
||||
// continue
|
||||
if foo() {
|
||||
println!("He that lies down with Dogs,");
|
||||
continue;
|
||||
}
|
||||
//~^ ERROR: redundant else block
|
||||
println!("shall rise up with fleas.");
|
||||
// match block
|
||||
if foo() {
|
||||
match foo() {
|
||||
1 => break,
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
//~^ ERROR: redundant else block
|
||||
println!("You may delay, but time will not.");
|
||||
}
|
||||
// else if
|
||||
if foo() {
|
||||
return;
|
||||
} else if foo() {
|
||||
return;
|
||||
}
|
||||
//~^ ERROR: redundant else block
|
||||
println!("A fat kitchen makes a lean will.");
|
||||
// let binding outside of block
|
||||
let _ = {
|
||||
if foo() {
|
||||
return;
|
||||
}
|
||||
//~^ ERROR: redundant else block
|
||||
1
|
||||
};
|
||||
// else if with let binding outside of block
|
||||
let _ = {
|
||||
if foo() {
|
||||
return;
|
||||
} else if foo() {
|
||||
return;
|
||||
}
|
||||
//~^ ERROR: redundant else block
|
||||
2
|
||||
};
|
||||
// inside if let
|
||||
let _ = if let Some(1) = foo() {
|
||||
let _ = 1;
|
||||
if foo() {
|
||||
return;
|
||||
}
|
||||
//~^ ERROR: redundant else block
|
||||
1
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
//
|
||||
// non-lint cases
|
||||
//
|
||||
|
||||
// sanity check
|
||||
if foo() {
|
||||
let _ = 1;
|
||||
} else {
|
||||
println!("Who is wise? He that learns from every one.");
|
||||
}
|
||||
// else if without else
|
||||
if foo() {
|
||||
return;
|
||||
} else if foo() {
|
||||
foo()
|
||||
};
|
||||
// nested if return
|
||||
if foo() {
|
||||
if foo() {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
foo()
|
||||
};
|
||||
// match with non-breaking branch
|
||||
if foo() {
|
||||
match foo() {
|
||||
1 => foo(),
|
||||
_ => return,
|
||||
}
|
||||
} else {
|
||||
println!("Three may keep a secret, if two of them are dead.");
|
||||
}
|
||||
// let binding
|
||||
let _ = if foo() {
|
||||
return;
|
||||
} else {
|
||||
1
|
||||
};
|
||||
// assign
|
||||
let mut a;
|
||||
a = if foo() {
|
||||
return;
|
||||
} else {
|
||||
1
|
||||
};
|
||||
// assign-op
|
||||
a += if foo() {
|
||||
return;
|
||||
} else {
|
||||
1
|
||||
};
|
||||
// if return else if else
|
||||
if foo() {
|
||||
return;
|
||||
} else if foo() {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
};
|
||||
// if else if return else
|
||||
if foo() {
|
||||
1
|
||||
} else if foo() {
|
||||
return;
|
||||
} else {
|
||||
2
|
||||
};
|
||||
// else if with let binding
|
||||
let _ = if foo() {
|
||||
return;
|
||||
} else if foo() {
|
||||
return;
|
||||
} else {
|
||||
2
|
||||
};
|
||||
// inside function call
|
||||
Box::new(if foo() {
|
||||
return;
|
||||
} else {
|
||||
1
|
||||
});
|
||||
}
|
||||
|
||||
fn foo<T>() -> T {
|
||||
unimplemented!("I'm not Santa Claus")
|
||||
}
|
|
@ -1,88 +1,123 @@
|
|||
error: redundant else block
|
||||
--> tests/ui/redundant_else.rs:10:16
|
||||
--> tests/ui/redundant_else.rs:10:10
|
||||
|
|
||||
LL | } else {
|
||||
| ________________^
|
||||
| __________^
|
||||
LL | |
|
||||
LL | | println!("yet don't pull down your hedge.");
|
||||
LL | | }
|
||||
| |_________^
|
||||
|
|
||||
= help: remove the `else` block and move the contents out
|
||||
= note: `-D clippy::redundant-else` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::redundant_else)]`
|
||||
help: remove the `else` block and move the contents out
|
||||
|
|
||||
LL ~ }
|
||||
LL +
|
||||
LL + println!("yet don't pull down your hedge.");
|
||||
|
|
||||
|
||||
error: redundant else block
|
||||
--> tests/ui/redundant_else.rs:18:16
|
||||
--> tests/ui/redundant_else.rs:18:10
|
||||
|
|
||||
LL | } else {
|
||||
| ________________^
|
||||
| __________^
|
||||
LL | |
|
||||
LL | | println!("shall rise up with fleas.");
|
||||
LL | | }
|
||||
| |_________^
|
||||
|
|
||||
= help: remove the `else` block and move the contents out
|
||||
help: remove the `else` block and move the contents out
|
||||
|
|
||||
LL ~ }
|
||||
LL +
|
||||
LL + println!("shall rise up with fleas.");
|
||||
|
|
||||
|
||||
error: redundant else block
|
||||
--> tests/ui/redundant_else.rs:28:16
|
||||
--> tests/ui/redundant_else.rs:28:10
|
||||
|
|
||||
LL | } else {
|
||||
| ________________^
|
||||
| __________^
|
||||
LL | |
|
||||
LL | | println!("You may delay, but time will not.");
|
||||
LL | | }
|
||||
| |_________^
|
||||
|
|
||||
= help: remove the `else` block and move the contents out
|
||||
help: remove the `else` block and move the contents out
|
||||
|
|
||||
LL ~ }
|
||||
LL +
|
||||
LL + println!("You may delay, but time will not.");
|
||||
|
|
||||
|
||||
error: redundant else block
|
||||
--> tests/ui/redundant_else.rs:38:12
|
||||
--> tests/ui/redundant_else.rs:38:6
|
||||
|
|
||||
LL | } else {
|
||||
| ____________^
|
||||
| ______^
|
||||
LL | |
|
||||
LL | | println!("A fat kitchen makes a lean will.");
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: remove the `else` block and move the contents out
|
||||
help: remove the `else` block and move the contents out
|
||||
|
|
||||
LL ~ }
|
||||
LL +
|
||||
LL + println!("A fat kitchen makes a lean will.");
|
||||
|
|
||||
|
||||
error: redundant else block
|
||||
--> tests/ui/redundant_else.rs:46:16
|
||||
--> tests/ui/redundant_else.rs:46:10
|
||||
|
|
||||
LL | } else {
|
||||
| ________________^
|
||||
| __________^
|
||||
LL | |
|
||||
LL | | 1
|
||||
LL | | }
|
||||
| |_________^
|
||||
|
|
||||
= help: remove the `else` block and move the contents out
|
||||
help: remove the `else` block and move the contents out
|
||||
|
|
||||
LL ~ }
|
||||
LL +
|
||||
LL + 1
|
||||
|
|
||||
|
||||
error: redundant else block
|
||||
--> tests/ui/redundant_else.rs:57:16
|
||||
--> tests/ui/redundant_else.rs:57:10
|
||||
|
|
||||
LL | } else {
|
||||
| ________________^
|
||||
| __________^
|
||||
LL | |
|
||||
LL | | 2
|
||||
LL | | }
|
||||
| |_________^
|
||||
|
|
||||
= help: remove the `else` block and move the contents out
|
||||
help: remove the `else` block and move the contents out
|
||||
|
|
||||
LL ~ }
|
||||
LL +
|
||||
LL + 2
|
||||
|
|
||||
|
||||
error: redundant else block
|
||||
--> tests/ui/redundant_else.rs:67:16
|
||||
--> tests/ui/redundant_else.rs:67:10
|
||||
|
|
||||
LL | } else {
|
||||
| ________________^
|
||||
| __________^
|
||||
LL | |
|
||||
LL | | 1
|
||||
LL | | }
|
||||
| |_________^
|
||||
|
|
||||
= help: remove the `else` block and move the contents out
|
||||
help: remove the `else` block and move the contents out
|
||||
|
|
||||
LL ~ }
|
||||
LL +
|
||||
LL + 1
|
||||
|
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
|
67
src/tools/clippy/tests/ui/return_and_then.fixed
Normal file
67
src/tools/clippy/tests/ui/return_and_then.fixed
Normal file
|
@ -0,0 +1,67 @@
|
|||
#![warn(clippy::return_and_then)]
|
||||
|
||||
fn main() {
|
||||
fn test_opt_block(opt: Option<i32>) -> Option<i32> {
|
||||
let n = opt?;
|
||||
let mut ret = n + 1;
|
||||
ret += n;
|
||||
if n > 1 { Some(ret) } else { None }
|
||||
}
|
||||
|
||||
fn test_opt_func(opt: Option<i32>) -> Option<i32> {
|
||||
let n = opt?;
|
||||
test_opt_block(Some(n))
|
||||
}
|
||||
|
||||
fn test_call_chain() -> Option<i32> {
|
||||
let n = gen_option(1)?;
|
||||
test_opt_block(Some(n))
|
||||
}
|
||||
|
||||
fn test_res_block(opt: Result<i32, i32>) -> Result<i32, i32> {
|
||||
let n = opt?;
|
||||
if n > 1 { Ok(n + 1) } else { Err(n) }
|
||||
}
|
||||
|
||||
fn test_res_func(opt: Result<i32, i32>) -> Result<i32, i32> {
|
||||
let n = opt?;
|
||||
test_res_block(Ok(n))
|
||||
}
|
||||
|
||||
fn test_ref_only() -> Option<i32> {
|
||||
// ref: empty string
|
||||
let x = Some("")?;
|
||||
if x.len() > 2 { Some(3) } else { None }
|
||||
}
|
||||
|
||||
fn test_tmp_only() -> Option<i32> {
|
||||
// unused temporary: vec![1, 2, 4]
|
||||
let x = Some(match (vec![1, 2, 3], vec![1, 2, 4]) {
|
||||
(a, _) if a.len() > 1 => a,
|
||||
(_, b) => b,
|
||||
})?;
|
||||
if x.len() > 2 { Some(3) } else { None }
|
||||
}
|
||||
|
||||
// should not lint
|
||||
fn test_tmp_ref() -> Option<String> {
|
||||
String::from("<BOOM>")
|
||||
.strip_prefix("<")
|
||||
.and_then(|s| s.strip_suffix(">").map(String::from))
|
||||
}
|
||||
|
||||
// should not lint
|
||||
fn test_unconsumed_tmp() -> Option<i32> {
|
||||
[1, 2, 3]
|
||||
.iter()
|
||||
.map(|x| x + 1)
|
||||
.collect::<Vec<_>>() // temporary Vec created here
|
||||
.as_slice() // creates temporary slice
|
||||
.first() // creates temporary reference
|
||||
.and_then(|x| test_opt_block(Some(*x)))
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_option(n: i32) -> Option<i32> {
|
||||
Some(n)
|
||||
}
|
63
src/tools/clippy/tests/ui/return_and_then.rs
Normal file
63
src/tools/clippy/tests/ui/return_and_then.rs
Normal file
|
@ -0,0 +1,63 @@
|
|||
#![warn(clippy::return_and_then)]
|
||||
|
||||
fn main() {
|
||||
fn test_opt_block(opt: Option<i32>) -> Option<i32> {
|
||||
opt.and_then(|n| {
|
||||
let mut ret = n + 1;
|
||||
ret += n;
|
||||
if n > 1 { Some(ret) } else { None }
|
||||
})
|
||||
}
|
||||
|
||||
fn test_opt_func(opt: Option<i32>) -> Option<i32> {
|
||||
opt.and_then(|n| test_opt_block(Some(n)))
|
||||
}
|
||||
|
||||
fn test_call_chain() -> Option<i32> {
|
||||
gen_option(1).and_then(|n| test_opt_block(Some(n)))
|
||||
}
|
||||
|
||||
fn test_res_block(opt: Result<i32, i32>) -> Result<i32, i32> {
|
||||
opt.and_then(|n| if n > 1 { Ok(n + 1) } else { Err(n) })
|
||||
}
|
||||
|
||||
fn test_res_func(opt: Result<i32, i32>) -> Result<i32, i32> {
|
||||
opt.and_then(|n| test_res_block(Ok(n)))
|
||||
}
|
||||
|
||||
fn test_ref_only() -> Option<i32> {
|
||||
// ref: empty string
|
||||
Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None })
|
||||
}
|
||||
|
||||
fn test_tmp_only() -> Option<i32> {
|
||||
// unused temporary: vec![1, 2, 4]
|
||||
Some(match (vec![1, 2, 3], vec![1, 2, 4]) {
|
||||
(a, _) if a.len() > 1 => a,
|
||||
(_, b) => b,
|
||||
})
|
||||
.and_then(|x| if x.len() > 2 { Some(3) } else { None })
|
||||
}
|
||||
|
||||
// should not lint
|
||||
fn test_tmp_ref() -> Option<String> {
|
||||
String::from("<BOOM>")
|
||||
.strip_prefix("<")
|
||||
.and_then(|s| s.strip_suffix(">").map(String::from))
|
||||
}
|
||||
|
||||
// should not lint
|
||||
fn test_unconsumed_tmp() -> Option<i32> {
|
||||
[1, 2, 3]
|
||||
.iter()
|
||||
.map(|x| x + 1)
|
||||
.collect::<Vec<_>>() // temporary Vec created here
|
||||
.as_slice() // creates temporary slice
|
||||
.first() // creates temporary reference
|
||||
.and_then(|x| test_opt_block(Some(*x)))
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_option(n: i32) -> Option<i32> {
|
||||
Some(n)
|
||||
}
|
101
src/tools/clippy/tests/ui/return_and_then.stderr
Normal file
101
src/tools/clippy/tests/ui/return_and_then.stderr
Normal file
|
@ -0,0 +1,101 @@
|
|||
error: use the question mark operator instead of an `and_then` call
|
||||
--> tests/ui/return_and_then.rs:5:9
|
||||
|
|
||||
LL | / opt.and_then(|n| {
|
||||
LL | | let mut ret = n + 1;
|
||||
LL | | ret += n;
|
||||
LL | | if n > 1 { Some(ret) } else { None }
|
||||
LL | | })
|
||||
| |__________^
|
||||
|
|
||||
= note: `-D clippy::return-and-then` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::return_and_then)]`
|
||||
help: try
|
||||
|
|
||||
LL ~ let n = opt?;
|
||||
LL + let mut ret = n + 1;
|
||||
LL + ret += n;
|
||||
LL + if n > 1 { Some(ret) } else { None }
|
||||
|
|
||||
|
||||
error: use the question mark operator instead of an `and_then` call
|
||||
--> tests/ui/return_and_then.rs:13:9
|
||||
|
|
||||
LL | opt.and_then(|n| test_opt_block(Some(n)))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL ~ let n = opt?;
|
||||
LL + test_opt_block(Some(n))
|
||||
|
|
||||
|
||||
error: use the question mark operator instead of an `and_then` call
|
||||
--> tests/ui/return_and_then.rs:17:9
|
||||
|
|
||||
LL | gen_option(1).and_then(|n| test_opt_block(Some(n)))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL ~ let n = gen_option(1)?;
|
||||
LL + test_opt_block(Some(n))
|
||||
|
|
||||
|
||||
error: use the question mark operator instead of an `and_then` call
|
||||
--> tests/ui/return_and_then.rs:21:9
|
||||
|
|
||||
LL | opt.and_then(|n| if n > 1 { Ok(n + 1) } else { Err(n) })
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL ~ let n = opt?;
|
||||
LL + if n > 1 { Ok(n + 1) } else { Err(n) }
|
||||
|
|
||||
|
||||
error: use the question mark operator instead of an `and_then` call
|
||||
--> tests/ui/return_and_then.rs:25:9
|
||||
|
|
||||
LL | opt.and_then(|n| test_res_block(Ok(n)))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL ~ let n = opt?;
|
||||
LL + test_res_block(Ok(n))
|
||||
|
|
||||
|
||||
error: use the question mark operator instead of an `and_then` call
|
||||
--> tests/ui/return_and_then.rs:30:9
|
||||
|
|
||||
LL | Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None })
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL ~ let x = Some("")?;
|
||||
LL + if x.len() > 2 { Some(3) } else { None }
|
||||
|
|
||||
|
||||
error: use the question mark operator instead of an `and_then` call
|
||||
--> tests/ui/return_and_then.rs:35:9
|
||||
|
|
||||
LL | / Some(match (vec![1, 2, 3], vec![1, 2, 4]) {
|
||||
LL | | (a, _) if a.len() > 1 => a,
|
||||
LL | | (_, b) => b,
|
||||
LL | | })
|
||||
LL | | .and_then(|x| if x.len() > 2 { Some(3) } else { None })
|
||||
| |_______________________________________________________________^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL ~ let x = Some(match (vec![1, 2, 3], vec![1, 2, 4]) {
|
||||
LL + (a, _) if a.len() > 1 => a,
|
||||
LL + (_, b) => b,
|
||||
LL + })?;
|
||||
LL + if x.len() > 2 { Some(3) } else { None }
|
||||
|
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
|
@ -8,11 +8,11 @@ fn main() {
|
|||
const SIZE: usize = 128;
|
||||
const HALF_SIZE: usize = SIZE / 2;
|
||||
const DOUBLE_SIZE: usize = SIZE * 2;
|
||||
let mut x = [2u8; SIZE];
|
||||
let mut y = [2u8; SIZE];
|
||||
let mut x = [2u16; SIZE];
|
||||
let mut y = [2u16; SIZE];
|
||||
|
||||
// Count expression involving multiplication of size_of (Should trigger the lint)
|
||||
unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
|
||||
unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u16>() * SIZE) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
|
||||
// Count expression involving nested multiplications of size_of (Should trigger the lint)
|
||||
|
@ -20,22 +20,19 @@ fn main() {
|
|||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
|
||||
// Count expression involving divisions of size_of (Should trigger the lint)
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::<u8>() / 2) };
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::<u16>() / 2) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
|
||||
// Count expression involving divisions by size_of (Should not trigger the lint)
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / size_of::<u8>()) };
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / size_of::<u16>()) };
|
||||
|
||||
// Count expression involving divisions by multiple size_of (Should not trigger the lint)
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 * size_of::<u8>())) };
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 * size_of::<u16>())) };
|
||||
|
||||
// Count expression involving recursive divisions by size_of (Should trigger the lint)
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 / size_of::<u8>())) };
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 / size_of::<u16>())) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
|
||||
// No size_of calls (Should not trigger the lint)
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) };
|
||||
|
||||
// Different types for pointee and size_of (Should not trigger the lint)
|
||||
unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::<u16>() / 2 * SIZE) };
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/expressions.rs:15:62
|
||||
|
|
||||
LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u16>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
= note: `-D clippy::size-of-in-element-count` implied by `-D warnings`
|
||||
|
@ -19,16 +19,16 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * si
|
|||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/expressions.rs:23:47
|
||||
|
|
||||
LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::<u8>() / 2) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::<u16>() / 2) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/expressions.rs:33:47
|
||||
|
|
||||
LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 / size_of::<u8>())) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 / size_of::<u16>())) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
|
|
|
@ -11,57 +11,52 @@ fn main() {
|
|||
const SIZE: usize = 128;
|
||||
const HALF_SIZE: usize = SIZE / 2;
|
||||
const DOUBLE_SIZE: usize = SIZE * 2;
|
||||
let mut x = [2u8; SIZE];
|
||||
let mut y = [2u8; SIZE];
|
||||
let mut x = [2u16; SIZE];
|
||||
let mut y = [2u16; SIZE];
|
||||
|
||||
// Count is size_of (Should trigger the lint)
|
||||
unsafe { copy_nonoverlapping::<u8>(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>()) };
|
||||
unsafe { copy_nonoverlapping::<u16>(x.as_ptr(), y.as_mut_ptr(), size_of::<u16>()) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
|
||||
unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::<u8>()) };
|
||||
unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::<u16>()) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::<u8>()) };
|
||||
unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::<u16>()) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::<u8>()) };
|
||||
unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::<u16>()) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::<u8>()) };
|
||||
unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::<u16>()) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>()) };
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::<u16>()) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
|
||||
unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::<u8>() * SIZE) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::<u8>() * SIZE) };
|
||||
unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::<u16>() * SIZE) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
|
||||
unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::<u8>() * SIZE) };
|
||||
slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::<u16>() * SIZE);
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
slice_from_raw_parts(y.as_ptr(), size_of::<u16>() * SIZE);
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
|
||||
slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::<u8>() * SIZE);
|
||||
unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::<u16>() * SIZE) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
slice_from_raw_parts(y.as_ptr(), size_of::<u8>() * SIZE);
|
||||
unsafe { from_raw_parts(y.as_ptr(), size_of::<u16>() * SIZE) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
|
||||
unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::<u8>() * SIZE) };
|
||||
unsafe { y.as_mut_ptr().sub(size_of::<u16>()) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
unsafe { from_raw_parts(y.as_ptr(), size_of::<u8>() * SIZE) };
|
||||
y.as_ptr().wrapping_sub(size_of::<u16>());
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
|
||||
unsafe { y.as_mut_ptr().sub(size_of::<u8>()) };
|
||||
unsafe { y.as_ptr().add(size_of::<u16>()) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
y.as_ptr().wrapping_sub(size_of::<u8>());
|
||||
y.as_mut_ptr().wrapping_add(size_of::<u16>());
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
unsafe { y.as_ptr().add(size_of::<u8>()) };
|
||||
unsafe { y.as_ptr().offset(size_of::<u16>() as isize) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
y.as_mut_ptr().wrapping_add(size_of::<u8>());
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
unsafe { y.as_ptr().offset(size_of::<u8>() as isize) };
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
y.as_mut_ptr().wrapping_offset(size_of::<u8>() as isize);
|
||||
y.as_mut_ptr().wrapping_offset(size_of::<u16>() as isize);
|
||||
//~^ ERROR: found a count of bytes instead of a count of elements of `T`
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:18:68
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:18:69
|
||||
|
|
||||
LL | unsafe { copy_nonoverlapping::<u8>(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | unsafe { copy_nonoverlapping::<u16>(x.as_ptr(), y.as_mut_ptr(), size_of::<u16>()) };
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
= note: `-D clippy::size-of-in-element-count` implied by `-D warnings`
|
||||
|
@ -19,40 +19,40 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x
|
|||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:23:49
|
||||
|
|
||||
LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::<u16>()) };
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:25:64
|
||||
|
|
||||
LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::<u16>()) };
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:27:51
|
||||
|
|
||||
LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::<u16>()) };
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:29:66
|
||||
|
|
||||
LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::<u16>()) };
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:32:47
|
||||
|
|
||||
LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::<u16>()) };
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
|
@ -65,108 +65,92 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) };
|
|||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:37:46
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:37:66
|
||||
|
|
||||
LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::<u8>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::<u16>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:39:47
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:40:46
|
||||
|
|
||||
LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::<u8>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::<u16>() * SIZE);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:42:66
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:42:38
|
||||
|
|
||||
LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::<u8>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | slice_from_raw_parts(y.as_ptr(), size_of::<u16>() * SIZE);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:45:46
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:45:49
|
||||
|
|
||||
LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::<u8>() * SIZE);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::<u16>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:47:38
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:47:41
|
||||
|
|
||||
LL | slice_from_raw_parts(y.as_ptr(), size_of::<u8>() * SIZE);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unsafe { from_raw_parts(y.as_ptr(), size_of::<u16>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:50:49
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:50:33
|
||||
|
|
||||
LL | unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::<u8>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unsafe { y.as_mut_ptr().sub(size_of::<u16>()) };
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:52:41
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:52:29
|
||||
|
|
||||
LL | unsafe { from_raw_parts(y.as_ptr(), size_of::<u8>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | y.as_ptr().wrapping_sub(size_of::<u16>());
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:55:33
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:54:29
|
||||
|
|
||||
LL | unsafe { y.as_mut_ptr().sub(size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | unsafe { y.as_ptr().add(size_of::<u16>()) };
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:57:29
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:56:33
|
||||
|
|
||||
LL | y.as_ptr().wrapping_sub(size_of::<u8>());
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | y.as_mut_ptr().wrapping_add(size_of::<u16>());
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:59:29
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:58:32
|
||||
|
|
||||
LL | unsafe { y.as_ptr().add(size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | unsafe { y.as_ptr().offset(size_of::<u16>() as isize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:61:33
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:60:36
|
||||
|
|
||||
LL | y.as_mut_ptr().wrapping_add(size_of::<u8>());
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | y.as_mut_ptr().wrapping_offset(size_of::<u16>() as isize);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:63:32
|
||||
|
|
||||
LL | unsafe { y.as_ptr().offset(size_of::<u8>() as isize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> tests/ui/size_of_in_element_count/functions.rs:65:36
|
||||
|
|
||||
LL | y.as_mut_ptr().wrapping_offset(size_of::<u8>() as isize);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: aborting due to 21 previous errors
|
||||
error: aborting due to 19 previous errors
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: `ref` directly on a function argument is ignored. Consider using a reference type instead
|
||||
error: `ref` directly on a function parameter does not prevent taking ownership of the passed argument. Consider using a reference type instead
|
||||
--> tests/ui/toplevel_ref_arg_non_rustfix.rs:9:15
|
||||
|
|
||||
LL | fn the_answer(ref mut x: u8) {
|
||||
|
@ -7,7 +7,7 @@ LL | fn the_answer(ref mut x: u8) {
|
|||
= note: `-D clippy::toplevel-ref-arg` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::toplevel_ref_arg)]`
|
||||
|
||||
error: `ref` directly on a function argument is ignored. Consider using a reference type instead
|
||||
error: `ref` directly on a function parameter does not prevent taking ownership of the passed argument. Consider using a reference type instead
|
||||
--> tests/ui/toplevel_ref_arg_non_rustfix.rs:20:24
|
||||
|
|
||||
LL | fn fun_example(ref _x: usize) {}
|
||||
|
|
|
@ -55,3 +55,9 @@ fn no_borrow_issue(a: u32, b: u32) {
|
|||
None => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn issue14100() -> bool {
|
||||
// Removing the `;` would make the block type be `()` instead of `!`, and this could no longer be
|
||||
// cast into the `bool` function return type.
|
||||
if return true {};
|
||||
}
|
||||
|
|
|
@ -55,3 +55,9 @@ fn no_borrow_issue(a: u32, b: u32) {
|
|||
None => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn issue14100() -> bool {
|
||||
// Removing the `;` would make the block type be `()` instead of `!`, and this could no longer be
|
||||
// cast into the `bool` function return type.
|
||||
if return true {};
|
||||
}
|
||||
|
|
|
@ -55,3 +55,9 @@ fn no_borrow_issue(a: u32, b: u32) {
|
|||
None => {},
|
||||
};
|
||||
}
|
||||
|
||||
fn issue14100() -> bool {
|
||||
// Removing the `;` would make the block type be `()` instead of `!`, and this could no longer be
|
||||
// cast into the `bool` function return type.
|
||||
if return true {};
|
||||
}
|
||||
|
|
|
@ -62,3 +62,19 @@ fn main() {
|
|||
writeln!(v, "hello {0} {1}, world {2}", 2, 3, 4);
|
||||
//~^ ERROR: literal with an empty format string
|
||||
}
|
||||
|
||||
fn issue_13959() {
|
||||
let mut v = Vec::new();
|
||||
writeln!(v, "\"");
|
||||
writeln!(
|
||||
v,
|
||||
"
|
||||
foo
|
||||
\\
|
||||
\\\\
|
||||
\"
|
||||
\\\"
|
||||
bar
|
||||
"
|
||||
);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue