[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
[`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
+[`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
[`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
[`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
[`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
[`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
+[`map_err_ignore`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_err_ignore
[`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
[`map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_identity
[`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
[`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
[`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
[`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
+[`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
[`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
[`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
[`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
[`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len
+[`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer
[`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
[`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
Clippy welcomes contributions from everyone. There are many ways to contribute to Clippy and the following document
explains how you can contribute and how to get started. If you have any questions about contributing or need help with
-anything, feel free to ask questions on issues or visit the `#clippy` on [Discord].
+anything, feel free to ask questions on issues or visit the `#clippy` on [Zulip].
All contributors are expected to follow the [Rust Code of Conduct].
- [Bors and Homu](#bors-and-homu)
- [Contributions](#contributions)
-[Discord]: https://discord.gg/rust-lang
+[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/clippy
[Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
## Getting started
```
3. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to
accelerate the process ping the `@rust-lang/clippy` team in your PR and/or
- ~~annoy~~ ask them in the [Discord] channel.)
+ ~~annoy~~ ask them in the [Zulip] stream.)
### Syncing back changes in Clippy to [`rust-lang/rust`]
// we can unwrap here because the arg is required here
let rustc_path = PathBuf::from(rustc_path.unwrap());
assert!(rustc_path.is_dir(), "path is not a directory");
- let rustc_source_basedir = rustc_path.join("src");
+ let rustc_source_basedir = rustc_path.join("compiler");
assert!(
rustc_source_basedir.is_dir(),
"are you sure the path leads to a rustc repo?"
let new_deps = extern_crates.map(|dep| {
// format the dependencies that are going to be put inside the Cargo.toml
format!(
- "{dep} = {{ path = \"{source_path}/lib{dep}\" }}\n",
+ "{dep} = {{ path = \"{source_path}/{dep}\" }}\n",
dep = dep,
source_path = rustc_source_dir.display()
)
if_chain = "1.0.0"
itertools = "0.9"
lazy_static = "1.0.2"
-pulldown-cmark = { version = "0.7.1", default-features = false }
+pulldown-cmark = { version = "0.8", default-features = false }
quine-mc_cluskey = "0.2.2"
regex-syntax = "0.6"
serde = { version = "1.0", features = ["derive"] }
declare_clippy_lint! {
/// **What it does:** Checks for usage of invalid atomic
- /// ordering in atomic loads/stores and memory fences.
+ /// ordering in atomic loads/stores/exchanges/updates and
+ /// memory fences.
///
/// **Why is this bad?** Using an invalid atomic ordering
/// will cause a panic at run-time.
///
/// **Example:**
/// ```rust,no_run
- /// # use std::sync::atomic::{self, AtomicBool, Ordering};
+ /// # use std::sync::atomic::{self, AtomicU8, Ordering};
///
- /// let x = AtomicBool::new(true);
+ /// let x = AtomicU8::new(0);
///
+ /// // Bad: `Release` and `AcqRel` cannot be used for `load`.
/// let _ = x.load(Ordering::Release);
/// let _ = x.load(Ordering::AcqRel);
///
- /// x.store(false, Ordering::Acquire);
- /// x.store(false, Ordering::AcqRel);
+ /// // Bad: `Acquire` and `AcqRel` cannot be used for `store`.
+ /// x.store(1, Ordering::Acquire);
+ /// x.store(2, Ordering::AcqRel);
///
+ /// // Bad: `Relaxed` cannot be used as a fence's ordering.
/// atomic::fence(Ordering::Relaxed);
/// atomic::compiler_fence(Ordering::Relaxed);
+ ///
+ /// // Bad: `Release` and `AcqRel` are both always invalid
+ /// // for the failure ordering (the last arg).
+ /// let _ = x.compare_exchange(1, 2, Ordering::SeqCst, Ordering::Release);
+ /// let _ = x.compare_exchange_weak(2, 3, Ordering::AcqRel, Ordering::AcqRel);
+ ///
+ /// // Bad: The failure ordering is not allowed to be
+ /// // stronger than the success order, and `SeqCst` is
+ /// // stronger than `Relaxed`.
+ /// let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |val| Some(val + val));
/// ```
pub INVALID_ATOMIC_ORDERING,
correctness,
- "usage of invalid atomic ordering in atomic loads/stores and memory fences"
+ "usage of invalid atomic ordering in atomic operations and memory fences"
}
declare_lint_pass!(AtomicOrdering => [INVALID_ATOMIC_ORDERING]);
}
}
+fn opt_ordering_defid(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option<DefId> {
+ if let ExprKind::Path(ref ord_qpath) = ord_arg.kind {
+ cx.qpath_res(ord_qpath, ord_arg.hir_id).opt_def_id()
+ } else {
+ None
+ }
+}
+
+fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if_chain! {
+ if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind;
+ let method = method_path.ident.name.as_str();
+ if type_is_atomic(cx, &args[0]);
+ if method == "compare_exchange" || method == "compare_exchange_weak" || method == "fetch_update";
+ let (success_order_arg, failure_order_arg) = if method == "fetch_update" {
+ (&args[1], &args[2])
+ } else {
+ (&args[3], &args[4])
+ };
+ if let Some(fail_ordering_def_id) = opt_ordering_defid(cx, failure_order_arg);
+ then {
+ // Helper type holding on to some checking and error reporting data. Has
+ // - (success ordering name,
+ // - list of failure orderings forbidden by the success order,
+ // - suggestion message)
+ type OrdLintInfo = (&'static str, &'static [&'static str], &'static str);
+ let relaxed: OrdLintInfo = ("Relaxed", &["SeqCst", "Acquire"], "ordering mode `Relaxed`");
+ let acquire: OrdLintInfo = ("Acquire", &["SeqCst"], "ordering modes `Acquire` or `Relaxed`");
+ let seq_cst: OrdLintInfo = ("SeqCst", &[], "ordering modes `Acquire`, `SeqCst` or `Relaxed`");
+ let release = ("Release", relaxed.1, relaxed.2);
+ let acqrel = ("AcqRel", acquire.1, acquire.2);
+ let search = [relaxed, acquire, seq_cst, release, acqrel];
+
+ let success_lint_info = opt_ordering_defid(cx, success_order_arg)
+ .and_then(|success_ord_def_id| -> Option<OrdLintInfo> {
+ search
+ .iter()
+ .find(|(ordering, ..)| {
+ match_def_path(cx, success_ord_def_id,
+ &["core", "sync", "atomic", "Ordering", ordering])
+ })
+ .copied()
+ });
+
+ if match_ordering_def_path(cx, fail_ordering_def_id, &["Release", "AcqRel"]) {
+ // If we don't know the success order is, use what we'd suggest
+ // if it were maximally permissive.
+ let suggested = success_lint_info.unwrap_or(seq_cst).2;
+ span_lint_and_help(
+ cx,
+ INVALID_ATOMIC_ORDERING,
+ failure_order_arg.span,
+ &format!(
+ "{}'s failure ordering may not be `Release` or `AcqRel`",
+ method,
+ ),
+ None,
+ &format!("consider using {} instead", suggested),
+ );
+ } else if let Some((success_ord_name, bad_ords_given_success, suggested)) = success_lint_info {
+ if match_ordering_def_path(cx, fail_ordering_def_id, bad_ords_given_success) {
+ span_lint_and_help(
+ cx,
+ INVALID_ATOMIC_ORDERING,
+ failure_order_arg.span,
+ &format!(
+ "{}'s failure ordering may not be stronger than the success ordering of `{}`",
+ method,
+ success_ord_name,
+ ),
+ None,
+ &format!("consider using {} instead", suggested),
+ );
+ }
+ }
+ }
+ }
+}
+
impl<'tcx> LateLintPass<'tcx> for AtomicOrdering {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
check_atomic_load_store(cx, expr);
check_memory_fence(cx, expr);
+ check_atomic_compare_exchange(cx, expr);
}
}
/// **What it does:** Checks for calls to await while holding a
/// non-async-aware MutexGuard.
///
- /// **Why is this bad?** The Mutex types found in syd::sync and parking_lot
+ /// **Why is this bad?** The Mutex types found in std::sync and parking_lot
/// are not designed to operate in an async context across await points.
///
/// There are two potential solutions. One is to use an asynx-aware Mutex
/// if x & 0b1111 == 0 { }
/// ```
pub VERBOSE_BIT_MASK,
- style,
+ pedantic,
"expressions where a bit mask is less readable than the corresponding method call"
}
use crate::utils::{
- contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability,
- span_lint_and_sugg, walk_ptrs_ty,
+ contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability, span_lint_and_sugg,
};
use if_chain::if_chain;
use rustc_ast::ast::UintTy;
if let ExprKind::Binary(ref op, ref l, ref r) = body.value.kind;
if op.node == BinOpKind::Eq;
if match_type(cx,
- walk_ptrs_ty(cx.typeck_results().expr_ty(&filter_args[0])),
+ cx.typeck_results().expr_ty(&filter_args[0]).peel_refs(),
&paths::SLICE_ITER);
then {
let needle = match get_path_name(l) {
_ => { return; }
}
};
- if ty::Uint(UintTy::U8) != *walk_ptrs_ty(cx.typeck_results().expr_ty(needle)).kind() {
+ if ty::Uint(UintTy::U8) != *cx.typeck_results().expr_ty(needle).peel_refs().kind() {
return;
}
let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) =
/// A `String` (e.g., "abc").
Str(String),
/// A binary string (e.g., `b"abc"`).
- Binary(Lrc<Vec<u8>>),
+ Binary(Lrc<[u8]>),
/// A single `char` (e.g., `'a'`).
Char(char),
/// An integer's bit representation.
match *lit {
LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
LitKind::Byte(b) => Constant::Int(u128::from(b)),
- LitKind::ByteStr(ref s) => Constant::Binary(Lrc::clone(s)),
+ LitKind::ByteStr(ref s) => Constant::Binary(Lrc::from(s.as_slice())),
LitKind::Char(c) => Constant::Char(c),
LitKind::Int(n, _) => Constant::Int(n),
LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
return false;
}
- let s = if s.ends_with('s') { &s[..s.len() - 1] } else { s };
+ let s = s.strip_suffix('s').unwrap_or(s);
s.chars().all(char::is_alphanumeric)
&& s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
use crate::consts::{constant, Constant};
use crate::utils::paths;
-use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg};
declare_clippy_lint! {
/// **What it does:** Checks for calculation of subsecond microseconds or milliseconds
if_chain! {
if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.kind;
if let ExprKind::MethodCall(ref method_path, _ , ref args, _) = left.kind;
- if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &paths::DURATION);
+ if match_type(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), &paths::DURATION);
if let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right);
then {
let suggested_fn = match (method_path.ident.as_str().as_ref(), divisor) {
use crate::utils::SpanlessEq;
use crate::utils::{get_item_name, higher, is_type_diagnostic_item, match_type, paths, snippet, snippet_opt};
-use crate::utils::{snippet_with_applicability, span_lint_and_then, walk_ptrs_ty};
+use crate::utils::{snippet_with_applicability, span_lint_and_then};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
if let ExprKind::AddrOf(BorrowKind::Ref, _, ref key) = params[1].kind;
then {
let map = ¶ms[0];
- let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(map));
+ let obj_ty = cx.typeck_results().expr_ty(map).peel_refs();
return if match_type(cx, obj_ty, &paths::BTREEMAP) {
Some(("BTreeMap", map, key))
use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT};
-use crate::utils::{
- is_expn_of, is_type_diagnostic_item, match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty,
-};
+use crate::utils::{is_expn_of, is_type_diagnostic_item, match_def_path, method_chain_args, span_lint_and_then};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
- let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0]));
+ let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
|| is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
{
use crate::utils::paths;
use crate::utils::{
is_expn_of, is_type_diagnostic_item, last_path_segment, match_def_path, match_function_call, snippet,
- span_lint_and_then, walk_ptrs_ty,
+ span_lint_and_then,
};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
if let PatKind::Tuple(ref pats, None) = arms[0].pat.kind;
if pats.len() == 1;
then {
- let ty = walk_ptrs_ty(cx.typeck_results().pat_ty(&pats[0]));
+ let ty = cx.typeck_results().pat_ty(&pats[0]).peel_refs();
if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) {
return None;
}
impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Index(ref array, ref index) = &expr.kind {
- let ty = cx.typeck_results().expr_ty(array);
+ let ty = cx.typeck_results().expr_ty(array).peel_refs();
if let Some(range) = higher::range(index) {
// Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
if let ty::Array(_, s) = ty.kind() {
use crate::utils::{
get_trait_def_id, implements_trait, is_type_diagnostic_item, paths, return_ty, span_lint_and_help,
- trait_ref_of_method, walk_ptrs_ty,
+ trait_ref_of_method,
};
declare_clippy_lint! {
// Get the real type of 'self'
let fn_def_id = cx.tcx.hir().local_def_id(item.hir_id);
let self_type = cx.tcx.fn_sig(fn_def_id).input(0);
- let self_type = walk_ptrs_ty(self_type.skip_binder());
+ let self_type = self_type.skip_binder().peel_refs();
// Emit either a warning or an error
if implements_trait(cx, self_type, display_trait_id, &[]) {
-use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg};
use rustc_ast::ast::LitKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
})
}
- let ty = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr));
+ let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
match ty.kind() {
ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| {
cx.tcx
mod main_recursion;
mod manual_async_fn;
mod manual_non_exhaustive;
+mod manual_strip;
mod map_clone;
+mod map_err_ignore;
mod map_identity;
mod map_unit_fn;
mod match_on_vec_items;
mod option_env_unwrap;
mod option_if_let_else;
mod overflow_check_conditional;
+mod panic_in_result_fn;
mod panic_unimplemented;
mod partialeq_ne_impl;
mod path_buf_push_overwrite;
&main_recursion::MAIN_RECURSION,
&manual_async_fn::MANUAL_ASYNC_FN,
&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
+ &manual_strip::MANUAL_STRIP,
&map_clone::MAP_CLONE,
+ &map_err_ignore::MAP_ERR_IGNORE,
&map_identity::MAP_IDENTITY,
&map_unit_fn::OPTION_MAP_UNIT_FN,
&map_unit_fn::RESULT_MAP_UNIT_FN,
&option_env_unwrap::OPTION_ENV_UNWRAP,
&option_if_let_else::OPTION_IF_LET_ELSE,
&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
+ &panic_in_result_fn::PANIC_IN_RESULT_FN,
&panic_unimplemented::PANIC,
&panic_unimplemented::PANIC_PARAMS,
&panic_unimplemented::TODO,
&types::LET_UNIT_VALUE,
&types::LINKEDLIST,
&types::OPTION_OPTION,
+ &types::RC_BUFFER,
&types::REDUNDANT_ALLOCATION,
&types::TYPE_COMPLEXITY,
&types::UNIT_ARG,
&utils::internal_lints::COMPILER_LINT_FUNCTIONS,
&utils::internal_lints::DEFAULT_LINT,
&utils::internal_lints::LINT_WITHOUT_LINT_PASS,
+ &utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
&utils::internal_lints::OUTER_EXPN_EXPN_DATA,
&utils::internal_lints::PRODUCE_ICE,
&vec::USELESS_VEC,
store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
store.register_late_pass(|| box methods::Methods);
store.register_late_pass(|| box map_clone::MapClone);
+ store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
store.register_late_pass(|| box shadow::Shadow);
store.register_late_pass(|| box types::LetUnitValue);
store.register_late_pass(|| box types::UnitCmp);
store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
store.register_early_pass(|| box redundant_field_names::RedundantFieldNames);
store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
+ store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn);
+
let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
single_char_binding_names_threshold,
store.register_late_pass(|| box self_assignment::SelfAssignment);
store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
+ store.register_late_pass(|| box manual_strip::ManualStrip);
+ store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
LintId::of(&modulo_arithmetic::MODULO_ARITHMETIC),
+ LintId::of(&panic_in_result_fn::PANIC_IN_RESULT_FN),
LintId::of(&panic_unimplemented::PANIC),
LintId::of(&panic_unimplemented::TODO),
LintId::of(&panic_unimplemented::UNIMPLEMENTED),
store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(&attrs::INLINE_ALWAYS),
LintId::of(&await_holding_lock::AWAIT_HOLDING_LOCK),
+ LintId::of(&bit_mask::VERBOSE_BIT_MASK),
LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
LintId::of(&copies::MATCH_SAME_ARMS),
LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
LintId::of(&loops::EXPLICIT_ITER_LOOP),
LintId::of(¯o_use::MACRO_USE_IMPORTS),
+ LintId::of(&map_err_ignore::MAP_ERR_IGNORE),
LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS),
LintId::of(&matches::MATCH_BOOL),
LintId::of(&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS),
LintId::of(&utils::internal_lints::DEFAULT_LINT),
LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS),
+ LintId::of(&utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA),
LintId::of(&utils::internal_lints::PRODUCE_ICE),
]);
LintId::of(&attrs::USELESS_ATTRIBUTE),
LintId::of(&bit_mask::BAD_BIT_MASK),
LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
- LintId::of(&bit_mask::VERBOSE_BIT_MASK),
LintId::of(&blacklisted_name::BLACKLISTED_NAME),
LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
LintId::of(&booleans::LOGIC_BUG),
LintId::of(&main_recursion::MAIN_RECURSION),
LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
+ LintId::of(&manual_strip::MANUAL_STRIP),
LintId::of(&map_clone::MAP_CLONE),
LintId::of(&map_identity::MAP_IDENTITY),
LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(&types::CHAR_LIT_AS_U8),
LintId::of(&types::FN_TO_NUMERIC_CAST),
LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
+ LintId::of(&types::RC_BUFFER),
LintId::of(&types::REDUNDANT_ALLOCATION),
LintId::of(&types::TYPE_COMPLEXITY),
LintId::of(&types::UNIT_ARG),
LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS),
- LintId::of(&bit_mask::VERBOSE_BIT_MASK),
LintId::of(&blacklisted_name::BLACKLISTED_NAME),
LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
LintId::of(&collapsible_if::COLLAPSIBLE_IF),
LintId::of(&loops::EXPLICIT_COUNTER_LOOP),
LintId::of(&loops::MUT_RANGE_BOUND),
LintId::of(&loops::WHILE_LET_LOOP),
+ LintId::of(&manual_strip::MANUAL_STRIP),
LintId::of(&map_identity::MAP_IDENTITY),
LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
LintId::of(&types::BOX_VEC),
+ LintId::of(&types::RC_BUFFER),
LintId::of(&types::REDUNDANT_ALLOCATION),
LintId::of(&vec::USELESS_VEC),
]);
if let Some(self_expr) = args.get(0);
if let Some(pushed_item) = args.get(1);
// Check that the method being called is push() on a Vec
- if match_type(cx, cx.typeck_results().expr_ty(self_expr), &paths::VEC);
+ if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym!(vec_type));
if path.ident.name.as_str() == "push";
then {
return Some((self_expr, pushed_item))
span,
NEEDLESS_COLLECT_MSG,
|diag| {
- let (arg, pred) = if contains_arg.starts_with('&') {
- ("x", &contains_arg[1..])
- } else {
- ("&x", &*contains_arg)
- };
+ let (arg, pred) = contains_arg
+ .strip_prefix('&')
+ .map_or(("&x", &*contains_arg), |s| ("x", s));
diag.span_suggestion(
span,
"replace with",
--- /dev/null
+use crate::consts::{constant, Constant};
+use crate::utils::usage::mutated_variables;
+use crate::utils::{
+ eq_expr_value, higher, match_def_path, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then,
+};
+
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_hir::def::Res;
+use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::BinOpKind;
+use rustc_hir::{BorrowKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::Map;
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Spanned;
+use rustc_span::Span;
+
+declare_clippy_lint! {
+ /// **What it does:**
+ /// Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using
+ /// the pattern's length.
+ ///
+ /// **Why is this bad?**
+ /// Using `str:strip_{prefix,suffix}` is safer and may have better performance as there is no
+ /// slicing which may panic and the compiler does not need to insert this panic code. It is
+ /// also sometimes more readable as it removes the need for duplicating or storing the pattern
+ /// used by `str::{starts,ends}_with` and in the slicing.
+ ///
+ /// **Known problems:**
+ /// None.
+ ///
+ /// **Example:**
+ ///
+ /// ```rust
+ /// let s = "hello, world!";
+ /// if s.starts_with("hello, ") {
+ /// assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let s = "hello, world!";
+ /// if let Some(end) = s.strip_prefix("hello, ") {
+ /// assert_eq!(end.to_uppercase(), "WORLD!");
+ /// }
+ /// ```
+ pub MANUAL_STRIP,
+ complexity,
+ "suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing"
+}
+
+declare_lint_pass!(ManualStrip => [MANUAL_STRIP]);
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+enum StripKind {
+ Prefix,
+ Suffix,
+}
+
+impl<'tcx> LateLintPass<'tcx> for ManualStrip {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ if_chain! {
+ if let Some((cond, then, _)) = higher::if_block(&expr);
+ if let ExprKind::MethodCall(_, _, [target_arg, pattern], _) = cond.kind;
+ if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id);
+ if let ExprKind::Path(target_path) = &target_arg.kind;
+ then {
+ let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) {
+ StripKind::Prefix
+ } else if match_def_path(cx, method_def_id, &paths::STR_ENDS_WITH) {
+ StripKind::Suffix
+ } else {
+ return;
+ };
+ let target_res = qpath_res(cx, &target_path, target_arg.hir_id);
+ if target_res == Res::Err {
+ return;
+ };
+
+ if_chain! {
+ if let Res::Local(hir_id) = target_res;
+ if let Some(used_mutably) = mutated_variables(then, cx);
+ if used_mutably.contains(&hir_id);
+ then {
+ return;
+ }
+ }
+
+ let strippings = find_stripping(cx, strip_kind, target_res, pattern, then);
+ if !strippings.is_empty() {
+
+ let kind_word = match strip_kind {
+ StripKind::Prefix => "prefix",
+ StripKind::Suffix => "suffix",
+ };
+
+ let test_span = expr.span.until(then.span);
+ span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {} manually", kind_word), |diag| {
+ diag.span_note(test_span, &format!("the {} was tested here", kind_word));
+ multispan_sugg(
+ diag,
+ &format!("try using the `strip_{}` method", kind_word),
+ vec![(test_span,
+ format!("if let Some(<stripped>) = {}.strip_{}({}) ",
+ snippet(cx, target_arg.span, ".."),
+ kind_word,
+ snippet(cx, pattern.span, "..")))]
+ .into_iter().chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
+ )
+ });
+ }
+ }
+ }
+ }
+}
+
+// Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.
+fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+ if_chain! {
+ if let ExprKind::MethodCall(_, _, [arg], _) = expr.kind;
+ if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+ if match_def_path(cx, method_def_id, &paths::STR_LEN);
+ then {
+ Some(arg)
+ } else {
+ None
+ }
+ }
+}
+
+// Returns the length of the `expr` if it's a constant string or char.
+fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
+ let (value, _) = constant(cx, cx.typeck_results(), expr)?;
+ match value {
+ Constant::Str(value) => Some(value.len() as u128),
+ Constant::Char(value) => Some(value.len_utf8() as u128),
+ _ => None,
+ }
+}
+
+// Tests if `expr` equals the length of the pattern.
+fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'tcx Expr<'_>) -> bool {
+ if let ExprKind::Lit(Spanned {
+ node: LitKind::Int(n, _),
+ ..
+ }) = expr.kind
+ {
+ constant_length(cx, pattern).map_or(false, |length| length == n)
+ } else {
+ len_arg(cx, expr).map_or(false, |arg| eq_expr_value(cx, pattern, arg))
+ }
+}
+
+// Tests if `expr` is a `&str`.
+fn is_ref_str(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ match cx.typeck_results().expr_ty_adjusted(&expr).kind() {
+ ty::Ref(_, ty, _) => ty.is_str(),
+ _ => false,
+ }
+}
+
+// Removes the outer `AddrOf` expression if needed.
+fn peel_ref<'a>(expr: &'a Expr<'_>) -> &'a Expr<'a> {
+ if let ExprKind::AddrOf(BorrowKind::Ref, _, unref) = &expr.kind {
+ unref
+ } else {
+ expr
+ }
+}
+
+// Find expressions where `target` is stripped using the length of `pattern`.
+// We'll suggest replacing these expressions with the result of the `strip_{prefix,suffix}`
+// method.
+fn find_stripping<'tcx>(
+ cx: &LateContext<'tcx>,
+ strip_kind: StripKind,
+ target: Res,
+ pattern: &'tcx Expr<'_>,
+ expr: &'tcx Expr<'_>,
+) -> Vec<Span> {
+ struct StrippingFinder<'a, 'tcx> {
+ cx: &'a LateContext<'tcx>,
+ strip_kind: StripKind,
+ target: Res,
+ pattern: &'tcx Expr<'tcx>,
+ results: Vec<Span>,
+ }
+
+ impl<'a, 'tcx> Visitor<'tcx> for StrippingFinder<'a, 'tcx> {
+ type Map = Map<'tcx>;
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
+ if_chain! {
+ if is_ref_str(self.cx, ex);
+ let unref = peel_ref(ex);
+ if let ExprKind::Index(indexed, index) = &unref.kind;
+ if let Some(range) = higher::range(index);
+ if let higher::Range { start, end, .. } = range;
+ if let ExprKind::Path(path) = &indexed.kind;
+ if qpath_res(self.cx, path, ex.hir_id) == self.target;
+ then {
+ match (self.strip_kind, start, end) {
+ (StripKind::Prefix, Some(start), None) => {
+ if eq_pattern_length(self.cx, self.pattern, start) {
+ self.results.push(ex.span);
+ return;
+ }
+ },
+ (StripKind::Suffix, None, Some(end)) => {
+ if_chain! {
+ if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, left, right) = end.kind;
+ if let Some(left_arg) = len_arg(self.cx, left);
+ if let ExprKind::Path(left_path) = &left_arg.kind;
+ if qpath_res(self.cx, left_path, left_arg.hir_id) == self.target;
+ if eq_pattern_length(self.cx, self.pattern, right);
+ then {
+ self.results.push(ex.span);
+ return;
+ }
+ }
+ },
+ _ => {}
+ }
+ }
+ }
+
+ walk_expr(self, ex);
+ }
+ }
+
+ let mut finder = StrippingFinder {
+ cx,
+ strip_kind,
+ target,
+ pattern,
+ results: vec![],
+ };
+ walk_expr(&mut finder, expr);
+ finder.results
+}
--- /dev/null
+use crate::utils::span_lint_and_help;
+
+use rustc_hir::{CaptureBy, Expr, ExprKind, PatKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// **What it does:** Checks for instances of `map_err(|_| Some::Enum)`
+ ///
+ /// **Why is this bad?** This map_err throws away the original error rather than allowing the enum to contain and report the cause of the error
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ /// Before:
+ /// ```rust
+ /// use std::fmt;
+ ///
+ /// #[derive(Debug)]
+ /// enum Error {
+ /// Indivisible,
+ /// Remainder(u8),
+ /// }
+ ///
+ /// impl fmt::Display for Error {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// match self {
+ /// Error::Indivisible => write!(f, "could not divide input by three"),
+ /// Error::Remainder(remainder) => write!(
+ /// f,
+ /// "input is not divisible by three, remainder = {}",
+ /// remainder
+ /// ),
+ /// }
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for Error {}
+ ///
+ /// fn divisible_by_3(input: &str) -> Result<(), Error> {
+ /// input
+ /// .parse::<i32>()
+ /// .map_err(|_| Error::Indivisible)
+ /// .map(|v| v % 3)
+ /// .and_then(|remainder| {
+ /// if remainder == 0 {
+ /// Ok(())
+ /// } else {
+ /// Err(Error::Remainder(remainder as u8))
+ /// }
+ /// })
+ /// }
+ /// ```
+ ///
+ /// After:
+ /// ```rust
+ /// use std::{fmt, num::ParseIntError};
+ ///
+ /// #[derive(Debug)]
+ /// enum Error {
+ /// Indivisible(ParseIntError),
+ /// Remainder(u8),
+ /// }
+ ///
+ /// impl fmt::Display for Error {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// match self {
+ /// Error::Indivisible(_) => write!(f, "could not divide input by three"),
+ /// Error::Remainder(remainder) => write!(
+ /// f,
+ /// "input is not divisible by three, remainder = {}",
+ /// remainder
+ /// ),
+ /// }
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for Error {
+ /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ /// match self {
+ /// Error::Indivisible(source) => Some(source),
+ /// _ => None,
+ /// }
+ /// }
+ /// }
+ ///
+ /// fn divisible_by_3(input: &str) -> Result<(), Error> {
+ /// input
+ /// .parse::<i32>()
+ /// .map_err(Error::Indivisible)
+ /// .map(|v| v % 3)
+ /// .and_then(|remainder| {
+ /// if remainder == 0 {
+ /// Ok(())
+ /// } else {
+ /// Err(Error::Remainder(remainder as u8))
+ /// }
+ /// })
+ /// }
+ /// ```
+ pub MAP_ERR_IGNORE,
+ pedantic,
+ "`map_err` should not ignore the original error"
+}
+
+declare_lint_pass!(MapErrIgnore => [MAP_ERR_IGNORE]);
+
+impl<'tcx> LateLintPass<'tcx> for MapErrIgnore {
+ // do not try to lint if this is from a macro or desugaring
+ fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
+ if e.span.from_expansion() {
+ return;
+ }
+
+ // check if this is a method call (e.g. x.foo())
+ if let ExprKind::MethodCall(ref method, _t_span, ref args, _) = e.kind {
+ // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1]
+ // Enum::Variant[2]))
+ if method.ident.as_str() == "map_err" && args.len() == 2 {
+ // make sure the first argument is a closure, and grab the CaptureRef, body_id, and body_span fields
+ if let ExprKind::Closure(capture, _, body_id, body_span, _) = args[1].kind {
+ // check if this is by Reference (meaning there's no move statement)
+ if capture == CaptureBy::Ref {
+ // Get the closure body to check the parameters and values
+ let closure_body = cx.tcx.hir().body(body_id);
+ // make sure there's only one parameter (`|_|`)
+ if closure_body.params.len() == 1 {
+ // make sure that parameter is the wild token (`_`)
+ if let PatKind::Wild = closure_body.params[0].pat.kind {
+ // span the area of the closure capture and warn that the
+ // original error will be thrown away
+ span_lint_and_help(
+ cx,
+ MAP_ERR_IGNORE,
+ body_span,
+ "`map_err(|_|...` ignores the original error",
+ None,
+ "Consider wrapping the error in an enum variant",
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
-use crate::utils::walk_ptrs_ty;
use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(expr);
- let ty = walk_ptrs_ty(ty);
+ let ty = ty.peel_refs();
is_type_diagnostic_item(cx, ty, sym!(vec_type))
}
fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(expr);
- let ty = walk_ptrs_ty(ty);
+ let ty = ty.peel_refs();
is_type_lang_item(cx, ty, LangItem::RangeFull)
}
expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable,
is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, multispan_sugg, remove_blocks, snippet,
snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
- span_lint_and_then, walk_ptrs_ty,
+ span_lint_and_then,
};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
impl<'tcx> LateLintPass<'tcx> for Matches {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if in_external_macro(cx.sess(), expr.span) {
+ if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) {
return;
}
}
fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
- let ex_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(ex));
+ let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
if is_type_diagnostic_item(cx, ex_ty, sym!(result_type)) {
for arm in arms {
if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind {
use rustc_span::Span;
pub(crate) struct OptionAndThenSome;
+
impl BindInsteadOfMap for OptionAndThenSome {
const TYPE_NAME: &'static str = "Option";
const TYPE_QPATH: &'static [&'static str] = &paths::OPTION;
}
pub(crate) struct ResultAndThenOk;
+
impl BindInsteadOfMap for ResultAndThenOk {
const TYPE_NAME: &'static str = "Result";
const TYPE_QPATH: &'static [&'static str] = &paths::RESULT;
}
pub(crate) struct ResultOrElseErrInfo;
+
impl BindInsteadOfMap for ResultOrElseErrInfo {
const TYPE_NAME: &'static str = "Result";
const TYPE_QPATH: &'static [&'static str] = &paths::RESULT;
}
}
- fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) {
+ fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) -> bool {
let mut suggs = Vec::new();
- let can_sugg = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
+ let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
if_chain! {
if !in_macro(ret_expr.span);
if let hir::ExprKind::Call(ref func_path, ref args) = ret_expr.kind;
)
});
}
+ can_sugg
}
/// Lint use of `_.and_then(|x| Some(y))` for `Option`s
- fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+ fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) -> bool {
if !match_type(cx, cx.typeck_results().expr_ty(&args[0]), Self::TYPE_QPATH) {
- return;
+ return false;
}
match args[1].kind {
let closure_body = cx.tcx.hir().body(body_id);
let closure_expr = remove_blocks(&closure_body.value);
- if !Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) {
- Self::lint_closure(cx, expr, closure_expr);
+ if Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) {
+ true
+ } else {
+ Self::lint_closure(cx, expr, closure_expr)
}
},
// `_.and_then(Some)` case, which is no-op.
snippet(cx, args[0].span, "..").into(),
Applicability::MachineApplicable,
);
+ true
},
- _ => {},
+ _ => false,
}
}
}
use rustc_span::symbol::{sym, SymbolStr};
use crate::consts::{constant, Constant};
+use crate::utils::eager_or_lazy::is_lazyness_candidate;
use crate::utils::usage::mutated_variables;
use crate::utils::{
contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro,
- is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats,
- last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls,
- method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability,
- snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
- span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
+ is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath,
+ match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty,
+ single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
+ span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth,
+ SpanlessEq,
};
declare_clippy_lint! {
["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]),
["unwrap_or_else", "map"] => {
if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) {
- unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or");
+ unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or");
}
},
["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]),
["and_then", ..] => {
- unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "and");
- bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]);
- bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]);
+ let biom_option_linted = bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]);
+ let biom_result_linted = bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]);
+ if !biom_option_linted && !biom_result_linted {
+ unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "and");
+ }
},
["or_else", ..] => {
- unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "or");
- bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]);
+ if !bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]) {
+ unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "or");
+ }
},
["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]),
["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]),
["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]),
["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false),
["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true),
- ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or"),
- ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "get_or_insert"),
- ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "ok_or"),
+ ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"),
+ ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"),
+ ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"),
_ => {},
}
name: &str,
args: &'tcx [hir::Expr<'_>],
) {
- // Searches an expression for method calls or function calls that aren't ctors
- struct FunCallFinder<'a, 'tcx> {
- cx: &'a LateContext<'tcx>,
- found: bool,
- }
-
- impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> {
- type Map = Map<'tcx>;
-
- fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
- let call_found = match &expr.kind {
- // ignore enum and struct constructors
- hir::ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr),
- hir::ExprKind::MethodCall(..) => true,
- _ => false,
- };
-
- if call_found {
- self.found |= true;
- }
-
- if !self.found {
- intravisit::walk_expr(self, expr);
- }
- }
-
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::None
- }
- }
-
/// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
fn check_unwrap_or_default(
cx: &LateContext<'_>,
) {
if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind {
if path.ident.as_str() == "len" {
- let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
+ let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
match ty.kind() {
ty::Slice(_) | ty::Array(_, _) => return,
_ => (),
}
- if match_type(cx, ty, &paths::VEC) {
+ if is_type_diagnostic_item(cx, ty, sym!(vec_type)) {
return;
}
}
if_chain! {
if know_types.iter().any(|k| k.2.contains(&name));
- let mut finder = FunCallFinder { cx: &cx, found: false };
- if { finder.visit_expr(&arg); finder.found };
+ if is_lazyness_candidate(cx, arg);
if !contains_return(&arg);
let self_ty = cx.typeck_results().expr_ty(self_expr);
&& (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref))
&& {
let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
- let base_type = walk_ptrs_ty(arg_type);
+ let base_type = arg_type.peel_refs();
*base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type))
}
{
}
fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
- let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(arg));
+ let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs();
if let ty::Adt(_, subst) = obj_ty.kind() {
let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
let arg = &args[1];
if let Some(arglists) = method_chain_args(arg, &["chars"]) {
let target = &arglists[0][0];
- let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(target));
+ let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
let ref_str = if *self_ty.kind() == ty::Str {
""
} else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
}
fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
- let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
+ let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) {
lint_string_extend(cx, expr, args);
}
}
} else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type))
|| matches!(
- &walk_ptrs_ty(cx.typeck_results().expr_ty(caller_expr)).kind(),
+ &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(),
ty::Array(_, _)
)
{
/// lint use of `unwrap()` for `Option`s and `Result`s
fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) {
- let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&unwrap_args[0]));
+ let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs();
let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
Some((UNWRAP_USED, "an Option", "None"))
/// lint use of `expect()` for `Option`s and `Result`s
fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
- let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&expect_args[0]));
+ let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs();
let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
Some((EXPECT_USED, "an Option", "None"))
if segment.ident.name == sym!(Some);
then {
let mut applicability = Applicability::MachineApplicable;
- let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty_adjusted(&args[0][0]));
+ let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
if *self_ty.kind() != ty::Str {
return false;
INTO_ITER_ON_REF,
method_span,
&format!(
- "this `.into_iter()` call is equivalent to `.{}()` and will not move the `{}`",
+ "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`",
method_name, kind,
),
"call directly",
-use crate::utils::{is_type_diagnostic_item, match_qpath, snippet, span_lint_and_sugg};
-use if_chain::if_chain;
+use crate::utils::{eager_or_lazy, usage};
+use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_sugg};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use super::UNNECESSARY_LAZY_EVALUATIONS;
-// Return true if the expression is an accessor of any of the arguments
-fn expr_uses_argument(expr: &hir::Expr<'_>, params: &[hir::Param<'_>]) -> bool {
- params.iter().any(|arg| {
- if_chain! {
- if let hir::PatKind::Binding(_, _, ident, _) = arg.pat.kind;
- if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind;
- if let [p, ..] = path.segments;
- then {
- ident.name == p.ident.name
- } else {
- false
- }
- }
- })
-}
-
-fn match_any_qpath(path: &hir::QPath<'_>, paths: &[&[&str]]) -> bool {
- paths.iter().any(|candidate| match_qpath(path, candidate))
-}
-
-fn can_simplify(expr: &hir::Expr<'_>, params: &[hir::Param<'_>], variant_calls: bool) -> bool {
- match expr.kind {
- // Closures returning literals can be unconditionally simplified
- hir::ExprKind::Lit(_) => true,
-
- hir::ExprKind::Index(ref object, ref index) => {
- // arguments are not being indexed into
- if expr_uses_argument(object, params) {
- false
- } else {
- // arguments are not used as index
- !expr_uses_argument(index, params)
- }
- },
-
- // Reading fields can be simplified if the object is not an argument of the closure
- hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params),
-
- // Paths can be simplified if the root is not the argument, this also covers None
- hir::ExprKind::Path(_) => !expr_uses_argument(expr, params),
-
- // Calls to Some, Ok, Err can be considered literals if they don't derive an argument
- hir::ExprKind::Call(ref func, ref args) => if_chain! {
- if variant_calls; // Disable lint when rules conflict with bind_instead_of_map
- if let hir::ExprKind::Path(ref path) = func.kind;
- if match_any_qpath(path, &[&["Some"], &["Ok"], &["Err"]]);
- then {
- // Recursively check all arguments
- args.iter().all(|arg| can_simplify(arg, params, variant_calls))
- } else {
- false
- }
- },
-
- // For anything more complex than the above, a closure is probably the right solution,
- // or the case is handled by an other lint
- _ => false,
- }
-}
-
/// lint use of `<fn>_else(simple closure)` for `Option`s and `Result`s that can be
/// replaced with `<fn>(return value of simple closure)`
pub(super) fn lint<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx hir::Expr<'_>,
args: &'tcx [hir::Expr<'_>],
- allow_variant_calls: bool,
simplify_using: &str,
) {
let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type));
if is_option || is_result {
if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind {
let body = cx.tcx.hir().body(eid);
- let ex = &body.value;
- let params = &body.params;
+ let body_expr = &body.value;
+
+ if usage::BindingUsageFinder::are_params_used(cx, body) {
+ return;
+ }
- if can_simplify(ex, params, allow_variant_calls) {
+ if eager_or_lazy::is_eagerness_candidate(cx, body_expr) {
let msg = if is_option {
"unnecessary closure used to substitute value for `Option::None`"
} else {
"{0}.{1}({2})",
snippet(cx, args[0].span, ".."),
simplify_using,
- snippet(cx, ex.span, ".."),
+ snippet(cx, body_expr.span, ".."),
),
Applicability::MachineApplicable,
);
use crate::utils::{
get_item_name, get_parent_expr, higher, implements_trait, in_constant, is_integer_const, iter_input_pats,
last_path_segment, match_qpath, match_trait_method, paths, snippet, snippet_opt, span_lint, span_lint_and_sugg,
- span_lint_and_then, span_lint_hir_and_then, walk_ptrs_ty, SpanlessEq,
+ span_lint_and_then, span_lint_hir_and_then, SpanlessEq,
};
declare_clippy_lint! {
/// if y != x {} // where both are floats
///
/// // Good
- /// let error = f64::EPSILON; // Use an epsilon for comparison
+ /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
/// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
- /// // let error = std::f64::EPSILON;
- /// if (y - 1.23f64).abs() < error { }
- /// if (y - x).abs() > error { }
+ /// // let error_margin = std::f64::EPSILON;
+ /// if (y - 1.23f64).abs() < error_margin { }
+ /// if (y - x).abs() > error_margin { }
/// ```
pub FLOAT_CMP,
correctness,
/// if x == ONE { } // where both are floats
///
/// // Good
- /// let error = f64::EPSILON; // Use an epsilon for comparison
+ /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
/// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
- /// // let error = std::f64::EPSILON;
- /// if (x - ONE).abs() < error { }
+ /// // let error_margin = std::f64::EPSILON;
+ /// if (x - ONE).abs() < error_margin { }
/// ```
pub FLOAT_CMP_CONST,
restriction,
if !is_comparing_arrays {
diag.span_suggestion(
expr.span,
- "consider comparing them within some error",
+ "consider comparing them within some margin of error",
format!(
- "({}).abs() {} error",
+ "({}).abs() {} error_margin",
lhs - rhs,
if op == BinOpKind::Eq { '<' } else { '>' }
),
Applicability::HasPlaceholders, // snippet
);
}
- diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error`");
+ diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`");
});
} else if op == BinOpKind::Rem && is_integer_const(cx, right, 1) {
span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0");
}
fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- let value = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind();
+ let value = &cx.typeck_results().expr_ty(expr).peel_refs().kind();
if let ty::Array(arr_ty, _) = value {
return matches!(arr_ty.kind(), ty::Float(_));
}
fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- matches!(&walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind(), ty::Array(_, _))
+ matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _))
}
fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
if let PatKind::Ident(_, ident, None) = arg.pat.kind {
let arg_name = ident.to_string();
- if arg_name.starts_with('_') {
- if let Some(correspondence) = registered_names.get(&arg_name[1..]) {
+ if let Some(arg_name) = arg_name.strip_prefix('_') {
+ if let Some(correspondence) = registered_names.get(arg_name) {
span_lint(
cx,
DUPLICATE_UNDERSCORE_ARGUMENT,
&format!(
"`{}` already exists, having another argument having almost the same \
name makes code comprehension and documentation more difficult",
- arg_name[1..].to_owned()
+ arg_name
),
);
}
-use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method, walk_ptrs_ty};
+use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method};
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut};
/// `BtreeSet` rely on either the hash or the order of keys be unchanging,
/// so having types with interior mutability is a bad idea.
///
- /// **Known problems:** We don't currently account for `Rc` or `Arc`, so
- /// this may yield false positives.
+ /// **Known problems:** It's correct to use a struct, that contains interior mutability
+ /// as a key, when its `Hash` implementation doesn't access any of the interior mutable types.
+ /// However, this lint is unable to recognize this, so it causes a false positive in theses cases.
+ /// The `bytes` crate is a great example of this.
///
/// **Example:**
/// ```rust
// We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
// generics (because the compiler cannot ensure immutability for unknown types).
fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
- let ty = walk_ptrs_ty(ty);
+ let ty = ty.peel_refs();
if let Adt(def, substs) = ty.kind() {
if [&paths::HASHMAP, &paths::BTREEMAP, &paths::HASHSET, &paths::BTREESET]
.iter()
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp};
+use rustc_infer::traits::specialization_graph;
use rustc_lint::{LateContext, LateLintPass, Lint};
use rustc_middle::ty::adjustment::Adjust;
-use rustc_middle::ty::{Ty, TypeFlags};
+use rustc_middle::ty::{AssocKind, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{InnerSpan, Span, DUMMY_SP};
use rustc_typeck::hir_ty_to_ty;
-use crate::utils::{in_constant, is_copy, qpath_res, span_lint_and_then};
+use crate::utils::{in_constant, qpath_res, span_lint_and_then};
+use if_chain::if_chain;
declare_clippy_lint! {
/// **What it does:** Checks for declaration of `const` items which is interior
"referencing `const` with interior mutability"
}
-#[allow(dead_code)]
#[derive(Copy, Clone)]
enum Source {
Item { item: Span },
- Assoc { item: Span, ty: Span },
+ Assoc { item: Span },
Expr { expr: Span },
}
}
fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) {
- if ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) || is_copy(cx, ty) {
- // An `UnsafeCell` is `!Copy`, and an `UnsafeCell` is also the only type which
- // is `!Freeze`, thus if our type is `Copy` we can be sure it must be `Freeze`
- // as well.
+ // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
+ // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
+ // 'unfrozen'. However, this code causes a false negative in which
+ // a type contains a layout-unknown type, but also a unsafe cell like `const CELL: Cell<T>`.
+ // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)`
+ // since it works when a pointer indirection involves (`Cell<*const T>`).
+ // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
+ // but I'm not sure whether it's a decent way, if possible.
+ if cx.tcx.layout_of(cx.param_env.and(ty)).is_err() || ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) {
return;
}
let const_kw_span = span.from_inner(InnerSpan::new(0, 5));
diag.span_label(const_kw_span, "make this a static item (maybe with lazy_static)");
},
- Source::Assoc { ty: ty_span, .. } => {
- if ty.flags().intersects(TypeFlags::HAS_FREE_LOCAL_NAMES) {
- diag.span_label(ty_span, &format!("consider requiring `{}` to be `Copy`", ty));
- }
- },
+ Source::Assoc { .. } => (),
Source::Expr { .. } => {
diag.help("assign this const to a local or static variable, and use the variable here");
},
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) {
if let TraitItemKind::Const(hir_ty, ..) = &trait_item.kind {
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
- verify_ty_bound(
- cx,
- ty,
- Source::Assoc {
- ty: hir_ty.span,
- item: trait_item.span,
- },
- );
+ // Normalize assoc types because ones originated from generic params
+ // bounded other traits could have their bound.
+ let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
+ verify_ty_bound(cx, normalized, Source::Assoc { item: trait_item.span });
}
}
if let ImplItemKind::Const(hir_ty, ..) = &impl_item.kind {
let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id);
let item = cx.tcx.hir().expect_item(item_hir_id);
- // Ensure the impl is an inherent impl.
- if let ItemKind::Impl { of_trait: None, .. } = item.kind {
- let ty = hir_ty_to_ty(cx.tcx, hir_ty);
- verify_ty_bound(
- cx,
- ty,
- Source::Assoc {
- ty: hir_ty.span,
- item: impl_item.span,
- },
- );
+
+ match &item.kind {
+ ItemKind::Impl {
+ of_trait: Some(of_trait_ref),
+ ..
+ } => {
+ if_chain! {
+ // Lint a trait impl item only when the definition is a generic type,
+ // assuming a assoc const is not meant to be a interior mutable type.
+ if let Some(of_trait_def_id) = of_trait_ref.trait_def_id();
+ if let Some(of_assoc_item) = specialization_graph::Node::Trait(of_trait_def_id)
+ .item(cx.tcx, impl_item.ident, AssocKind::Const, of_trait_def_id);
+ if cx
+ .tcx
+ .layout_of(cx.tcx.param_env(of_trait_def_id).and(
+ // Normalize assoc types because ones originated from generic params
+ // bounded other traits could have their bound at the trait defs;
+ // and, in that case, the definition is *not* generic.
+ cx.tcx.normalize_erasing_regions(
+ cx.tcx.param_env(of_trait_def_id),
+ cx.tcx.type_of(of_assoc_item.def_id),
+ ),
+ ))
+ .is_err();
+ then {
+ let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+ let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
+ verify_ty_bound(
+ cx,
+ normalized,
+ Source::Assoc {
+ item: impl_item.span,
+ },
+ );
+ }
+ }
+ },
+ ItemKind::Impl { of_trait: None, .. } => {
+ let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+ // Normalize assoc types originated from generic params.
+ let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
+ verify_ty_bound(cx, normalized, Source::Assoc { item: impl_item.span });
+ },
+ _ => (),
}
}
}
-use crate::utils::{match_type, paths, span_lint, walk_ptrs_ty};
+use crate::utils::{match_type, paths, span_lint};
use rustc_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
impl<'tcx> LateLintPass<'tcx> for OpenOptions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if let ExprKind::MethodCall(ref path, _, ref arguments, _) = e.kind {
- let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&arguments[0]));
+ let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs();
if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) {
let mut options = Vec::new();
get_open_options(cx, &arguments[0], &mut options);
fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
if let ExprKind::MethodCall(ref path, _, ref arguments, _) = argument.kind {
- let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&arguments[0]));
+ let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs();
// Only proceed if this is a call on some object of type std::fs::OpenOptions
if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 {
use crate::utils;
+use crate::utils::eager_or_lazy;
use crate::utils::sugg::Sugg;
-use crate::utils::{match_type, paths, span_lint_and_sugg};
+use crate::utils::{is_type_diagnostic_item, paths, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
declare_clippy_lint! {
/// **What it does:**
/// Lints usage of `if let Some(v) = ... { y } else { x }` which is more
- /// idiomatically done with `Option::map_or` (if the else bit is a simple
- /// expression) or `Option::map_or_else` (if the else bit is a longer
- /// block).
+ /// idiomatically done with `Option::map_or` (if the else bit is a pure
+ /// expression) or `Option::map_or_else` (if the else bit is an impure
+ /// expresion).
///
/// **Why is this bad?**
/// Using the dedicated functions of the Option type is clearer and
/// more concise than an if let expression.
///
/// **Known problems:**
- /// This lint uses whether the block is just an expression or if it has
- /// more statements to decide whether to use `Option::map_or` or
- /// `Option::map_or_else`. If you have a single expression which calls
- /// an expensive function, then it would be more efficient to use
- /// `Option::map_or_else`, but this lint would suggest `Option::map_or`.
- ///
- /// Also, this lint uses a deliberately conservative metric for checking
+ /// This lint uses a deliberately conservative metric for checking
/// if the inside of either body contains breaks or continues which will
/// cause it to not suggest a fix if either block contains a loop with
/// continues or breaks contained within the loop.
fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind {
path.ident.name.to_ident_string() == "ok"
- && match_type(cx, &cx.typeck_results().expr_ty(&receiver), &paths::RESULT)
+ && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym!(result_type))
} else {
false
}
struct ReturnBreakContinueMacroVisitor {
seen_return_break_continue: bool,
}
+
impl ReturnBreakContinueMacroVisitor {
fn new() -> ReturnBreakContinueMacroVisitor {
ReturnBreakContinueMacroVisitor {
}
}
}
+
impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
}
/// If this is the else body of an if/else expression, then we need to wrap
-/// it in curcly braces. Otherwise, we don't.
+/// it in curly braces. Otherwise, we don't.
fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
utils::get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| {
if let Some(Expr {
/// If this expression is the option if let/else construct we're detecting, then
/// this function returns an `OptionIfLetElseOccurence` struct with details if
/// this construct is found, or None if this construct is not found.
-fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OptionIfLetElseOccurence> {
+fn detect_option_if_let_else<'tcx>(
+ cx: &'_ LateContext<'tcx>,
+ expr: &'_ Expr<'tcx>,
+) -> Option<OptionIfLetElseOccurence> {
if_chain! {
if !utils::in_macro(expr.span); // Don't lint macros, because it behaves weirdly
if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind;
let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
let some_body = extract_body_from_arm(&arms[0])?;
let none_body = extract_body_from_arm(&arms[1])?;
- let method_sugg = match &none_body.kind {
- ExprKind::Block(..) => "map_or_else",
- _ => "map_or",
- };
+ let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { "map_or" } else { "map_or_else" };
let capture_name = id.name.to_ident_string();
let wrap_braces = should_wrap_in_braces(cx, expr);
let (as_ref, as_mut) = match &cond_expr.kind {
}
}
-impl<'a> LateLintPass<'a> for OptionIfLetElse {
- fn check_expr(&mut self, cx: &LateContext<'a>, expr: &Expr<'_>) {
+impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
if let Some(detection) = detect_option_if_let_else(cx, expr) {
span_lint_and_sugg(
cx,
--- /dev/null
+use crate::utils::{is_expn_of, is_type_diagnostic_item, return_ty, span_lint_and_then};
+use rustc_hir as hir;
+use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::Map;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+ /// **What it does:** Checks for usage of `panic!`, `unimplemented!`, `todo!` or `unreachable!` in a function of type result.
+ ///
+ /// **Why is this bad?** For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence unimplemented, panic and unreachable should be avoided.
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ ///
+ /// ```rust
+ /// fn result_with_panic() -> Result<bool, String>
+ /// {
+ /// panic!("error");
+ /// }
+ /// ```
+ pub PANIC_IN_RESULT_FN,
+ restriction,
+ "functions of type `Result<..>` that contain `panic!()`, `todo!()` or `unreachable()` or `unimplemented()` "
+}
+
+declare_lint_pass!(PanicInResultFn => [PANIC_IN_RESULT_FN]);
+
+impl<'tcx> LateLintPass<'tcx> for PanicInResultFn {
+ fn check_fn(
+ &mut self,
+ cx: &LateContext<'tcx>,
+ fn_kind: FnKind<'tcx>,
+ _: &'tcx hir::FnDecl<'tcx>,
+ body: &'tcx hir::Body<'tcx>,
+ span: Span,
+ hir_id: hir::HirId,
+ ) {
+ if !matches!(fn_kind, FnKind::Closure(_))
+ && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type))
+ {
+ lint_impl_body(cx, span, body);
+ }
+ }
+}
+
+struct FindPanicUnimplementedUnreachable {
+ result: Vec<Span>,
+}
+
+impl<'tcx> Visitor<'tcx> for FindPanicUnimplementedUnreachable {
+ type Map = Map<'tcx>;
+
+ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
+ if ["unimplemented", "unreachable", "panic", "todo"]
+ .iter()
+ .any(|fun| is_expn_of(expr.span, fun).is_some())
+ {
+ self.result.push(expr.span);
+ }
+ // and check sub-expressions
+ intravisit::walk_expr(self, expr);
+ }
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::None
+ }
+}
+
+fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) {
+ let mut panics = FindPanicUnimplementedUnreachable { result: Vec::new() };
+ panics.visit_expr(&body.value);
+ if !panics.result.is_empty() {
+ span_lint_and_then(
+ cx,
+ PANIC_IN_RESULT_FN,
+ impl_span,
+ "used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`",
+ move |diag| {
+ diag.help(
+ "`unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing",
+ );
+ diag.span_note(panics.result, "return Err() instead of panicking");
+ },
+ );
+ }
+}
-use crate::utils::{match_type, paths, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{match_type, paths, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
if path.ident.name == sym!(push);
if args.len() == 2;
- if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &paths::PATH_BUF);
+ if match_type(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), &paths::PATH_BUF);
if let Some(get_index_arg) = args.get(1);
if let ExprKind::Lit(ref lit) = get_index_arg.kind;
if let LitKind::Str(ref path_lit, _) = lit.node;
);
let mut app = Applicability::MaybeIncorrect;
- let mut call_snip = &snip[dot + 1..];
+ let call_snip = &snip[dot + 1..];
// Machine applicable when `call_snip` looks like `foobar()`
- if call_snip.ends_with("()") {
- call_snip = call_snip[..call_snip.len()-2].trim();
+ if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) {
if call_snip.as_bytes().iter().all(|b| b.is_ascii_alphabetic() || *b == b'_') {
app = Applicability::MachineApplicable;
}
use crate::consts::{constant_context, Constant};
-use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&count);
if !in_macro(receiver.span);
then {
- let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&receiver));
+ let ty = cx.typeck_results().expr_ty(&receiver).peel_refs();
if ty.is_str() {
span_lint_and_sugg(
cx,
/// **Example:**
/// ```rust
/// # let x = 1;
- ///
/// // Bad
/// let x = &x;
///
/// names to bindings or introducing more scopes to contain the bindings.
///
/// **Known problems:** This lint, as the other shadowing related lints,
- /// currently only catches very simple patterns.
+ /// currently only catches very simple patterns. Note that
+ /// `allow`/`warn`/`deny`/`forbid` attributes only work on the function level
+ /// for this lint.
///
/// **Example:**
/// ```rust
use if_chain::if_chain;
use crate::utils::SpanlessEq;
-use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg};
declare_clippy_lint! {
/// **What it does:** Checks for string appends of the form `x = x + y` (without
}
fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
- is_type_diagnostic_item(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(e)), sym!(string_type))
+ is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym!(string_type))
}
fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
use crate::utils::sugg::Sugg;
use crate::utils::{
differing_macro_contexts, eq_expr_value, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_then,
- walk_ptrs_ty,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind {
if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind {
if eq_expr_value(cx, lhs1, lhs2) {
- let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(lhs1));
+ let ty = cx.typeck_results().expr_ty(lhs1).peel_refs();
if matches!(ty.kind(), ty::Slice(_))
|| matches!(ty.kind(), ty::Array(_, _))
"redundant allocation"
}
+declare_clippy_lint! {
+ /// **What it does:** Checks for Rc<T> and Arc<T> when T is a mutable buffer type such as String or Vec
+ ///
+ /// **Why is this bad?** Expressions such as Rc<String> have no advantage over Rc<str>, since
+ /// it is larger and involves an extra level of indirection, and doesn't implement Borrow<str>.
+ ///
+ /// While mutating a buffer type would still be possible with Rc::get_mut(), it only
+ /// works if there are no additional references yet, which defeats the purpose of
+ /// enclosing it in a shared ownership type. Instead, additionally wrapping the inner
+ /// type with an interior mutable container (such as RefCell or Mutex) would normally
+ /// be used.
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ /// ```rust,ignore
+ /// # use std::rc::Rc;
+ /// fn foo(interned: Rc<String>) { ... }
+ /// ```
+ ///
+ /// Better:
+ ///
+ /// ```rust,ignore
+ /// fn foo(interned: Rc<str>) { ... }
+ /// ```
+ pub RC_BUFFER,
+ perf,
+ "shared ownership of a buffer type"
+}
+
pub struct Types {
vec_box_size_threshold: u64,
}
-impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION]);
+impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER]);
impl<'tcx> LateLintPass<'tcx> for Types {
fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
None
}
+fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
+ if match_type_parameter(cx, qpath, &paths::STRING).is_some() {
+ return Some("str");
+ }
+ if match_type_parameter(cx, qpath, &paths::OS_STRING).is_some() {
+ return Some("std::ffi::OsStr");
+ }
+ if match_type_parameter(cx, qpath, &paths::PATH_BUF).is_some() {
+ return Some("std::path::Path");
+ }
+ None
+}
+
fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Span> {
let last = last_path_segment(qpath);
if_chain! {
if let Some(def_id) = res.opt_def_id() {
if Some(def_id) == cx.tcx.lang_items().owned_box() {
if let Some(span) = match_borrows_parameter(cx, qpath) {
+ let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
REDUNDANT_ALLOCATION,
hir_ty.span,
"usage of `Box<&T>`",
"try",
- snippet(cx, span, "..").to_string(),
- Applicability::MachineApplicable,
+ snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
+ applicability,
);
return; // don't recurse into the type
}
}
} else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
if let Some(span) = match_type_parameter(cx, qpath, &paths::RC) {
+ let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
REDUNDANT_ALLOCATION,
hir_ty.span,
"usage of `Rc<Rc<T>>`",
"try",
- snippet(cx, span, "..").to_string(),
- Applicability::MachineApplicable,
+ snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
+ applicability,
);
return; // don't recurse into the type
}
GenericArg::Type(ty) => ty.span,
_ => return,
};
+ let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
REDUNDANT_ALLOCATION,
hir_ty.span,
"usage of `Rc<Box<T>>`",
"try",
- format!("Rc<{}>", snippet(cx, inner_span, "..")),
+ format!(
+ "Rc<{}>",
+ snippet_with_applicability(cx, inner_span, "..", &mut applicability)
+ ),
+ applicability,
+ );
+ return; // don't recurse into the type
+ }
+ if let Some(alternate) = match_buffer_type(cx, qpath) {
+ span_lint_and_sugg(
+ cx,
+ RC_BUFFER,
+ hir_ty.span,
+ "usage of `Rc<T>` when T is a buffer type",
+ "try",
+ format!("Rc<{}>", alternate),
+ Applicability::MachineApplicable,
+ );
+ return; // don't recurse into the type
+ }
+ if match_type_parameter(cx, qpath, &paths::VEC).is_some() {
+ let vec_ty = match &last_path_segment(qpath).args.unwrap().args[0] {
+ GenericArg::Type(ty) => match &ty.kind {
+ TyKind::Path(qpath) => qpath,
+ _ => return,
+ },
+ _ => return,
+ };
+ let inner_span = match &last_path_segment(&vec_ty).args.unwrap().args[0] {
+ GenericArg::Type(ty) => ty.span,
+ _ => return,
+ };
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ RC_BUFFER,
+ hir_ty.span,
+ "usage of `Rc<T>` when T is a buffer type",
+ "try",
+ format!(
+ "Rc<[{}]>",
+ snippet_with_applicability(cx, inner_span, "..", &mut applicability)
+ ),
Applicability::MachineApplicable,
);
return; // don't recurse into the type
}
if let Some(span) = match_borrows_parameter(cx, qpath) {
+ let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
REDUNDANT_ALLOCATION,
hir_ty.span,
"usage of `Rc<&T>`",
"try",
- snippet(cx, span, "..").to_string(),
+ snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
+ applicability,
+ );
+ return; // don't recurse into the type
+ }
+ } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) {
+ if let Some(alternate) = match_buffer_type(cx, qpath) {
+ span_lint_and_sugg(
+ cx,
+ RC_BUFFER,
+ hir_ty.span,
+ "usage of `Arc<T>` when T is a buffer type",
+ "try",
+ format!("Arc<{}>", alternate),
+ Applicability::MachineApplicable,
+ );
+ return; // don't recurse into the type
+ }
+ if match_type_parameter(cx, qpath, &paths::VEC).is_some() {
+ let vec_ty = match &last_path_segment(qpath).args.unwrap().args[0] {
+ GenericArg::Type(ty) => match &ty.kind {
+ TyKind::Path(qpath) => qpath,
+ _ => return,
+ },
+ _ => return,
+ };
+ let inner_span = match &last_path_segment(&vec_ty).args.unwrap().args[0] {
+ GenericArg::Type(ty) => ty.span,
+ _ => return,
+ };
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ RC_BUFFER,
+ hir_ty.span,
+ "usage of `Arc<T>` when T is a buffer type",
+ "try",
+ format!(
+ "Arc<[{}]>",
+ snippet_with_applicability(cx, inner_span, "..", &mut applicability)
+ ),
Applicability::MachineApplicable,
);
return; // don't recurse into the type
// details.
return;
}
- let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
BORROWED_BOX,
format!(
"&{}{}",
ltopt,
- &snippet_with_applicability(cx, inner.span, "..", &mut applicability)
+ &snippet(cx, inner.span, "..")
),
+ // To make this `MachineApplicable`, at least one needs to check if it isn't a trait item
+ // because the trait impls of it will break otherwise;
+ // and there may be other cases that result in invalid code.
+ // For example, type coercion doesn't work nicely.
Applicability::Unspecified,
);
return; // don't recurse into the type
-use crate::utils::{is_type_diagnostic_item, method_chain_args, return_ty, span_lint_and_then, walk_ptrs_ty};
+use crate::utils::{is_type_diagnostic_item, method_chain_args, return_ty, span_lint_and_then};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
// check for `expect`
if let Some(arglists) = method_chain_args(expr, &["expect"]) {
- let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0]));
+ let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
|| is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
{
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
- let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0]));
+ let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
|| is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
{
cx,
USELESS_CONVERSION,
e.span,
- "useless conversion to the same type",
+ &format!("useless conversion to the same type: `{}`", b),
"consider removing `.into()`",
sugg,
Applicability::MachineApplicable, // snippet
cx,
USELESS_CONVERSION,
e.span,
- "useless conversion to the same type",
+ &format!("useless conversion to the same type: `{}`", b),
"consider removing `.into_iter()`",
sugg,
Applicability::MachineApplicable, // snippet
cx,
USELESS_CONVERSION,
e.span,
- "useless conversion to the same type",
+ &format!("useless conversion to the same type: `{}`", b),
None,
"consider removing `.try_into()`",
);
cx,
USELESS_CONVERSION,
e.span,
- "useless conversion to the same type",
+ &format!("useless conversion to the same type: `{}`", b),
None,
&hint,
);
cx,
USELESS_CONVERSION,
e.span,
- "useless conversion to the same type",
+ &format!("useless conversion to the same type: `{}`", b),
&sugg_msg,
sugg.to_string(),
Applicability::MachineApplicable, // snippet
///
/// The `help` message can be optionally attached to a `Span`.
///
+/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
+///
/// # Example
///
/// ```ignore
/// The `note` message is presented separately from the main lint message
/// and is attached to a specific span:
///
+/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
+///
/// # Example
///
/// ```ignore
/// Like `span_lint` but allows to add notes, help and suggestions using a closure.
///
/// If you need to customize your lint output a lot, use this function.
+/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
where
F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x >
/// 2)"`.
///
+/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
+///
+/// # Example
+///
/// ```ignore
/// error: This `.fold` can be more succinctly expressed as `.any`
/// --> $DIR/methods.rs:390:13
--- /dev/null
+//! Utilities for evaluating whether eagerly evaluated expressions can be made lazy and vice versa.
+//!
+//! Things to consider:
+//! - has the expression side-effects?
+//! - is the expression computationally expensive?
+//!
+//! See lints:
+//! - unnecessary-lazy-evaluations
+//! - or-fun-call
+//! - option-if-let-else
+
+use crate::utils::is_ctor_or_promotable_const_function;
+use rustc_hir::def::{DefKind, Res};
+
+use rustc_hir::intravisit;
+use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
+
+use rustc_hir::{Block, Expr, ExprKind, Path, QPath};
+use rustc_lint::LateContext;
+use rustc_middle::hir::map::Map;
+
+/// Is the expr pure (is it free from side-effects)?
+/// This function is named so to stress that it isn't exhaustive and returns FNs.
+fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool {
+ match expr.kind {
+ ExprKind::Lit(..) | ExprKind::Path(..) | ExprKind::Field(..) => true,
+ ExprKind::AddrOf(_, _, addr_of_expr) => identify_some_pure_patterns(addr_of_expr),
+ ExprKind::Tup(tup_exprs) => tup_exprs.iter().all(|expr| identify_some_pure_patterns(expr)),
+ ExprKind::Struct(_, fields, expr) => {
+ fields.iter().all(|f| identify_some_pure_patterns(f.expr))
+ && expr.map_or(true, |e| identify_some_pure_patterns(e))
+ },
+ ExprKind::Call(
+ &Expr {
+ kind:
+ ExprKind::Path(QPath::Resolved(
+ _,
+ Path {
+ res: Res::Def(DefKind::Ctor(..) | DefKind::Variant, ..),
+ ..
+ },
+ )),
+ ..
+ },
+ args,
+ ) => args.iter().all(|expr| identify_some_pure_patterns(expr)),
+ ExprKind::Block(
+ &Block {
+ stmts,
+ expr: Some(expr),
+ ..
+ },
+ _,
+ ) => stmts.is_empty() && identify_some_pure_patterns(expr),
+ ExprKind::Box(..)
+ | ExprKind::Array(..)
+ | ExprKind::Call(..)
+ | ExprKind::MethodCall(..)
+ | ExprKind::Binary(..)
+ | ExprKind::Unary(..)
+ | ExprKind::Cast(..)
+ | ExprKind::Type(..)
+ | ExprKind::DropTemps(..)
+ | ExprKind::Loop(..)
+ | ExprKind::Match(..)
+ | ExprKind::Closure(..)
+ | ExprKind::Block(..)
+ | ExprKind::Assign(..)
+ | ExprKind::AssignOp(..)
+ | ExprKind::Index(..)
+ | ExprKind::Break(..)
+ | ExprKind::Continue(..)
+ | ExprKind::Ret(..)
+ | ExprKind::InlineAsm(..)
+ | ExprKind::LlvmInlineAsm(..)
+ | ExprKind::Repeat(..)
+ | ExprKind::Yield(..)
+ | ExprKind::Err => false,
+ }
+}
+
+/// Identify some potentially computationally expensive patterns.
+/// This function is named so to stress that its implementation is non-exhaustive.
+/// It returns FNs and FPs.
+fn identify_some_potentially_expensive_patterns<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+ // Searches an expression for method calls or function calls that aren't ctors
+ struct FunCallFinder<'a, 'tcx> {
+ cx: &'a LateContext<'tcx>,
+ found: bool,
+ }
+
+ impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> {
+ type Map = Map<'tcx>;
+
+ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+ let call_found = match &expr.kind {
+ // ignore enum and struct constructors
+ ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr),
+ ExprKind::MethodCall(..) => true,
+ _ => false,
+ };
+
+ if call_found {
+ self.found |= true;
+ }
+
+ if !self.found {
+ intravisit::walk_expr(self, expr);
+ }
+ }
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::None
+ }
+ }
+
+ let mut finder = FunCallFinder { cx, found: false };
+ finder.visit_expr(expr);
+ finder.found
+}
+
+pub fn is_eagerness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+ !identify_some_potentially_expensive_patterns(cx, expr) && identify_some_pure_patterns(expr)
+}
+
+pub fn is_lazyness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+ identify_some_potentially_expensive_patterns(cx, expr)
+}
use crate::utils::{
- is_expn_of, match_def_path, match_qpath, match_type, method_calls, paths, run_lints, snippet, span_lint,
- span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty, SpanlessEq,
+ is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, qpath_res, run_lints,
+ snippet, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq,
};
use if_chain::if_chain;
use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
-use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Path, StmtKind, Ty, TyKind};
+use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Node, Path, StmtKind, Ty, TyKind};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
"found collapsible `span_lint_and_then` calls"
}
+declare_clippy_lint! {
+ /// **What it does:** Checks for calls to `utils::match_type()` on a type diagnostic item
+ /// and suggests to use `utils::is_type_diagnostic_item()` instead.
+ ///
+ /// **Why is this bad?** `utils::is_type_diagnostic_item()` does not require hardcoded paths.
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ /// Bad:
+ /// ```rust,ignore
+ /// utils::match_type(cx, ty, &paths::VEC)
+ /// ```
+ ///
+ /// Good:
+ /// ```rust,ignore
+ /// utils::is_type_diagnostic_item(cx, ty, sym!(vec_type))
+ /// ```
+ pub MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
+ internal,
+ "using `utils::match_type()` instead of `utils::is_type_diagnostic_item()`"
+}
+
declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
impl EarlyLintPass for ClippyLintsInternal {
if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
let fn_name = path.ident;
if let Some(sugg) = self.map.get(&*fn_name.as_str());
- let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
+ let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
if match_type(cx, ty, &paths::EARLY_CONTEXT)
|| match_type(cx, ty, &paths::LATE_CONTEXT);
then {
let args = arg_lists[1];
if args.len() == 1;
let self_arg = &args[0];
- let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(self_arg));
+ let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
then {
span_lint_and_sugg(
Applicability::MachineApplicable,
);
}
+
+declare_lint_pass!(MatchTypeOnDiagItem => [MATCH_TYPE_ON_DIAGNOSTIC_ITEM]);
+
+impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+ if !run_lints(cx, &[MATCH_TYPE_ON_DIAGNOSTIC_ITEM], expr.hir_id) {
+ return;
+ }
+
+ if_chain! {
+ // Check if this is a call to utils::match_type()
+ if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind;
+ if let ExprKind::Path(fn_qpath) = &fn_path.kind;
+ if match_qpath(&fn_qpath, &["utils", "match_type"]);
+ // Extract the path to the matched type
+ if let Some(segments) = path_to_matched_type(cx, ty_path);
+ let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
+ if let Some(ty_did) = path_to_res(cx, &segments[..]).and_then(|res| res.opt_def_id());
+ // Check if the matched type is a diagnostic item
+ let diag_items = cx.tcx.diagnostic_items(ty_did.krate);
+ if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None });
+ then {
+ let cx_snippet = snippet(cx, context.span, "_");
+ let ty_snippet = snippet(cx, ty.span, "_");
+
+ span_lint_and_sugg(
+ cx,
+ MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
+ expr.span,
+ "usage of `utils::match_type()` on a type diagnostic item",
+ "try",
+ format!("utils::is_type_diagnostic_item({}, {}, sym!({}))", cx_snippet, ty_snippet, item_name),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+}
+
+fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<SymbolStr>> {
+ use rustc_hir::ItemKind;
+
+ match &expr.kind {
+ ExprKind::AddrOf(.., expr) => return path_to_matched_type(cx, expr),
+ ExprKind::Path(qpath) => match qpath_res(cx, qpath, expr.hir_id) {
+ Res::Local(hir_id) => {
+ let parent_id = cx.tcx.hir().get_parent_node(hir_id);
+ if let Some(Node::Local(local)) = cx.tcx.hir().find(parent_id) {
+ if let Some(init) = local.init {
+ return path_to_matched_type(cx, init);
+ }
+ }
+ },
+ Res::Def(DefKind::Const | DefKind::Static, def_id) => {
+ if let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(def_id) {
+ if let ItemKind::Const(.., body_id) | ItemKind::Static(.., body_id) = item.kind {
+ let body = cx.tcx.hir().body(body_id);
+ return path_to_matched_type(cx, &body.value);
+ }
+ }
+ },
+ _ => {},
+ },
+ ExprKind::Array(exprs) => {
+ let segments: Vec<SymbolStr> = exprs
+ .iter()
+ .filter_map(|expr| {
+ if let ExprKind::Lit(lit) = &expr.kind {
+ if let LitKind::Str(sym, _) = lit.node {
+ return Some(sym.as_str());
+ }
+ }
+
+ None
+ })
+ .collect();
+
+ if segments.len() == exprs.len() {
+ return Some(segments);
+ }
+ },
+ _ => {},
+ }
+
+ None
+}
pub mod conf;
pub mod constants;
mod diagnostics;
+pub mod eager_or_lazy;
pub mod higher;
mod hir_utils;
pub mod inspector;
}
/// Checks if type is struct, enum or union type with the given def path.
+///
+/// If the type is a diagnostic item, use `is_type_diagnostic_item` instead.
+/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
match ty.kind() {
ty::Adt(adt, _) => match_def_path(cx, adt.did, path),
}
/// Checks if the type is equal to a diagnostic item
+///
+/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
match ty.kind() {
ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did),
}
}
-/// Returns the base type for references and raw pointers.
-pub fn walk_ptrs_ty(ty: Ty<'_>) -> Ty<'_> {
- match ty.kind() {
- ty::Ref(_, ty, _) => walk_ptrs_ty(ty),
- _ => ty,
- }
-}
-
/// Returns the base type for references and raw pointers, and count reference
/// depth.
pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"];
pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"];
+pub const STRING: [&str; 3] = ["alloc", "string", "String"];
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
+pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"];
+pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
+pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"];
pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
/// Convenience function around `hir_opt` for suggestions with a default
/// text.
pub fn hir(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self {
- Self::hir_opt(cx, expr).unwrap_or_else(|| Sugg::NonParen(Cow::Borrowed(default)))
+ Self::hir_opt(cx, expr).unwrap_or(Sugg::NonParen(Cow::Borrowed(default)))
}
/// Same as `hir`, but it adapts the applicability level by following rules:
use crate::utils::match_var;
use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
use rustc_hir::def::Res;
+use rustc_hir::intravisit;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{Expr, HirId, Path};
use rustc_infer::infer::TyCtxtInferExt;
walk_expr(&mut visitor, body);
!visitor.used
}
+
+pub struct ParamBindingIdCollector {
+ binding_hir_ids: Vec<hir::HirId>,
+}
+impl<'tcx> ParamBindingIdCollector {
+ fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec<hir::HirId> {
+ let mut finder = ParamBindingIdCollector {
+ binding_hir_ids: Vec::new(),
+ };
+ finder.visit_body(body);
+ finder.binding_hir_ids
+ }
+}
+impl<'tcx> intravisit::Visitor<'tcx> for ParamBindingIdCollector {
+ type Map = Map<'tcx>;
+
+ fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
+ if let hir::PatKind::Binding(_, hir_id, ..) = param.pat.kind {
+ self.binding_hir_ids.push(hir_id);
+ }
+ }
+
+ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+ intravisit::NestedVisitorMap::None
+ }
+}
+
+pub struct BindingUsageFinder<'a, 'tcx> {
+ cx: &'a LateContext<'tcx>,
+ binding_ids: Vec<hir::HirId>,
+ usage_found: bool,
+}
+impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> {
+ pub fn are_params_used(cx: &'a LateContext<'tcx>, body: &'tcx hir::Body<'tcx>) -> bool {
+ let mut finder = BindingUsageFinder {
+ cx,
+ binding_ids: ParamBindingIdCollector::collect_binding_hir_ids(body),
+ usage_found: false,
+ };
+ finder.visit_body(body);
+ finder.usage_found
+ }
+}
+impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
+ type Map = Map<'tcx>;
+
+ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+ if !self.usage_found {
+ intravisit::walk_expr(self, expr);
+ }
+ }
+
+ fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
+ if let hir::def::Res::Local(id) = path.res {
+ if self.binding_ids.contains(&id) {
+ self.usage_found = true;
+ }
+ }
+ }
+
+ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+ intravisit::NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+ }
+}
}
/// Given a format string that ends in a newline and its span, calculates the span of the
-/// newline.
+/// newline, or the format string itself if the format string consists solely of a newline.
fn newline_span(fmtstr: &StrLit) -> Span {
let sp = fmtstr.span;
let contents = &fmtstr.symbol.as_str();
+ if *contents == r"\n" {
+ return sp;
+ }
+
let newline_sp_hi = sp.hi()
- match fmtstr.style {
StrStyle::Cooked => BytePos(1),
While most of Clippy's lint utils are documented, most of rustc's internals lack
documentation currently. This is unfortunate, but in most cases you can probably
get away with copying things from existing similar lints. If you are stuck,
-don't hesitate to ask on [Discord] or in the issue/PR.
+don't hesitate to ask on [Zulip] or in the issue/PR.
[utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/mod.rs
[if_chain]: https://docs.rs/if_chain/*/if_chain/
[nightly_docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/
[ast]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/index.html
[ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/index.html
-[Discord]: https://discord.gg/rust-lang
+[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/clippy
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if_chain! {
// Check our expr is calling a method
- if let hir::ExprKind::MethodCall(path, _, _args) = &expr.kind;
+ if let hir::ExprKind::MethodCall(path, _, _args, _) = &expr.kind;
// Check the name of this method is `some_method`
if path.ident.name == sym!(some_method);
then {
Lint {
name: "invalid_atomic_ordering",
group: "correctness",
- desc: "usage of invalid atomic ordering in atomic loads/stores and memory fences",
+ desc: "usage of invalid atomic ordering in atomic operations and memory fences",
deprecation: None,
module: "atomic_ordering",
},
deprecation: None,
module: "methods",
},
+ Lint {
+ name: "manual_strip",
+ group: "complexity",
+ desc: "suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing",
+ deprecation: None,
+ module: "manual_strip",
+ },
Lint {
name: "manual_swap",
group: "complexity",
deprecation: None,
module: "entry",
},
+ Lint {
+ name: "map_err_ignore",
+ group: "pedantic",
+ desc: "`map_err` should not ignore the original error",
+ deprecation: None,
+ module: "map_err_ignore",
+ },
Lint {
name: "map_flatten",
group: "pedantic",
deprecation: None,
module: "panic_unimplemented",
},
+ Lint {
+ name: "panic_in_result_fn",
+ group: "restriction",
+ desc: "functions of type `Result<..>` that contain `panic!()`, `todo!()` or `unreachable()` or `unimplemented()` ",
+ deprecation: None,
+ module: "panic_in_result_fn",
+ },
Lint {
name: "panic_params",
group: "style",
deprecation: None,
module: "ranges",
},
+ Lint {
+ name: "rc_buffer",
+ group: "perf",
+ desc: "shared ownership of a buffer type",
+ deprecation: None,
+ module: "types",
+ },
Lint {
name: "redundant_allocation",
group: "perf",
},
Lint {
name: "verbose_bit_mask",
- group: "style",
+ group: "pedantic",
desc: "expressions where a bit mask is less readable than the corresponding method call",
deprecation: None,
module: "bit_mask",
--- /dev/null
+#![warn(clippy::invalid_atomic_ordering)]
+
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+fn main() {
+ // `compare_exchange` (not weak) testing
+ let x = AtomicUsize::new(0);
+
+ // Allowed ordering combos
+ let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Relaxed);
+ let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Acquire);
+ let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Relaxed);
+ let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Relaxed);
+ let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Acquire);
+ let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Relaxed);
+ let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Relaxed);
+ let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Acquire);
+ let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::SeqCst);
+
+ // AcqRel is always forbidden as a failure ordering
+ let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::AcqRel);
+ let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::AcqRel);
+ let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::AcqRel);
+ let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::AcqRel);
+ let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::AcqRel);
+
+ // Release is always forbidden as a failure ordering
+ let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Release);
+ let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Release);
+ let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Release);
+ let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Release);
+ let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Release);
+
+ // Release success order forbids failure order of Acquire or SeqCst
+ let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Acquire);
+ let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::SeqCst);
+
+ // Relaxed success order also forbids failure order of Acquire or SeqCst
+ let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::SeqCst);
+ let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Acquire);
+
+ // Acquire/AcqRel forbids failure order of SeqCst
+ let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::SeqCst);
+ let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::SeqCst);
+}
--- /dev/null
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange.rs:21:57
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::AcqRel);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings`
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange.rs:22:57
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::AcqRel);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange.rs:23:57
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::AcqRel);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange.rs:24:56
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::AcqRel);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange.rs:25:56
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::AcqRel);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange.rs:28:57
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Release);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange.rs:29:57
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Release);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange.rs:30:57
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Release);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange.rs:31:56
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Release);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange.rs:32:56
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Release);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be stronger than the success ordering of `Release`
+ --> $DIR/atomic_ordering_exchange.rs:35:57
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Acquire);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be stronger than the success ordering of `Release`
+ --> $DIR/atomic_ordering_exchange.rs:36:57
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::SeqCst);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be stronger than the success ordering of `Relaxed`
+ --> $DIR/atomic_ordering_exchange.rs:39:57
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::SeqCst);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be stronger than the success ordering of `Relaxed`
+ --> $DIR/atomic_ordering_exchange.rs:40:57
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Acquire);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be stronger than the success ordering of `Acquire`
+ --> $DIR/atomic_ordering_exchange.rs:43:57
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::SeqCst);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be stronger than the success ordering of `AcqRel`
+ --> $DIR/atomic_ordering_exchange.rs:44:56
+ |
+LL | let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::SeqCst);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: aborting due to 16 previous errors
+
--- /dev/null
+#![warn(clippy::invalid_atomic_ordering)]
+
+use std::sync::atomic::{AtomicPtr, Ordering};
+
+fn main() {
+ let ptr = &mut 5;
+ let ptr2 = &mut 10;
+ // `compare_exchange_weak` testing
+ let x = AtomicPtr::new(ptr);
+
+ // Allowed ordering combos
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Relaxed);
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Acquire);
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Relaxed);
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Release, Ordering::Relaxed);
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Acquire);
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Relaxed);
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Relaxed);
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Acquire);
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::SeqCst);
+
+ // AcqRel is always forbidden as a failure ordering
+ let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Relaxed, Ordering::AcqRel);
+ let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::AcqRel);
+ let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::AcqRel);
+ let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::AcqRel);
+ let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::SeqCst, Ordering::AcqRel);
+
+ // Release is always forbidden as a failure ordering
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Release);
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Release);
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Release, Ordering::Release);
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Release);
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Release);
+
+ // Release success order forbids failure order of Acquire or SeqCst
+ let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::Acquire);
+ let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::SeqCst);
+
+ // Relaxed success order also forbids failure order of Acquire or SeqCst
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::SeqCst);
+ let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Acquire);
+
+ // Acquire/AcqRel forbids failure order of SeqCst
+ let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::SeqCst);
+ let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::SeqCst);
+}
--- /dev/null
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange_weak.rs:23:67
+ |
+LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Relaxed, Ordering::AcqRel);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings`
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange_weak.rs:24:67
+ |
+LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::AcqRel);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange_weak.rs:25:67
+ |
+LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::AcqRel);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange_weak.rs:26:66
+ |
+LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::AcqRel);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange_weak.rs:27:66
+ |
+LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::SeqCst, Ordering::AcqRel);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange_weak.rs:30:67
+ |
+LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Release);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange_weak.rs:31:67
+ |
+LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Release);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange_weak.rs:32:67
+ |
+LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Release, Ordering::Release);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange_weak.rs:33:66
+ |
+LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Release);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_exchange_weak.rs:34:66
+ |
+LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Release);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Release`
+ --> $DIR/atomic_ordering_exchange_weak.rs:37:67
+ |
+LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::Acquire);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Release`
+ --> $DIR/atomic_ordering_exchange_weak.rs:38:67
+ |
+LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::SeqCst);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Relaxed`
+ --> $DIR/atomic_ordering_exchange_weak.rs:41:67
+ |
+LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::SeqCst);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Relaxed`
+ --> $DIR/atomic_ordering_exchange_weak.rs:42:67
+ |
+LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Acquire);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Acquire`
+ --> $DIR/atomic_ordering_exchange_weak.rs:45:67
+ |
+LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::SeqCst);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `AcqRel`
+ --> $DIR/atomic_ordering_exchange_weak.rs:46:66
+ |
+LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::SeqCst);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: aborting due to 16 previous errors
+
--- /dev/null
+#![warn(clippy::invalid_atomic_ordering)]
+
+use std::sync::atomic::{AtomicIsize, Ordering};
+
+fn main() {
+ // `fetch_update` testing
+ let x = AtomicIsize::new(0);
+
+ // Allowed ordering combos
+ let _ = x.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::Acquire, Ordering::Acquire, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::Acquire, Ordering::Relaxed, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::Release, Ordering::Relaxed, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::AcqRel, Ordering::Acquire, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::AcqRel, Ordering::Relaxed, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::SeqCst, Ordering::Relaxed, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::SeqCst, Ordering::Acquire, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |old| Some(old + 1));
+
+ // AcqRel is always forbidden as a failure ordering
+ let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1));
+
+ // Release is always forbidden as a failure ordering
+ let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1));
+
+ // Release success order forbids failure order of Acquire or SeqCst
+ let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1));
+
+ // Relaxed success order also forbids failure order of Acquire or SeqCst
+ let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1));
+
+ // Acquire/AcqRel forbids failure order of SeqCst
+ let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1));
+ let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1));
+}
--- /dev/null
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_fetch_update.rs:21:47
+ |
+LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings`
+ = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_fetch_update.rs:22:47
+ |
+LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_fetch_update.rs:23:47
+ |
+LL | let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_fetch_update.rs:24:46
+ |
+LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_fetch_update.rs:25:46
+ |
+LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_fetch_update.rs:28:47
+ |
+LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_fetch_update.rs:29:47
+ |
+LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_fetch_update.rs:30:47
+ |
+LL | let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_fetch_update.rs:31:46
+ |
+LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+ --> $DIR/atomic_ordering_fetch_update.rs:32:46
+ |
+LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be stronger than the success ordering of `Release`
+ --> $DIR/atomic_ordering_fetch_update.rs:35:47
+ |
+LL | let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be stronger than the success ordering of `Release`
+ --> $DIR/atomic_ordering_fetch_update.rs:36:47
+ |
+LL | let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be stronger than the success ordering of `Relaxed`
+ --> $DIR/atomic_ordering_fetch_update.rs:39:47
+ |
+LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be stronger than the success ordering of `Relaxed`
+ --> $DIR/atomic_ordering_fetch_update.rs:40:47
+ |
+LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be stronger than the success ordering of `Acquire`
+ --> $DIR/atomic_ordering_fetch_update.rs:43:47
+ |
+LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be stronger than the success ordering of `AcqRel`
+ --> $DIR/atomic_ordering_fetch_update.rs:44:46
+ |
+LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1));
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: aborting due to 16 previous errors
+
static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
const ONCE_INIT: Once = Once::new();
-trait Trait<T>: Copy {
- type NonCopyType;
+trait Trait<T> {
+ type AssocType;
const ATOMIC: AtomicUsize;
+ const INPUT: T;
+ const ASSOC: Self::AssocType;
+
+ fn function() {
+ let _ = &Self::INPUT;
+ let _ = &Self::ASSOC;
+ }
}
impl Trait<u32> for u64 {
- type NonCopyType = u16;
+ type AssocType = AtomicUsize;
const ATOMIC: AtomicUsize = AtomicUsize::new(9);
+ const INPUT: u32 = 10;
+ const ASSOC: Self::AssocType = AtomicUsize::new(11);
+
+ fn function() {
+ let _ = &Self::INPUT;
+ let _ = &Self::ASSOC; //~ ERROR interior mutability
+ }
}
// This is just a pointer that can be safely dereferended,
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:66:5
+ --> $DIR/borrow_interior_mutable_const.rs:44:18
+ |
+LL | let _ = &Self::ASSOC; //~ ERROR interior mutability
+ | ^^^^^^^^^^^
+ |
+ = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/borrow_interior_mutable_const.rs:80:5
|
LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
| ^^^^^^
|
- = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:67:16
+ --> $DIR/borrow_interior_mutable_const.rs:81:16
|
LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
| ^^^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:70:22
+ --> $DIR/borrow_interior_mutable_const.rs:84:22
|
LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
| ^^^^^^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:71:25
+ --> $DIR/borrow_interior_mutable_const.rs:85:25
|
LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
| ^^^^^^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:72:27
+ --> $DIR/borrow_interior_mutable_const.rs:86:27
|
LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
| ^^^^^^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:73:26
+ --> $DIR/borrow_interior_mutable_const.rs:87:26
|
LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
| ^^^^^^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:84:14
+ --> $DIR/borrow_interior_mutable_const.rs:98:14
|
LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
| ^^^^^^^^^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:85:14
+ --> $DIR/borrow_interior_mutable_const.rs:99:14
|
LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
| ^^^^^^^^^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:86:19
+ --> $DIR/borrow_interior_mutable_const.rs:100:19
|
LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
| ^^^^^^^^^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:87:14
+ --> $DIR/borrow_interior_mutable_const.rs:101:14
|
LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
| ^^^^^^^^^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:88:13
+ --> $DIR/borrow_interior_mutable_const.rs:102:13
|
LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
| ^^^^^^^^^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:94:13
+ --> $DIR/borrow_interior_mutable_const.rs:108:13
|
LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
| ^^^^^^^^^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:99:5
+ --> $DIR/borrow_interior_mutable_const.rs:113:5
|
LL | CELL.set(2); //~ ERROR interior mutability
| ^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:100:16
+ --> $DIR/borrow_interior_mutable_const.rs:114:16
|
LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
| ^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:113:5
+ --> $DIR/borrow_interior_mutable_const.rs:127:5
|
LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
| ^^^^^^^^^^^
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:114:16
+ --> $DIR/borrow_interior_mutable_const.rs:128:16
|
LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
| ^^^^^^^^^^^
|
= help: assign this const to a local or static variable, and use the variable here
-error: aborting due to 16 previous errors
+error: aborting due to 17 previous errors
+++ /dev/null
-#![allow(dead_code)]
-
-enum Foo {
- A,
- B,
- C,
-}
-
-macro_rules! test_hash {
- ($foo:expr, $($t:ident => $ord:expr),+ ) => {
- use self::Foo::*;
- match $foo {
- $ ( & $t => $ord,
- )*
- };
- };
-}
-
-fn main() {
- let a = Foo::A;
- test_hash!(&a, A => 0, B => 1, C => 2);
-}
+++ /dev/null
-error: you don't need to add `&` to both the expression and the patterns
- --> $DIR/ice-2636.rs:12:9
- |
-LL | / match $foo {
-LL | | $ ( & $t => $ord,
-LL | | )*
-LL | | };
- | |_________^
-...
-LL | test_hash!(&a, A => 0, B => 1, C => 2);
- | --------------------------------------- in this macro invocation
- |
- = note: `-D clippy::match-ref-pats` implied by `-D warnings`
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
#[allow(clippy::declare_interior_mutable_const)]
const ONCE_INIT: Once = Once::new();
-trait Trait<T>: Copy {
- type NonCopyType;
-
+// a constant whose type is a concrete type should be linted at the definition site.
+trait ConcreteTypes {
const ATOMIC: AtomicUsize; //~ ERROR interior mutable
const INTEGER: u64;
const STRING: String;
- const SELF: Self; // (no error)
- const INPUT: T;
- //~^ ERROR interior mutable
- //~| HELP consider requiring `T` to be `Copy`
- const ASSOC: Self::NonCopyType;
- //~^ ERROR interior mutable
- //~| HELP consider requiring `<Self as Trait<T>>::NonCopyType` to be `Copy`
+ declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable
+}
- const AN_INPUT: T = Self::INPUT;
- //~^ ERROR interior mutable
- //~| ERROR consider requiring `T` to be `Copy`
- declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable
+impl ConcreteTypes for u64 {
+ const ATOMIC: AtomicUsize = AtomicUsize::new(9);
+ const INTEGER: u64 = 10;
+ const STRING: String = String::new();
}
-trait Trait2 {
- type CopyType: Copy;
+// a helper trait used below
+trait ConstDefault {
+ const DEFAULT: Self;
+}
+
+// a constant whose type is a generic type should be linted at the implementation site.
+trait GenericTypes<T, U> {
+ const TO_REMAIN_GENERIC: T;
+ const TO_BE_CONCRETE: U;
- const SELF_2: Self;
- //~^ ERROR interior mutable
- //~| HELP consider requiring `Self` to be `Copy`
- const ASSOC_2: Self::CopyType; // (no error)
+ const HAVING_DEFAULT: T = Self::TO_REMAIN_GENERIC;
+ declare_const!(IN_MACRO: T = Self::TO_REMAIN_GENERIC);
}
-// we don't lint impl of traits, because an impl has no power to change the interface.
-impl Trait<u32> for u64 {
- type NonCopyType = u16;
+impl<T: ConstDefault> GenericTypes<T, AtomicUsize> for u64 {
+ const TO_REMAIN_GENERIC: T = T::DEFAULT;
+ const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable
+}
- const ATOMIC: AtomicUsize = AtomicUsize::new(9);
- const INTEGER: u64 = 10;
- const STRING: String = String::new();
- const SELF: Self = 11;
- const INPUT: u32 = 12;
- const ASSOC: Self::NonCopyType = 13;
+// a helper type used below
+struct Wrapper<T>(T);
+
+// a constant whose type is an associated type should be linted at the implementation site, too.
+trait AssocTypes {
+ type ToBeFrozen;
+ type ToBeUnfrozen;
+ type ToBeGenericParam;
+
+ const TO_BE_FROZEN: Self::ToBeFrozen;
+ const TO_BE_UNFROZEN: Self::ToBeUnfrozen;
+ const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen>;
+ // to ensure it can handle things when a generic type remains after normalization.
+ const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam>;
}
-struct Local<T, U>(T, U);
+impl<T: ConstDefault> AssocTypes for Vec<T> {
+ type ToBeFrozen = u16;
+ type ToBeUnfrozen = AtomicUsize;
+ type ToBeGenericParam = T;
+
+ const TO_BE_FROZEN: Self::ToBeFrozen = 12;
+ const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable
+ const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable
+ const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam> = Wrapper(T::DEFAULT);
+}
+
+// a helper trait used below
+trait AssocTypesHelper {
+ type NotToBeBounded;
+ type ToBeBounded;
+
+ const NOT_TO_BE_BOUNDED: Self::NotToBeBounded;
+}
-impl<T: Trait2 + Trait<u32>, U: Trait2> Local<T, U> {
- const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable
+// a constant whose type is an assoc type originated from a generic param bounded at the definition
+// site should be linted at there.
+trait AssocTypesFromGenericParam<T>
+where
+ T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
+{
+ const NOT_BOUNDED: T::NotToBeBounded;
+ const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable
+}
+
+impl<T> AssocTypesFromGenericParam<T> for u64
+where
+ T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
+{
+ // an associated type could remain unknown in a trait impl.
+ const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
+ const BOUNDED: T::ToBeBounded = AtomicUsize::new(15);
+}
+
+// a constant whose type is `Self` should be linted at the implementation site as well.
+// (`Option` requires `Sized` bound.)
+trait SelfType: Sized {
+ const SELF: Self;
+ // this was the one in the original issue (#5050).
+ const WRAPPED_SELF: Option<Self>;
+}
+
+impl SelfType for u64 {
+ const SELF: Self = 16;
+ const WRAPPED_SELF: Option<Self> = Some(20);
+}
+
+impl SelfType for AtomicUsize {
+ // this (interior mutable `Self` const) exists in `parking_lot`.
+ // `const_trait_impl` will replace it in the future, hopefully.
+ const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable
+ const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21)); //~ ERROR interior mutable
+}
+
+// Even though a constant contains a generic type, if it also have a interior mutable type,
+// it should be linted at the definition site.
+trait BothOfCellAndGeneric<T> {
+ // this is a false negative in the current implementation.
+ const DIRECT: Cell<T>;
+ const INDIRECT: Cell<*const T>; //~ ERROR interior mutable
+}
+
+impl<T: ConstDefault> BothOfCellAndGeneric<T> for u64 {
+ const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
+ const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
+}
+
+struct Local<T>(T);
+
+// a constant in an inherent impl are essentially the same as a normal const item
+// except there can be a generic or associated type.
+impl<T> Local<T>
+where
+ T: ConstDefault + AssocTypesHelper<ToBeBounded = AtomicUsize>,
+{
+ const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable
const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy");
- const T_SELF: T = T::SELF_2;
- const U_SELF: U = U::SELF_2;
- //~^ ERROR interior mutable
- //~| HELP consider requiring `U` to be `Copy`
- const T_ASSOC: T::NonCopyType = T::ASSOC;
- //~^ ERROR interior mutable
- //~| HELP consider requiring `<T as Trait<u32>>::NonCopyType` to be `Copy`
- const U_ASSOC: U::CopyType = U::ASSOC_2;
+
+ const GENERIC_TYPE: T = T::DEFAULT;
+
+ const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
+ const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable
}
fn main() {}
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:40:5
+ --> $DIR/declare_interior_mutable_const.rs:39:5
|
LL | const ATOMIC: AtomicUsize; //~ ERROR interior mutable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:44:5
+ --> $DIR/declare_interior_mutable_const.rs:16:9
+ |
+LL | const $name: $ty = $e;
+ | ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable
+ | ----------------------------------------------------------- in this macro invocation
|
-LL | const INPUT: T;
- | ^^^^^^^^^^^^^-^
- | |
- | consider requiring `T` to be `Copy`
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:47:5
+ --> $DIR/declare_interior_mutable_const.rs:67:5
|
-LL | const ASSOC: Self::NonCopyType;
- | ^^^^^^^^^^^^^-----------------^
- | |
- | consider requiring `<Self as Trait<T>>::NonCopyType` to be `Copy`
+LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:51:5
+ --> $DIR/declare_interior_mutable_const.rs:92:5
|
-LL | const AN_INPUT: T = Self::INPUT;
- | ^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^
- | |
- | consider requiring `T` to be `Copy`
+LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:16:9
+ --> $DIR/declare_interior_mutable_const.rs:93:5
|
-LL | const $name: $ty = $e;
- | ^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable
- | ----------------------------------------------- in this macro invocation
+LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/declare_interior_mutable_const.rs:112:5
|
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/declare_interior_mutable_const.rs:140:5
+ |
+LL | const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:60:5
+ --> $DIR/declare_interior_mutable_const.rs:141:5
|
-LL | const SELF_2: Self;
- | ^^^^^^^^^^^^^^----^
- | |
- | consider requiring `Self` to be `Copy`
+LL | const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21)); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:81:5
+ --> $DIR/declare_interior_mutable_const.rs:149:5
|
-LL | const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const INDIRECT: Cell<*const T>; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:84:5
+ --> $DIR/declare_interior_mutable_const.rs:165:5
|
-LL | const U_SELF: U = U::SELF_2;
- | ^^^^^^^^^^^^^^-^^^^^^^^^^^^^
- | |
- | consider requiring `U` to be `Copy`
+LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:87:5
+ --> $DIR/declare_interior_mutable_const.rs:171:5
|
-LL | const T_ASSOC: T::NonCopyType = T::ASSOC;
- | ^^^^^^^^^^^^^^^--------------^^^^^^^^^^^^
- | |
- | consider requiring `<T as Trait<u32>>::NonCopyType` to be `Copy`
+LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 13 previous errors
+error: aborting due to 15 previous errors
#![warn(clippy::drop_ref)]
#![allow(clippy::toplevel_ref_arg)]
+#![allow(clippy::map_err_ignore)]
use std::mem::drop;
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:9:5
+ --> $DIR/drop_ref.rs:10:5
|
LL | drop(&SomeStruct);
| ^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::drop-ref` implied by `-D warnings`
note: argument has type `&SomeStruct`
- --> $DIR/drop_ref.rs:9:10
+ --> $DIR/drop_ref.rs:10:10
|
LL | drop(&SomeStruct);
| ^^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:12:5
+ --> $DIR/drop_ref.rs:13:5
|
LL | drop(&owned1);
| ^^^^^^^^^^^^^
|
note: argument has type `&SomeStruct`
- --> $DIR/drop_ref.rs:12:10
+ --> $DIR/drop_ref.rs:13:10
|
LL | drop(&owned1);
| ^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:13:5
+ --> $DIR/drop_ref.rs:14:5
|
LL | drop(&&owned1);
| ^^^^^^^^^^^^^^
|
note: argument has type `&&SomeStruct`
- --> $DIR/drop_ref.rs:13:10
+ --> $DIR/drop_ref.rs:14:10
|
LL | drop(&&owned1);
| ^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:14:5
+ --> $DIR/drop_ref.rs:15:5
|
LL | drop(&mut owned1);
| ^^^^^^^^^^^^^^^^^
|
note: argument has type `&mut SomeStruct`
- --> $DIR/drop_ref.rs:14:10
+ --> $DIR/drop_ref.rs:15:10
|
LL | drop(&mut owned1);
| ^^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:18:5
+ --> $DIR/drop_ref.rs:19:5
|
LL | drop(reference1);
| ^^^^^^^^^^^^^^^^
|
note: argument has type `&SomeStruct`
- --> $DIR/drop_ref.rs:18:10
+ --> $DIR/drop_ref.rs:19:10
|
LL | drop(reference1);
| ^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:21:5
+ --> $DIR/drop_ref.rs:22:5
|
LL | drop(reference2);
| ^^^^^^^^^^^^^^^^
|
note: argument has type `&mut SomeStruct`
- --> $DIR/drop_ref.rs:21:10
+ --> $DIR/drop_ref.rs:22:10
|
LL | drop(reference2);
| ^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:24:5
+ --> $DIR/drop_ref.rs:25:5
|
LL | drop(reference3);
| ^^^^^^^^^^^^^^^^
|
note: argument has type `&SomeStruct`
- --> $DIR/drop_ref.rs:24:10
+ --> $DIR/drop_ref.rs:25:10
|
LL | drop(reference3);
| ^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:29:5
+ --> $DIR/drop_ref.rs:30:5
|
LL | drop(&val);
| ^^^^^^^^^^
|
note: argument has type `&T`
- --> $DIR/drop_ref.rs:29:10
+ --> $DIR/drop_ref.rs:30:10
|
LL | drop(&val);
| ^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:37:5
+ --> $DIR/drop_ref.rs:38:5
|
LL | std::mem::drop(&SomeStruct);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: argument has type `&SomeStruct`
- --> $DIR/drop_ref.rs:37:20
+ --> $DIR/drop_ref.rs:38:20
|
LL | std::mem::drop(&SomeStruct);
| ^^^^^^^^^^^
--> $DIR/float_cmp.rs:65:5
|
LL | ONE as f64 != 2.0;
- | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE as f64 - 2.0).abs() > error`
+ | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin`
|
= note: `-D clippy::float-cmp` implied by `-D warnings`
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: strict comparison of `f32` or `f64`
--> $DIR/float_cmp.rs:70:5
|
LL | x == 1.0;
- | ^^^^^^^^ help: consider comparing them within some error: `(x - 1.0).abs() < error`
+ | ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin`
|
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: strict comparison of `f32` or `f64`
--> $DIR/float_cmp.rs:73:5
|
LL | twice(x) != twice(ONE as f64);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(twice(x) - twice(ONE as f64)).abs() > error`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin`
|
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: strict comparison of `f32` or `f64`
--> $DIR/float_cmp.rs:93:5
|
LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin`
|
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: strict comparison of `f32` or `f64` arrays
--> $DIR/float_cmp.rs:98:5
LL | a1 == a2;
| ^^^^^^^^
|
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: strict comparison of `f32` or `f64`
--> $DIR/float_cmp.rs:99:5
|
LL | a1[0] == a2[0];
- | ^^^^^^^^^^^^^^ help: consider comparing them within some error: `(a1[0] - a2[0]).abs() < error`
+ | ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin`
|
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: aborting due to 6 previous errors
--> $DIR/float_cmp_const.rs:20:5
|
LL | 1f32 == ONE;
- | ^^^^^^^^^^^ help: consider comparing them within some error: `(1f32 - ONE).abs() < error`
+ | ^^^^^^^^^^^ help: consider comparing them within some margin of error: `(1f32 - ONE).abs() < error_margin`
|
= note: `-D clippy::float-cmp-const` implied by `-D warnings`
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:21:5
|
LL | TWO == ONE;
- | ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() < error`
+ | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() < error_margin`
|
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:22:5
|
LL | TWO != ONE;
- | ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() > error`
+ | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin`
|
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:23:5
|
LL | ONE + ONE == TWO;
- | ^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE + ONE - TWO).abs() < error`
+ | ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin`
|
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:25:5
|
LL | x as f32 == ONE;
- | ^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(x as f32 - ONE).abs() < error`
+ | ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin`
|
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:28:5
|
LL | v == ONE;
- | ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() < error`
+ | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() < error_margin`
|
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:29:5
|
LL | v != ONE;
- | ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() > error`
+ | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() > error_margin`
|
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: strict comparison of `f32` or `f64` constant arrays
--> $DIR/float_cmp_const.rs:61:5
LL | NON_ZERO_ARRAY == NON_ZERO_ARRAY2;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
error: aborting due to 8 previous errors
x[3]; // Ok, should not produce stderr.
let y = &x;
- y[0];
+ y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
+ y[4]; // Ok, rustc will handle references too.
let v = vec![0; 5];
v[0];
= help: Consider using `.get(n)` or `.get_mut(n)` instead
error: indexing may panic.
- --> $DIR/indexing_slicing_index.rs:18:5
- |
-LL | y[0];
- | ^^^^
- |
- = help: Consider using `.get(n)` or `.get_mut(n)` instead
-
-error: indexing may panic.
- --> $DIR/indexing_slicing_index.rs:21:5
+ --> $DIR/indexing_slicing_index.rs:22:5
|
LL | v[0];
| ^^^^
= help: Consider using `.get(n)` or `.get_mut(n)` instead
error: indexing may panic.
- --> $DIR/indexing_slicing_index.rs:22:5
+ --> $DIR/indexing_slicing_index.rs:23:5
|
LL | v[10];
| ^^^^^
= help: Consider using `.get(n)` or `.get_mut(n)` instead
error: indexing may panic.
- --> $DIR/indexing_slicing_index.rs:23:5
+ --> $DIR/indexing_slicing_index.rs:24:5
|
LL | v[1 << 3];
| ^^^^^^^^^
= help: Consider using `.get(n)` or `.get_mut(n)` instead
error: indexing may panic.
- --> $DIR/indexing_slicing_index.rs:29:5
+ --> $DIR/indexing_slicing_index.rs:30:5
|
LL | v[N];
| ^^^^
= help: Consider using `.get(n)` or `.get_mut(n)` instead
error: indexing may panic.
- --> $DIR/indexing_slicing_index.rs:30:5
+ --> $DIR/indexing_slicing_index.rs:31:5
|
LL | v[M];
| ^^^^
|
= help: Consider using `.get(n)` or `.get_mut(n)` instead
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
|
= help: Consider using `.get(..n)`or `.get_mut(..n)` instead
-error: slicing may panic.
- --> $DIR/indexing_slicing_slice.rs:24:6
- |
-LL | &y[1..2];
- | ^^^^^^^
- |
- = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead
-
-error: slicing may panic.
- --> $DIR/indexing_slicing_slice.rs:25:6
+error: range is out of bounds
+ --> $DIR/indexing_slicing_slice.rs:25:12
|
LL | &y[0..=4];
- | ^^^^^^^^
- |
- = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead
+ | ^
-error: slicing may panic.
- --> $DIR/indexing_slicing_slice.rs:26:6
+error: range is out of bounds
+ --> $DIR/indexing_slicing_slice.rs:26:11
|
LL | &y[..=4];
- | ^^^^^^^
- |
- = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
+ | ^
error: slicing may panic.
--> $DIR/indexing_slicing_slice.rs:31:6
|
= help: Consider using `.get(..n)`or `.get_mut(..n)` instead
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Vec`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec`
--> $DIR/into_iter_on_ref.rs:14:30
|
LL | let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter()
|
= note: `-D clippy::into-iter-on-ref` implied by `-D warnings`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice`
--> $DIR/into_iter_on_ref.rs:15:46
|
LL | let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice`
--> $DIR/into_iter_on_ref.rs:16:41
|
LL | let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice`
--> $DIR/into_iter_on_ref.rs:17:44
|
LL | let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array`
--> $DIR/into_iter_on_ref.rs:19:32
|
LL | let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array`
--> $DIR/into_iter_on_ref.rs:20:36
|
LL | let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `array`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `array`
--> $DIR/into_iter_on_ref.rs:21:40
|
LL | let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `iter_mut`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Option`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Option`
--> $DIR/into_iter_on_ref.rs:23:24
|
LL | let _ = (&Some(4)).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Option`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Option`
--> $DIR/into_iter_on_ref.rs:24:28
|
LL | let _ = (&mut Some(5)).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `iter_mut`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Result`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Result`
--> $DIR/into_iter_on_ref.rs:25:32
|
LL | let _ = (&Ok::<_, i32>(6)).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Result`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Result`
--> $DIR/into_iter_on_ref.rs:26:37
|
LL | let _ = (&mut Err::<i32, _>(7)).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `iter_mut`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Vec`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec`
--> $DIR/into_iter_on_ref.rs:27:34
|
LL | let _ = (&Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Vec`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Vec`
--> $DIR/into_iter_on_ref.rs:28:38
|
LL | let _ = (&mut Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `iter_mut`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BTreeMap`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeMap`
--> $DIR/into_iter_on_ref.rs:29:44
|
LL | let _ = (&BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `BTreeMap`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `BTreeMap`
--> $DIR/into_iter_on_ref.rs:30:48
|
LL | let _ = (&mut BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `iter_mut`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `VecDeque`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `VecDeque`
--> $DIR/into_iter_on_ref.rs:31:39
|
LL | let _ = (&VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `VecDeque`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `VecDeque`
--> $DIR/into_iter_on_ref.rs:32:43
|
LL | let _ = (&mut VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `iter_mut`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `LinkedList`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `LinkedList`
--> $DIR/into_iter_on_ref.rs:33:41
|
LL | let _ = (&LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `LinkedList`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `LinkedList`
--> $DIR/into_iter_on_ref.rs:34:45
|
LL | let _ = (&mut LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `iter_mut`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `HashMap`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashMap`
--> $DIR/into_iter_on_ref.rs:35:43
|
LL | let _ = (&HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `HashMap`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `HashMap`
--> $DIR/into_iter_on_ref.rs:36:47
|
LL | let _ = (&mut HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `iter_mut`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BTreeSet`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeSet`
--> $DIR/into_iter_on_ref.rs:38:39
|
LL | let _ = (&BTreeSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BinaryHeap`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BinaryHeap`
--> $DIR/into_iter_on_ref.rs:39:41
|
LL | let _ = (&BinaryHeap::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `HashSet`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashSet`
--> $DIR/into_iter_on_ref.rs:40:38
|
LL | let _ = (&HashSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Path`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Path`
--> $DIR/into_iter_on_ref.rs:41:43
|
LL | let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `PathBuf`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `PathBuf`
--> $DIR/into_iter_on_ref.rs:42:47
|
LL | let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter()
| ^^^^^^^^^ help: call directly: `iter`
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array`
--> $DIR/into_iter_on_ref.rs:44:26
|
LL | let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter()
x
}
+#[allow(clippy::manual_strip)]
fn issue975() -> String {
let mut udn = "dummy".to_string();
if udn.starts_with("uuid:") {
error: `if _ { .. } else { .. }` is an expression
- --> $DIR/let_if_seq.rs:63:5
+ --> $DIR/let_if_seq.rs:64:5
|
LL | / let mut foo = 0;
LL | | if f() {
= note: you might not need `mut` at all
error: `if _ { .. } else { .. }` is an expression
- --> $DIR/let_if_seq.rs:68:5
+ --> $DIR/let_if_seq.rs:69:5
|
LL | / let mut bar = 0;
LL | | if f() {
= note: you might not need `mut` at all
error: `if _ { .. } else { .. }` is an expression
- --> $DIR/let_if_seq.rs:76:5
+ --> $DIR/let_if_seq.rs:77:5
|
LL | / let quz;
LL | | if f() {
| |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };`
error: `if _ { .. } else { .. }` is an expression
- --> $DIR/let_if_seq.rs:105:5
+ --> $DIR/let_if_seq.rs:106:5
|
LL | / let mut baz = 0;
LL | | if f() {
--- /dev/null
+#![warn(clippy::manual_strip)]
+
+fn main() {
+ let s = "abc";
+
+ if s.starts_with("ab") {
+ str::to_string(&s["ab".len()..]);
+ s["ab".len()..].to_string();
+
+ str::to_string(&s[2..]);
+ s[2..].to_string();
+ }
+
+ if s.ends_with("bc") {
+ str::to_string(&s[..s.len() - "bc".len()]);
+ s[..s.len() - "bc".len()].to_string();
+
+ str::to_string(&s[..s.len() - 2]);
+ s[..s.len() - 2].to_string();
+ }
+
+ // Character patterns
+ if s.starts_with('a') {
+ str::to_string(&s[1..]);
+ s[1..].to_string();
+ }
+
+ // Variable prefix
+ let prefix = "ab";
+ if s.starts_with(prefix) {
+ str::to_string(&s[prefix.len()..]);
+ }
+
+ // Constant prefix
+ const PREFIX: &str = "ab";
+ if s.starts_with(PREFIX) {
+ str::to_string(&s[PREFIX.len()..]);
+ str::to_string(&s[2..]);
+ }
+
+ // Constant target
+ const TARGET: &str = "abc";
+ if TARGET.starts_with(prefix) {
+ str::to_string(&TARGET[prefix.len()..]);
+ }
+
+ // String target - not mutated.
+ let s1: String = "abc".into();
+ if s1.starts_with("ab") {
+ s1[2..].to_uppercase();
+ }
+
+ // String target - mutated. (Don't lint.)
+ let mut s2: String = "abc".into();
+ if s2.starts_with("ab") {
+ s2.push('d');
+ s2[2..].to_uppercase();
+ }
+
+ // Target not stripped. (Don't lint.)
+ let s3 = String::from("abcd");
+ let s4 = String::from("efgh");
+ if s3.starts_with("ab") {
+ s4[2..].to_string();
+ }
+}
--- /dev/null
+error: stripping a prefix manually
+ --> $DIR/manual_strip.rs:7:24
+ |
+LL | str::to_string(&s["ab".len()..]);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::manual-strip` implied by `-D warnings`
+note: the prefix was tested here
+ --> $DIR/manual_strip.rs:6:5
+ |
+LL | if s.starts_with("ab") {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+ |
+LL | if let Some(<stripped>) = s.strip_prefix("ab") {
+LL | str::to_string(<stripped>);
+LL | <stripped>.to_string();
+LL |
+LL | str::to_string(<stripped>);
+LL | <stripped>.to_string();
+ |
+
+error: stripping a suffix manually
+ --> $DIR/manual_strip.rs:15:24
+ |
+LL | str::to_string(&s[..s.len() - "bc".len()]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the suffix was tested here
+ --> $DIR/manual_strip.rs:14:5
+ |
+LL | if s.ends_with("bc") {
+ | ^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_suffix` method
+ |
+LL | if let Some(<stripped>) = s.strip_suffix("bc") {
+LL | str::to_string(<stripped>);
+LL | <stripped>.to_string();
+LL |
+LL | str::to_string(<stripped>);
+LL | <stripped>.to_string();
+ |
+
+error: stripping a prefix manually
+ --> $DIR/manual_strip.rs:24:24
+ |
+LL | str::to_string(&s[1..]);
+ | ^^^^^^^
+ |
+note: the prefix was tested here
+ --> $DIR/manual_strip.rs:23:5
+ |
+LL | if s.starts_with('a') {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+ |
+LL | if let Some(<stripped>) = s.strip_prefix('a') {
+LL | str::to_string(<stripped>);
+LL | <stripped>.to_string();
+ |
+
+error: stripping a prefix manually
+ --> $DIR/manual_strip.rs:31:24
+ |
+LL | str::to_string(&s[prefix.len()..]);
+ | ^^^^^^^^^^^^^^^^^^
+ |
+note: the prefix was tested here
+ --> $DIR/manual_strip.rs:30:5
+ |
+LL | if s.starts_with(prefix) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+ |
+LL | if let Some(<stripped>) = s.strip_prefix(prefix) {
+LL | str::to_string(<stripped>);
+ |
+
+error: stripping a prefix manually
+ --> $DIR/manual_strip.rs:37:24
+ |
+LL | str::to_string(&s[PREFIX.len()..]);
+ | ^^^^^^^^^^^^^^^^^^
+ |
+note: the prefix was tested here
+ --> $DIR/manual_strip.rs:36:5
+ |
+LL | if s.starts_with(PREFIX) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+ |
+LL | if let Some(<stripped>) = s.strip_prefix(PREFIX) {
+LL | str::to_string(<stripped>);
+LL | str::to_string(<stripped>);
+ |
+
+error: stripping a prefix manually
+ --> $DIR/manual_strip.rs:44:24
+ |
+LL | str::to_string(&TARGET[prefix.len()..]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the prefix was tested here
+ --> $DIR/manual_strip.rs:43:5
+ |
+LL | if TARGET.starts_with(prefix) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+ |
+LL | if let Some(<stripped>) = TARGET.strip_prefix(prefix) {
+LL | str::to_string(<stripped>);
+ |
+
+error: stripping a prefix manually
+ --> $DIR/manual_strip.rs:50:9
+ |
+LL | s1[2..].to_uppercase();
+ | ^^^^^^^
+ |
+note: the prefix was tested here
+ --> $DIR/manual_strip.rs:49:5
+ |
+LL | if s1.starts_with("ab") {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+ |
+LL | if let Some(<stripped>) = s1.strip_prefix("ab") {
+LL | <stripped>.to_uppercase();
+ |
+
+error: aborting due to 7 previous errors
+
--- /dev/null
+#![warn(clippy::map_err_ignore)]
+use std::convert::TryFrom;
+use std::error::Error;
+use std::fmt;
+
+#[derive(Debug)]
+enum Errors {
+ Ignored,
+}
+
+impl Error for Errors {}
+
+impl fmt::Display for Errors {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Error")
+ }
+}
+
+fn main() -> Result<(), Errors> {
+ let x = u32::try_from(-123_i32);
+
+ println!("{:?}", x.map_err(|_| Errors::Ignored));
+
+ Ok(())
+}
--- /dev/null
+error: `map_err(|_|...` ignores the original error
+ --> $DIR/map_err.rs:22:32
+ |
+LL | println!("{:?}", x.map_err(|_| Errors::Ignored));
+ | ^^^
+ |
+ = note: `-D clippy::map-err-ignore` implied by `-D warnings`
+ = help: Consider wrapping the error in an enum variant
+
+error: aborting due to previous error
+
--- /dev/null
+#![deny(clippy::internal)]
+#![feature(rustc_private)]
+
+extern crate rustc_hir;
+extern crate rustc_lint;
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_session;
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Ty;
+
+mod paths {
+ pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
+}
+
+mod utils {
+ use super::*;
+
+ pub fn match_type(_cx: &LateContext<'_>, _ty: Ty<'_>, _path: &[&str]) -> bool {
+ false
+ }
+}
+
+use utils::match_type;
+
+declare_lint! {
+ pub TEST_LINT,
+ Warn,
+ ""
+}
+
+declare_lint_pass!(Pass => [TEST_LINT]);
+
+static OPTION: [&str; 3] = ["core", "option", "Option"];
+
+impl<'tcx> LateLintPass<'tcx> for Pass {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr) {
+ let ty = cx.typeck_results().expr_ty(expr);
+
+ let _ = match_type(cx, ty, &paths::VEC);
+ let _ = match_type(cx, ty, &OPTION);
+ let _ = match_type(cx, ty, &["core", "result", "Result"]);
+
+ let rc_path = &["alloc", "rc", "Rc"];
+ let _ = utils::match_type(cx, ty, rc_path);
+ }
+}
+
+fn main() {}
--- /dev/null
+error: usage of `utils::match_type()` on a type diagnostic item
+ --> $DIR/match_type_on_diag_item.rs:41:17
+ |
+LL | let _ = match_type(cx, ty, &paths::VEC);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(vec_type))`
+ |
+note: the lint level is defined here
+ --> $DIR/match_type_on_diag_item.rs:1:9
+ |
+LL | #![deny(clippy::internal)]
+ | ^^^^^^^^^^^^^^^^
+ = note: `#[deny(clippy::match_type_on_diagnostic_item)]` implied by `#[deny(clippy::internal)]`
+
+error: usage of `utils::match_type()` on a type diagnostic item
+ --> $DIR/match_type_on_diag_item.rs:42:17
+ |
+LL | let _ = match_type(cx, ty, &OPTION);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(option_type))`
+
+error: usage of `utils::match_type()` on a type diagnostic item
+ --> $DIR/match_type_on_diag_item.rs:43:17
+ |
+LL | let _ = match_type(cx, ty, &["core", "result", "Result"]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(result_type))`
+
+error: usage of `utils::match_type()` on a type diagnostic item
+ --> $DIR/match_type_on_diag_item.rs:46:17
+ |
+LL | let _ = utils::match_type(cx, ty, rc_path);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(Rc))`
+
+error: aborting due to 4 previous errors
+
// run-rustfix
#![warn(clippy::option_if_let_else)]
+#![allow(clippy::redundant_closure)]
fn bad1(string: Option<&str>) -> (bool, &str) {
string.map_or((false, "hello"), |x| (true, x))
})
}
+fn impure_else(arg: Option<i32>) {
+ let side_effect = || {
+ println!("return 1");
+ 1
+ };
+ let _ = arg.map_or_else(|| side_effect(), |x| x);
+}
+
fn test_map_or_else(arg: Option<u32>) {
let _ = arg.map_or_else(|| {
let mut y = 1;
let _ = longer_body(None);
test_map_or_else(None);
let _ = negative_tests(None);
+ let _ = impure_else(None);
}
// run-rustfix
#![warn(clippy::option_if_let_else)]
+#![allow(clippy::redundant_closure)]
fn bad1(string: Option<&str>) -> (bool, &str) {
if let Some(x) = string {
}
}
+fn impure_else(arg: Option<i32>) {
+ let side_effect = || {
+ println!("return 1");
+ 1
+ };
+ let _ = if let Some(x) = arg {
+ x
+ } else {
+ // map_or_else must be suggested
+ side_effect()
+ };
+}
+
fn test_map_or_else(arg: Option<u32>) {
let _ = if let Some(x) = arg {
x * x * x * x
let _ = longer_body(None);
test_map_or_else(None);
let _ = negative_tests(None);
+ let _ = impure_else(None);
}
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:5:5
+ --> $DIR/option_if_let_else.rs:6:5
|
LL | / if let Some(x) = string {
LL | | (true, x)
= note: `-D clippy::option-if-let-else` implied by `-D warnings`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:15:12
+ --> $DIR/option_if_let_else.rs:16:12
|
LL | } else if let Some(x) = string {
| ____________^
| |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:23:13
+ --> $DIR/option_if_let_else.rs:24:13
|
LL | let _ = if let Some(s) = *string { s.len() } else { 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:24:13
+ --> $DIR/option_if_let_else.rs:25:13
|
LL | let _ = if let Some(s) = &num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:25:13
+ --> $DIR/option_if_let_else.rs:26:13
|
LL | let _ = if let Some(s) = &mut num {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:31:13
+ --> $DIR/option_if_let_else.rs:32:13
|
LL | let _ = if let Some(ref s) = num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:32:13
+ --> $DIR/option_if_let_else.rs:33:13
|
LL | let _ = if let Some(mut s) = num {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:38:13
+ --> $DIR/option_if_let_else.rs:39:13
|
LL | let _ = if let Some(ref mut s) = num {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:47:5
+ --> $DIR/option_if_let_else.rs:48:5
|
LL | / if let Some(x) = arg {
LL | | let y = x * x;
|
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:56:13
+ --> $DIR/option_if_let_else.rs:61:13
+ |
+LL | let _ = if let Some(x) = arg {
+ | _____________^
+LL | | x
+LL | | } else {
+LL | | // map_or_else must be suggested
+LL | | side_effect()
+LL | | };
+ | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
+
+error: use Option::map_or_else instead of an if let/else
+ --> $DIR/option_if_let_else.rs:70:13
|
LL | let _ = if let Some(x) = arg {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:85:13
+ --> $DIR/option_if_let_else.rs:99:13
|
LL | let _ = if let Some(x) = optional { x + 2 } else { 5 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
--- /dev/null
+#![warn(clippy::panic_in_result_fn)]
+
+struct A;
+
+impl A {
+ fn result_with_panic() -> Result<bool, String> // should emit lint
+ {
+ panic!("error");
+ }
+
+ fn result_with_unimplemented() -> Result<bool, String> // should emit lint
+ {
+ unimplemented!();
+ }
+
+ fn result_with_unreachable() -> Result<bool, String> // should emit lint
+ {
+ unreachable!();
+ }
+
+ fn result_with_todo() -> Result<bool, String> // should emit lint
+ {
+ todo!("Finish this");
+ }
+
+ fn other_with_panic() // should not emit lint
+ {
+ panic!("");
+ }
+
+ fn other_with_unreachable() // should not emit lint
+ {
+ unreachable!();
+ }
+
+ fn other_with_unimplemented() // should not emit lint
+ {
+ unimplemented!();
+ }
+
+ fn other_with_todo() // should not emit lint
+ {
+ todo!("finish this")
+ }
+
+ fn result_without_banned_functions() -> Result<bool, String> // should not emit lint
+ {
+ Ok(true)
+ }
+}
+
+fn function_result_with_panic() -> Result<bool, String> // should emit lint
+{
+ panic!("error");
+}
+
+fn todo() {
+ println!("something");
+}
+
+fn function_result_with_custom_todo() -> Result<bool, String> // should not emit lint
+{
+ todo();
+ Ok(true)
+}
+
+fn main() -> Result<(), String> {
+ todo!("finish main method");
+ Ok(())
+}
--- /dev/null
+error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
+ --> $DIR/panic_in_result_fn.rs:6:5
+ |
+LL | / fn result_with_panic() -> Result<bool, String> // should emit lint
+LL | | {
+LL | | panic!("error");
+LL | | }
+ | |_____^
+ |
+ = note: `-D clippy::panic-in-result-fn` implied by `-D warnings`
+ = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+note: return Err() instead of panicking
+ --> $DIR/panic_in_result_fn.rs:8:9
+ |
+LL | panic!("error");
+ | ^^^^^^^^^^^^^^^^
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
+ --> $DIR/panic_in_result_fn.rs:11:5
+ |
+LL | / fn result_with_unimplemented() -> Result<bool, String> // should emit lint
+LL | | {
+LL | | unimplemented!();
+LL | | }
+ | |_____^
+ |
+ = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+note: return Err() instead of panicking
+ --> $DIR/panic_in_result_fn.rs:13:9
+ |
+LL | unimplemented!();
+ | ^^^^^^^^^^^^^^^^^
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
+ --> $DIR/panic_in_result_fn.rs:16:5
+ |
+LL | / fn result_with_unreachable() -> Result<bool, String> // should emit lint
+LL | | {
+LL | | unreachable!();
+LL | | }
+ | |_____^
+ |
+ = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+note: return Err() instead of panicking
+ --> $DIR/panic_in_result_fn.rs:18:9
+ |
+LL | unreachable!();
+ | ^^^^^^^^^^^^^^^
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
+ --> $DIR/panic_in_result_fn.rs:21:5
+ |
+LL | / fn result_with_todo() -> Result<bool, String> // should emit lint
+LL | | {
+LL | | todo!("Finish this");
+LL | | }
+ | |_____^
+ |
+ = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+note: return Err() instead of panicking
+ --> $DIR/panic_in_result_fn.rs:23:9
+ |
+LL | todo!("Finish this");
+ | ^^^^^^^^^^^^^^^^^^^^^
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
+ --> $DIR/panic_in_result_fn.rs:52:1
+ |
+LL | / fn function_result_with_panic() -> Result<bool, String> // should emit lint
+LL | | {
+LL | | panic!("error");
+LL | | }
+ | |_^
+ |
+ = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+note: return Err() instead of panicking
+ --> $DIR/panic_in_result_fn.rs:54:5
+ |
+LL | panic!("error");
+ | ^^^^^^^^^^^^^^^^
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
+ --> $DIR/panic_in_result_fn.rs:67:1
+ |
+LL | / fn main() -> Result<(), String> {
+LL | | todo!("finish main method");
+LL | | Ok(())
+LL | | }
+ | |_^
+ |
+ = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+note: return Err() instead of panicking
+ --> $DIR/panic_in_result_fn.rs:68:5
+ |
+LL | todo!("finish main method");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
+
print!("Hello {}\n", "world");
print!("Hello {} {}\n", "world", "#2");
print!("{}\n", 1265);
+ print!("\n");
// these are all fine
print!("");
| ^^^^^^^ --
error: using `print!()` with a format string that ends in a single newline
- --> $DIR/print_with_newline.rs:30:5
+ --> $DIR/print_with_newline.rs:12:5
+ |
+LL | print!("/n");
+ | ^^^^^^^^^^^^
+ |
+help: use `println!` instead
+ |
+LL | println!();
+ | ^^^^^^^ --
+
+error: using `print!()` with a format string that ends in a single newline
+ --> $DIR/print_with_newline.rs:31:5
|
LL | print!("//n"); // should fail
| ^^^^^^^^^^^^^^
| ^^^^^^^ --
error: using `print!()` with a format string that ends in a single newline
- --> $DIR/print_with_newline.rs:37:5
+ --> $DIR/print_with_newline.rs:38:5
|
LL | / print!(
LL | | "
|
error: using `print!()` with a format string that ends in a single newline
- --> $DIR/print_with_newline.rs:41:5
+ --> $DIR/print_with_newline.rs:42:5
|
LL | / print!(
LL | | r"
|
error: using `print!()` with a format string that ends in a single newline
- --> $DIR/print_with_newline.rs:49:5
+ --> $DIR/print_with_newline.rs:50:5
|
LL | print!("/r/n"); //~ ERROR
| ^^^^^^^^^^^^^^^
| ^^^^^^^ --
error: using `print!()` with a format string that ends in a single newline
- --> $DIR/print_with_newline.rs:50:5
+ --> $DIR/print_with_newline.rs:51:5
|
LL | print!("foo/rbar/n") // ~ ERROR
| ^^^^^^^^^^^^^^^^^^^^
LL | println!("foo/rbar") // ~ ERROR
| ^^^^^^^ --
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
--- /dev/null
+#![warn(clippy::rc_buffer)]
+
+use std::cell::RefCell;
+use std::ffi::OsString;
+use std::path::PathBuf;
+use std::rc::Rc;
+
+struct S {
+ // triggers lint
+ bad1: Rc<String>,
+ bad2: Rc<PathBuf>,
+ bad3: Rc<Vec<u8>>,
+ bad4: Rc<OsString>,
+ // does not trigger lint
+ good1: Rc<RefCell<String>>,
+}
+
+// triggers lint
+fn func_bad1(_: Rc<String>) {}
+fn func_bad2(_: Rc<PathBuf>) {}
+fn func_bad3(_: Rc<Vec<u8>>) {}
+fn func_bad4(_: Rc<OsString>) {}
+// does not trigger lint
+fn func_good1(_: Rc<RefCell<String>>) {}
+
+fn main() {}
--- /dev/null
+error: usage of `Rc<T>` when T is a buffer type
+ --> $DIR/rc_buffer.rs:10:11
+ |
+LL | bad1: Rc<String>,
+ | ^^^^^^^^^^ help: try: `Rc<str>`
+ |
+ = note: `-D clippy::rc-buffer` implied by `-D warnings`
+
+error: usage of `Rc<T>` when T is a buffer type
+ --> $DIR/rc_buffer.rs:11:11
+ |
+LL | bad2: Rc<PathBuf>,
+ | ^^^^^^^^^^^ help: try: `Rc<std::path::Path>`
+
+error: usage of `Rc<T>` when T is a buffer type
+ --> $DIR/rc_buffer.rs:12:11
+ |
+LL | bad3: Rc<Vec<u8>>,
+ | ^^^^^^^^^^^ help: try: `Rc<[u8]>`
+
+error: usage of `Rc<T>` when T is a buffer type
+ --> $DIR/rc_buffer.rs:13:11
+ |
+LL | bad4: Rc<OsString>,
+ | ^^^^^^^^^^^^ help: try: `Rc<std::ffi::OsStr>`
+
+error: usage of `Rc<T>` when T is a buffer type
+ --> $DIR/rc_buffer.rs:19:17
+ |
+LL | fn func_bad1(_: Rc<String>) {}
+ | ^^^^^^^^^^ help: try: `Rc<str>`
+
+error: usage of `Rc<T>` when T is a buffer type
+ --> $DIR/rc_buffer.rs:20:17
+ |
+LL | fn func_bad2(_: Rc<PathBuf>) {}
+ | ^^^^^^^^^^^ help: try: `Rc<std::path::Path>`
+
+error: usage of `Rc<T>` when T is a buffer type
+ --> $DIR/rc_buffer.rs:21:17
+ |
+LL | fn func_bad3(_: Rc<Vec<u8>>) {}
+ | ^^^^^^^^^^^ help: try: `Rc<[u8]>`
+
+error: usage of `Rc<T>` when T is a buffer type
+ --> $DIR/rc_buffer.rs:22:17
+ |
+LL | fn func_bad4(_: Rc<OsString>) {}
+ | ^^^^^^^^^^^^ help: try: `Rc<std::ffi::OsStr>`
+
+error: aborting due to 8 previous errors
+
--- /dev/null
+#![warn(clippy::rc_buffer)]
+
+use std::ffi::OsString;
+use std::path::PathBuf;
+use std::sync::{Arc, Mutex};
+
+struct S {
+ // triggers lint
+ bad1: Arc<String>,
+ bad2: Arc<PathBuf>,
+ bad3: Arc<Vec<u8>>,
+ bad4: Arc<OsString>,
+ // does not trigger lint
+ good1: Arc<Mutex<String>>,
+}
+
+// triggers lint
+fn func_bad1(_: Arc<String>) {}
+fn func_bad2(_: Arc<PathBuf>) {}
+fn func_bad3(_: Arc<Vec<u8>>) {}
+fn func_bad4(_: Arc<OsString>) {}
+// does not trigger lint
+fn func_good1(_: Arc<Mutex<String>>) {}
+
+fn main() {}
--- /dev/null
+error: usage of `Arc<T>` when T is a buffer type
+ --> $DIR/rc_buffer_arc.rs:9:11
+ |
+LL | bad1: Arc<String>,
+ | ^^^^^^^^^^^ help: try: `Arc<str>`
+ |
+ = note: `-D clippy::rc-buffer` implied by `-D warnings`
+
+error: usage of `Arc<T>` when T is a buffer type
+ --> $DIR/rc_buffer_arc.rs:10:11
+ |
+LL | bad2: Arc<PathBuf>,
+ | ^^^^^^^^^^^^ help: try: `Arc<std::path::Path>`
+
+error: usage of `Arc<T>` when T is a buffer type
+ --> $DIR/rc_buffer_arc.rs:11:11
+ |
+LL | bad3: Arc<Vec<u8>>,
+ | ^^^^^^^^^^^^ help: try: `Arc<[u8]>`
+
+error: usage of `Arc<T>` when T is a buffer type
+ --> $DIR/rc_buffer_arc.rs:12:11
+ |
+LL | bad4: Arc<OsString>,
+ | ^^^^^^^^^^^^^ help: try: `Arc<std::ffi::OsStr>`
+
+error: usage of `Arc<T>` when T is a buffer type
+ --> $DIR/rc_buffer_arc.rs:18:17
+ |
+LL | fn func_bad1(_: Arc<String>) {}
+ | ^^^^^^^^^^^ help: try: `Arc<str>`
+
+error: usage of `Arc<T>` when T is a buffer type
+ --> $DIR/rc_buffer_arc.rs:19:17
+ |
+LL | fn func_bad2(_: Arc<PathBuf>) {}
+ | ^^^^^^^^^^^^ help: try: `Arc<std::path::Path>`
+
+error: usage of `Arc<T>` when T is a buffer type
+ --> $DIR/rc_buffer_arc.rs:20:17
+ |
+LL | fn func_bad3(_: Arc<Vec<u8>>) {}
+ | ^^^^^^^^^^^^ help: try: `Arc<[u8]>`
+
+error: usage of `Arc<T>` when T is a buffer type
+ --> $DIR/rc_buffer_arc.rs:21:17
+ |
+LL | fn func_bad4(_: Arc<OsString>) {}
+ | ^^^^^^^^^^^^^ help: try: `Arc<std::ffi::OsStr>`
+
+error: aborting due to 8 previous errors
+
--- /dev/null
+#![warn(clippy::rc_buffer)]
+
+use std::rc::Rc;
+
+struct String;
+
+struct S {
+ // does not trigger lint
+ good1: Rc<String>,
+}
+
+fn main() {}
if Err::<i32, i32>(42).is_err() {}
- if None::<()>.is_none() {}
-
- if Some(42).is_some() {}
-
- if Some(42).is_some() {
- foo();
- } else {
- bar();
- }
-
- while Some(42).is_some() {}
-
- while Some(42).is_none() {}
-
- while None::<()>.is_none() {}
-
while Ok::<i32, i32>(10).is_ok() {}
while Ok::<i32, i32>(10).is_err() {}
- let mut v = vec![1, 2, 3];
- while v.pop().is_some() {
- foo();
- }
-
if Ok::<i32, i32>(42).is_ok() {}
if Err::<i32, i32>(42).is_err() {}
- if None::<i32>.is_none() {}
-
- if Some(42).is_some() {}
-
if let Ok(x) = Ok::<i32, i32>(42) {
println!("{}", x);
}
Err::<i32, i32>(42).is_ok();
- Some(42).is_some();
-
- None::<()>.is_none();
-
- let _ = None::<()>.is_none();
-
let _ = if Ok::<usize, ()>(4).is_ok() { true } else { false };
- let opt = Some(false);
- let x = if opt.is_some() { true } else { false };
- takes_bool(x);
-
issue5504();
issue6067();
+ issue6065();
- let _ = if gen_opt().is_some() {
+ let _ = if gen_res().is_ok() {
1
- } else if gen_opt().is_none() {
- 2
- } else if gen_res().is_ok() {
- 3
} else if gen_res().is_err() {
- 4
+ 2
} else {
- 5
+ 3
};
}
-fn gen_opt() -> Option<()> {
- None
-}
-
fn gen_res() -> Result<(), ()> {
Ok(())
}
-fn takes_bool(_: bool) {}
-
-fn foo() {}
-
-fn bar() {}
-
macro_rules! m {
() => {
Some(42u32)
while m!().is_some() {}
}
+fn issue6065() {
+ macro_rules! if_let_in_macro {
+ ($pat:pat, $x:expr) => {
+ if let Some($pat) = $x {}
+ };
+ }
+
+ // shouldn't be linted
+ if_let_in_macro!(_, Some(42));
+}
+
// Methods that are unstable const should not be suggested within a const context, see issue #5697.
-// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result`, and `is_some` and `is_none`
-// of `Option` were stabilized as const, so the following should be linted.
+// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const,
+// so the following should be linted.
const fn issue6067() {
if Ok::<i32, i32>(42).is_ok() {}
if Err::<i32, i32>(42).is_err() {}
- if Some(42).is_some() {}
-
- if None::<()>.is_none() {}
-
while Ok::<i32, i32>(10).is_ok() {}
while Ok::<i32, i32>(10).is_err() {}
- while Some(42).is_some() {}
-
- while None::<()>.is_none() {}
-
Ok::<i32, i32>(42).is_ok();
Err::<i32, i32>(42).is_err();
-
- Some(42).is_some();
-
- None::<()>.is_none();
}
if let Err(_) = Err::<i32, i32>(42) {}
- if let None = None::<()> {}
-
- if let Some(_) = Some(42) {}
-
- if let Some(_) = Some(42) {
- foo();
- } else {
- bar();
- }
-
- while let Some(_) = Some(42) {}
-
- while let None = Some(42) {}
-
- while let None = None::<()> {}
-
while let Ok(_) = Ok::<i32, i32>(10) {}
while let Err(_) = Ok::<i32, i32>(10) {}
- let mut v = vec![1, 2, 3];
- while let Some(_) = v.pop() {
- foo();
- }
-
if Ok::<i32, i32>(42).is_ok() {}
if Err::<i32, i32>(42).is_err() {}
- if None::<i32>.is_none() {}
-
- if Some(42).is_some() {}
-
if let Ok(x) = Ok::<i32, i32>(42) {
println!("{}", x);
}
Err(_) => false,
};
- match Some(42) {
- Some(_) => true,
- None => false,
- };
-
- match None::<()> {
- Some(_) => false,
- None => true,
- };
-
- let _ = match None::<()> {
- Some(_) => false,
- None => true,
- };
-
let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
- let opt = Some(false);
- let x = if let Some(_) = opt { true } else { false };
- takes_bool(x);
-
issue5504();
issue6067();
+ issue6065();
- let _ = if let Some(_) = gen_opt() {
+ let _ = if let Ok(_) = gen_res() {
1
- } else if let None = gen_opt() {
- 2
- } else if let Ok(_) = gen_res() {
- 3
} else if let Err(_) = gen_res() {
- 4
+ 2
} else {
- 5
+ 3
};
}
-fn gen_opt() -> Option<()> {
- None
-}
-
fn gen_res() -> Result<(), ()> {
Ok(())
}
-fn takes_bool(_: bool) {}
-
-fn foo() {}
-
-fn bar() {}
-
macro_rules! m {
() => {
Some(42u32)
while let Some(_) = m!() {}
}
+fn issue6065() {
+ macro_rules! if_let_in_macro {
+ ($pat:pat, $x:expr) => {
+ if let Some($pat) = $x {}
+ };
+ }
+
+ // shouldn't be linted
+ if_let_in_macro!(_, Some(42));
+}
+
// Methods that are unstable const should not be suggested within a const context, see issue #5697.
-// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result`, and `is_some` and `is_none`
-// of `Option` were stabilized as const, so the following should be linted.
+// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const,
+// so the following should be linted.
const fn issue6067() {
if let Ok(_) = Ok::<i32, i32>(42) {}
if let Err(_) = Err::<i32, i32>(42) {}
- if let Some(_) = Some(42) {}
-
- if let None = None::<()> {}
-
while let Ok(_) = Ok::<i32, i32>(10) {}
while let Err(_) = Ok::<i32, i32>(10) {}
- while let Some(_) = Some(42) {}
-
- while let None = None::<()> {}
-
match Ok::<i32, i32>(42) {
Ok(_) => true,
Err(_) => false,
Ok(_) => false,
Err(_) => true,
};
-
- match Some(42) {
- Some(_) => true,
- None => false,
- };
-
- match None::<()> {
- Some(_) => false,
- None => true,
- };
}
LL | if let Err(_) = Err::<i32, i32>(42) {}
| -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
-error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:21:12
- |
-LL | if let None = None::<()> {}
- | -------^^^^------------- help: try this: `if None::<()>.is_none()`
-
-error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:23:12
- |
-LL | if let Some(_) = Some(42) {}
- | -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
-
-error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:25:12
- |
-LL | if let Some(_) = Some(42) {
- | -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
-
-error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:31:15
- |
-LL | while let Some(_) = Some(42) {}
- | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
-
-error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:33:15
- |
-LL | while let None = Some(42) {}
- | ----------^^^^----------- help: try this: `while Some(42).is_none()`
-
-error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:35:15
- |
-LL | while let None = None::<()> {}
- | ----------^^^^------------- help: try this: `while None::<()>.is_none()`
-
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:37:15
+ --> $DIR/redundant_pattern_matching.rs:21:15
|
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:39:15
+ --> $DIR/redundant_pattern_matching.rs:23:15
|
LL | while let Err(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
-error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:42:15
- |
-LL | while let Some(_) = v.pop() {
- | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
-
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:58:5
+ --> $DIR/redundant_pattern_matching.rs:33:5
|
LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => true,
| |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:63:5
+ --> $DIR/redundant_pattern_matching.rs:38:5
|
LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => false,
| |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:68:5
+ --> $DIR/redundant_pattern_matching.rs:43:5
|
LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => false,
| |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:73:5
+ --> $DIR/redundant_pattern_matching.rs:48:5
|
LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => true,
LL | | };
| |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
-error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:78:5
- |
-LL | / match Some(42) {
-LL | | Some(_) => true,
-LL | | None => false,
-LL | | };
- | |_____^ help: try this: `Some(42).is_some()`
-
-error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:83:5
- |
-LL | / match None::<()> {
-LL | | Some(_) => false,
-LL | | None => true,
-LL | | };
- | |_____^ help: try this: `None::<()>.is_none()`
-
-error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:88:13
- |
-LL | let _ = match None::<()> {
- | _____________^
-LL | | Some(_) => false,
-LL | | None => true,
-LL | | };
- | |_____^ help: try this: `None::<()>.is_none()`
-
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:93:20
+ --> $DIR/redundant_pattern_matching.rs:53:20
|
LL | let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
| -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
-error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:96:20
- |
-LL | let x = if let Some(_) = opt { true } else { false };
- | -------^^^^^^^------ help: try this: `if opt.is_some()`
-
-error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:102:20
- |
-LL | let _ = if let Some(_) = gen_opt() {
- | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
-
-error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:104:19
- |
-LL | } else if let None = gen_opt() {
- | -------^^^^------------ help: try this: `if gen_opt().is_none()`
-
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:106:19
+ --> $DIR/redundant_pattern_matching.rs:59:20
|
-LL | } else if let Ok(_) = gen_res() {
- | -------^^^^^------------ help: try this: `if gen_res().is_ok()`
+LL | let _ = if let Ok(_) = gen_res() {
+ | -------^^^^^------------ help: try this: `if gen_res().is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:108:19
+ --> $DIR/redundant_pattern_matching.rs:61:19
|
LL | } else if let Err(_) = gen_res() {
| -------^^^^^^------------ help: try this: `if gen_res().is_err()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:141:19
+ --> $DIR/redundant_pattern_matching.rs:84:19
|
LL | while let Some(_) = r#try!(result_opt()) {}
| ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:142:16
+ --> $DIR/redundant_pattern_matching.rs:85:16
|
LL | if let Some(_) = r#try!(result_opt()) {}
| -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:148:12
+ --> $DIR/redundant_pattern_matching.rs:91:12
|
LL | if let Some(_) = m!() {}
| -------^^^^^^^------- help: try this: `if m!().is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:149:15
+ --> $DIR/redundant_pattern_matching.rs:92:15
|
LL | while let Some(_) = m!() {}
| ----------^^^^^^^------- help: try this: `while m!().is_some()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:156:12
+ --> $DIR/redundant_pattern_matching.rs:110:12
|
LL | if let Ok(_) = Ok::<i32, i32>(42) {}
| -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:158:12
+ --> $DIR/redundant_pattern_matching.rs:112:12
|
LL | if let Err(_) = Err::<i32, i32>(42) {}
| -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
-error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:160:12
- |
-LL | if let Some(_) = Some(42) {}
- | -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
-
-error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:162:12
- |
-LL | if let None = None::<()> {}
- | -------^^^^------------- help: try this: `if None::<()>.is_none()`
-
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:164:15
+ --> $DIR/redundant_pattern_matching.rs:114:15
|
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:166:15
+ --> $DIR/redundant_pattern_matching.rs:116:15
|
LL | while let Err(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
-error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:168:15
- |
-LL | while let Some(_) = Some(42) {}
- | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
-
-error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:170:15
- |
-LL | while let None = None::<()> {}
- | ----------^^^^------------- help: try this: `while None::<()>.is_none()`
-
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:172:5
+ --> $DIR/redundant_pattern_matching.rs:118:5
|
LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => true,
| |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:177:5
+ --> $DIR/redundant_pattern_matching.rs:123:5
|
LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => false,
LL | | };
| |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
-error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:182:5
- |
-LL | / match Some(42) {
-LL | | Some(_) => true,
-LL | | None => false,
-LL | | };
- | |_____^ help: try this: `Some(42).is_some()`
-
-error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:187:5
- |
-LL | / match None::<()> {
-LL | | Some(_) => false,
-LL | | None => true,
-LL | | };
- | |_____^ help: try this: `None::<()>.is_none()`
-
-error: aborting due to 41 previous errors
+error: aborting due to 22 previous errors
--- /dev/null
+// run-rustfix
+
+#![warn(clippy::all)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(
+ clippy::unit_arg,
+ unused_must_use,
+ clippy::needless_bool,
+ clippy::match_like_matches_macro,
+ deprecated
+)]
+
+fn main() {
+ if None::<()>.is_none() {}
+
+ if Some(42).is_some() {}
+
+ if Some(42).is_some() {
+ foo();
+ } else {
+ bar();
+ }
+
+ while Some(42).is_some() {}
+
+ while Some(42).is_none() {}
+
+ while None::<()>.is_none() {}
+
+ let mut v = vec![1, 2, 3];
+ while v.pop().is_some() {
+ foo();
+ }
+
+ if None::<i32>.is_none() {}
+
+ if Some(42).is_some() {}
+
+ Some(42).is_some();
+
+ None::<()>.is_none();
+
+ let _ = None::<()>.is_none();
+
+ let opt = Some(false);
+ let x = if opt.is_some() { true } else { false };
+ takes_bool(x);
+
+ issue6067();
+
+ let _ = if gen_opt().is_some() {
+ 1
+ } else if gen_opt().is_none() {
+ 2
+ } else {
+ 3
+ };
+}
+
+fn gen_opt() -> Option<()> {
+ None
+}
+
+fn takes_bool(_: bool) {}
+
+fn foo() {}
+
+fn bar() {}
+
+// Methods that are unstable const should not be suggested within a const context, see issue #5697.
+// However, in Rust 1.48.0 the methods `is_some` and `is_none` of `Option` were stabilized as const,
+// so the following should be linted.
+const fn issue6067() {
+ if Some(42).is_some() {}
+
+ if None::<()>.is_none() {}
+
+ while Some(42).is_some() {}
+
+ while None::<()>.is_none() {}
+
+ Some(42).is_some();
+
+ None::<()>.is_none();
+}
--- /dev/null
+// run-rustfix
+
+#![warn(clippy::all)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(
+ clippy::unit_arg,
+ unused_must_use,
+ clippy::needless_bool,
+ clippy::match_like_matches_macro,
+ deprecated
+)]
+
+fn main() {
+ if let None = None::<()> {}
+
+ if let Some(_) = Some(42) {}
+
+ if let Some(_) = Some(42) {
+ foo();
+ } else {
+ bar();
+ }
+
+ while let Some(_) = Some(42) {}
+
+ while let None = Some(42) {}
+
+ while let None = None::<()> {}
+
+ let mut v = vec![1, 2, 3];
+ while let Some(_) = v.pop() {
+ foo();
+ }
+
+ if None::<i32>.is_none() {}
+
+ if Some(42).is_some() {}
+
+ match Some(42) {
+ Some(_) => true,
+ None => false,
+ };
+
+ match None::<()> {
+ Some(_) => false,
+ None => true,
+ };
+
+ let _ = match None::<()> {
+ Some(_) => false,
+ None => true,
+ };
+
+ let opt = Some(false);
+ let x = if let Some(_) = opt { true } else { false };
+ takes_bool(x);
+
+ issue6067();
+
+ let _ = if let Some(_) = gen_opt() {
+ 1
+ } else if let None = gen_opt() {
+ 2
+ } else {
+ 3
+ };
+}
+
+fn gen_opt() -> Option<()> {
+ None
+}
+
+fn takes_bool(_: bool) {}
+
+fn foo() {}
+
+fn bar() {}
+
+// Methods that are unstable const should not be suggested within a const context, see issue #5697.
+// However, in Rust 1.48.0 the methods `is_some` and `is_none` of `Option` were stabilized as const,
+// so the following should be linted.
+const fn issue6067() {
+ if let Some(_) = Some(42) {}
+
+ if let None = None::<()> {}
+
+ while let Some(_) = Some(42) {}
+
+ while let None = None::<()> {}
+
+ match Some(42) {
+ Some(_) => true,
+ None => false,
+ };
+
+ match None::<()> {
+ Some(_) => false,
+ None => true,
+ };
+}
--- /dev/null
+error: redundant pattern matching, consider using `is_none()`
+ --> $DIR/redundant_pattern_matching_option.rs:14:12
+ |
+LL | if let None = None::<()> {}
+ | -------^^^^------------- help: try this: `if None::<()>.is_none()`
+ |
+ = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+
+error: redundant pattern matching, consider using `is_some()`
+ --> $DIR/redundant_pattern_matching_option.rs:16:12
+ |
+LL | if let Some(_) = Some(42) {}
+ | -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+ --> $DIR/redundant_pattern_matching_option.rs:18:12
+ |
+LL | if let Some(_) = Some(42) {
+ | -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+ --> $DIR/redundant_pattern_matching_option.rs:24:15
+ |
+LL | while let Some(_) = Some(42) {}
+ | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+ --> $DIR/redundant_pattern_matching_option.rs:26:15
+ |
+LL | while let None = Some(42) {}
+ | ----------^^^^----------- help: try this: `while Some(42).is_none()`
+
+error: redundant pattern matching, consider using `is_none()`
+ --> $DIR/redundant_pattern_matching_option.rs:28:15
+ |
+LL | while let None = None::<()> {}
+ | ----------^^^^------------- help: try this: `while None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+ --> $DIR/redundant_pattern_matching_option.rs:31:15
+ |
+LL | while let Some(_) = v.pop() {
+ | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+ --> $DIR/redundant_pattern_matching_option.rs:39:5
+ |
+LL | / match Some(42) {
+LL | | Some(_) => true,
+LL | | None => false,
+LL | | };
+ | |_____^ help: try this: `Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+ --> $DIR/redundant_pattern_matching_option.rs:44:5
+ |
+LL | / match None::<()> {
+LL | | Some(_) => false,
+LL | | None => true,
+LL | | };
+ | |_____^ help: try this: `None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_none()`
+ --> $DIR/redundant_pattern_matching_option.rs:49:13
+ |
+LL | let _ = match None::<()> {
+ | _____________^
+LL | | Some(_) => false,
+LL | | None => true,
+LL | | };
+ | |_____^ help: try this: `None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+ --> $DIR/redundant_pattern_matching_option.rs:55:20
+ |
+LL | let x = if let Some(_) = opt { true } else { false };
+ | -------^^^^^^^------ help: try this: `if opt.is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+ --> $DIR/redundant_pattern_matching_option.rs:60:20
+ |
+LL | let _ = if let Some(_) = gen_opt() {
+ | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+ --> $DIR/redundant_pattern_matching_option.rs:62:19
+ |
+LL | } else if let None = gen_opt() {
+ | -------^^^^------------ help: try this: `if gen_opt().is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+ --> $DIR/redundant_pattern_matching_option.rs:83:12
+ |
+LL | if let Some(_) = Some(42) {}
+ | -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+ --> $DIR/redundant_pattern_matching_option.rs:85:12
+ |
+LL | if let None = None::<()> {}
+ | -------^^^^------------- help: try this: `if None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+ --> $DIR/redundant_pattern_matching_option.rs:87:15
+ |
+LL | while let Some(_) = Some(42) {}
+ | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+ --> $DIR/redundant_pattern_matching_option.rs:89:15
+ |
+LL | while let None = None::<()> {}
+ | ----------^^^^------------- help: try this: `while None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+ --> $DIR/redundant_pattern_matching_option.rs:91:5
+ |
+LL | / match Some(42) {
+LL | | Some(_) => true,
+LL | | None => false,
+LL | | };
+ | |_____^ help: try this: `Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+ --> $DIR/redundant_pattern_matching_option.rs:96:5
+ |
+LL | / match None::<()> {
+LL | | Some(_) => false,
+LL | | None => true,
+LL | | };
+ | |_____^ help: try this: `None::<()>.is_none()`
+
+error: aborting due to 19 previous errors
+
#![allow(unused_parens)]
+#![warn(clippy::verbose_bit_mask)]
fn main() {
let x: i32 = 42;
error: bit mask could be simplified with a call to `trailing_zeros`
- --> $DIR/trailing_zeros.rs:5:13
+ --> $DIR/trailing_zeros.rs:6:13
|
LL | let _ = (x & 0b1111 == 0); // suggest trailing_zeros
| ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 4`
= note: `-D clippy::verbose-bit-mask` implied by `-D warnings`
error: bit mask could be simplified with a call to `trailing_zeros`
- --> $DIR/trailing_zeros.rs:6:13
+ --> $DIR/trailing_zeros.rs:7:13
|
LL | let _ = x & 0b1_1111 == 0; // suggest trailing_zeros
| ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 5`
#![warn(clippy::unnecessary_lazy_evaluations)]
#![allow(clippy::redundant_closure)]
#![allow(clippy::bind_instead_of_map)]
+#![allow(clippy::map_identity)]
struct Deep(Option<usize>);
let _ = opt.unwrap_or(2);
let _ = opt.unwrap_or(astronomers_pi);
let _ = opt.unwrap_or(ext_str.some_field);
- let _ = opt.unwrap_or(ext_arr[0]);
+ let _ = opt.unwrap_or_else(|| ext_arr[0]);
let _ = opt.and(ext_opt);
let _ = opt.or(ext_opt);
let _ = opt.or(None);
let _ = opt.get_or_insert(2);
let _ = opt.ok_or(2);
- let _ = opt.ok_or(ext_arr[0]);
+ let _ = nested_tuple_opt.unwrap_or(Some((1, 2)));
// Cases when unwrap is not called on a simple variable
let _ = Some(10).unwrap_or(2);
// Should not lint - Option
let _ = opt.unwrap_or_else(|| ext_str.return_some_field());
let _ = nested_opt.unwrap_or_else(|| Some(some_call()));
- let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call())));
let _ = opt.or_else(some_call);
let _ = opt.or_else(|| some_call());
let _ = deep.0.get_or_insert_with(|| some_call());
let _ = deep.0.or_else(some_call);
let _ = deep.0.or_else(|| some_call());
+ let _ = opt.ok_or_else(|| ext_arr[0]);
- // These are handled by bind_instead_of_map
+ // should not lint, bind_instead_of_map takes priority
let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
let _ = Some(10).and_then(|idx| Some(idx));
- let _: Option<usize> = None.or_else(|| Some(3));
- let _ = deep.0.or_else(|| Some(3));
- let _ = opt.or_else(|| Some(3));
+
+ // should lint, bind_instead_of_map doesn't apply
+ let _: Option<usize> = None.or(Some(3));
+ let _ = deep.0.or(Some(3));
+ let _ = opt.or(Some(3));
// Should lint - Result
let res: Result<usize, usize> = Err(5);
let _ = res2.unwrap_or_else(|err| err.return_some_field());
let _ = res2.unwrap_or_else(|_| ext_str.return_some_field());
+ // should not lint, bind_instead_of_map takes priority
let _: Result<usize, usize> = res.and_then(|x| Ok(x));
- let _: Result<usize, usize> = res.and_then(|x| Err(x));
-
- let _: Result<usize, usize> = res.or_else(|err| Ok(err));
let _: Result<usize, usize> = res.or_else(|err| Err(err));
- // These are handled by bind_instead_of_map
let _: Result<usize, usize> = res.and_then(|_| Ok(2));
let _: Result<usize, usize> = res.and_then(|_| Ok(astronomers_pi));
let _: Result<usize, usize> = res.and_then(|_| Ok(ext_str.some_field));
- let _: Result<usize, usize> = res.and_then(|_| Err(2));
- let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
- let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
-
- let _: Result<usize, usize> = res.or_else(|_| Ok(2));
- let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
- let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
-
let _: Result<usize, usize> = res.or_else(|_| Err(2));
let _: Result<usize, usize> = res.or_else(|_| Err(astronomers_pi));
let _: Result<usize, usize> = res.or_else(|_| Err(ext_str.some_field));
+
+ // should lint, bind_instead_of_map doesn't apply
+ let _: Result<usize, usize> = res.and(Err(2));
+ let _: Result<usize, usize> = res.and(Err(astronomers_pi));
+ let _: Result<usize, usize> = res.and(Err(ext_str.some_field));
+
+ let _: Result<usize, usize> = res.or(Ok(2));
+ let _: Result<usize, usize> = res.or(Ok(astronomers_pi));
+ let _: Result<usize, usize> = res.or(Ok(ext_str.some_field));
+
+ // neither bind_instead_of_map nor unnecessary_lazy_eval applies here
+ let _: Result<usize, usize> = res.and_then(|x| Err(x));
+ let _: Result<usize, usize> = res.or_else(|err| Ok(err));
}
#![warn(clippy::unnecessary_lazy_evaluations)]
#![allow(clippy::redundant_closure)]
#![allow(clippy::bind_instead_of_map)]
+#![allow(clippy::map_identity)]
struct Deep(Option<usize>);
let _ = opt.or_else(|| None);
let _ = opt.get_or_insert_with(|| 2);
let _ = opt.ok_or_else(|| 2);
- let _ = opt.ok_or_else(|| ext_arr[0]);
+ let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
// Cases when unwrap is not called on a simple variable
let _ = Some(10).unwrap_or_else(|| 2);
// Should not lint - Option
let _ = opt.unwrap_or_else(|| ext_str.return_some_field());
let _ = nested_opt.unwrap_or_else(|| Some(some_call()));
- let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call())));
let _ = opt.or_else(some_call);
let _ = opt.or_else(|| some_call());
let _ = deep.0.get_or_insert_with(|| some_call());
let _ = deep.0.or_else(some_call);
let _ = deep.0.or_else(|| some_call());
+ let _ = opt.ok_or_else(|| ext_arr[0]);
- // These are handled by bind_instead_of_map
+ // should not lint, bind_instead_of_map takes priority
let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
let _ = Some(10).and_then(|idx| Some(idx));
+
+ // should lint, bind_instead_of_map doesn't apply
let _: Option<usize> = None.or_else(|| Some(3));
let _ = deep.0.or_else(|| Some(3));
let _ = opt.or_else(|| Some(3));
let _ = res2.unwrap_or_else(|err| err.return_some_field());
let _ = res2.unwrap_or_else(|_| ext_str.return_some_field());
+ // should not lint, bind_instead_of_map takes priority
let _: Result<usize, usize> = res.and_then(|x| Ok(x));
- let _: Result<usize, usize> = res.and_then(|x| Err(x));
-
- let _: Result<usize, usize> = res.or_else(|err| Ok(err));
let _: Result<usize, usize> = res.or_else(|err| Err(err));
- // These are handled by bind_instead_of_map
let _: Result<usize, usize> = res.and_then(|_| Ok(2));
let _: Result<usize, usize> = res.and_then(|_| Ok(astronomers_pi));
let _: Result<usize, usize> = res.and_then(|_| Ok(ext_str.some_field));
+ let _: Result<usize, usize> = res.or_else(|_| Err(2));
+ let _: Result<usize, usize> = res.or_else(|_| Err(astronomers_pi));
+ let _: Result<usize, usize> = res.or_else(|_| Err(ext_str.some_field));
+
+ // should lint, bind_instead_of_map doesn't apply
let _: Result<usize, usize> = res.and_then(|_| Err(2));
let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
- let _: Result<usize, usize> = res.or_else(|_| Err(2));
- let _: Result<usize, usize> = res.or_else(|_| Err(astronomers_pi));
- let _: Result<usize, usize> = res.or_else(|_| Err(ext_str.some_field));
+ // neither bind_instead_of_map nor unnecessary_lazy_eval applies here
+ let _: Result<usize, usize> = res.and_then(|x| Err(x));
+ let _: Result<usize, usize> = res.or_else(|err| Ok(err));
}
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:34:13
+ --> $DIR/unnecessary_lazy_eval.rs:35:13
|
LL | let _ = opt.unwrap_or_else(|| 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(2)`
= note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:35:13
+ --> $DIR/unnecessary_lazy_eval.rs:36:13
|
LL | let _ = opt.unwrap_or_else(|| astronomers_pi);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(astronomers_pi)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:36:13
+ --> $DIR/unnecessary_lazy_eval.rs:37:13
|
LL | let _ = opt.unwrap_or_else(|| ext_str.some_field);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_str.some_field)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:37:13
- |
-LL | let _ = opt.unwrap_or_else(|| ext_arr[0]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_arr[0])`
-
-error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:38:13
+ --> $DIR/unnecessary_lazy_eval.rs:39:13
|
LL | let _ = opt.and_then(|_| ext_opt);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `opt.and(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:39:13
+ --> $DIR/unnecessary_lazy_eval.rs:40:13
|
LL | let _ = opt.or_else(|| ext_opt);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:40:13
+ --> $DIR/unnecessary_lazy_eval.rs:41:13
|
LL | let _ = opt.or_else(|| None);
| ^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(None)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:41:13
+ --> $DIR/unnecessary_lazy_eval.rs:42:13
|
LL | let _ = opt.get_or_insert_with(|| 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `opt.get_or_insert(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:42:13
+ --> $DIR/unnecessary_lazy_eval.rs:43:13
|
LL | let _ = opt.ok_or_else(|| 2);
| ^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:43:13
+ --> $DIR/unnecessary_lazy_eval.rs:44:13
|
-LL | let _ = opt.ok_or_else(|| ext_arr[0]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(ext_arr[0])`
+LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `nested_tuple_opt.unwrap_or(Some((1, 2)))`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:46:13
+ --> $DIR/unnecessary_lazy_eval.rs:47:13
|
LL | let _ = Some(10).unwrap_or_else(|| 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Some(10).unwrap_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:47:13
+ --> $DIR/unnecessary_lazy_eval.rs:48:13
|
LL | let _ = Some(10).and_then(|_| ext_opt);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `Some(10).and(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:48:28
+ --> $DIR/unnecessary_lazy_eval.rs:49:28
|
LL | let _: Option<usize> = None.or_else(|| ext_opt);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:49:13
+ --> $DIR/unnecessary_lazy_eval.rs:50:13
|
LL | let _ = None.get_or_insert_with(|| 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `None.get_or_insert(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:50:35
+ --> $DIR/unnecessary_lazy_eval.rs:51:35
|
LL | let _: Result<usize, usize> = None.ok_or_else(|| 2);
| ^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `None.ok_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:51:28
+ --> $DIR/unnecessary_lazy_eval.rs:52:28
|
LL | let _: Option<usize> = None.or_else(|| None);
| ^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(None)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:54:13
+ --> $DIR/unnecessary_lazy_eval.rs:55:13
|
LL | let _ = deep.0.unwrap_or_else(|| 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `deep.0.unwrap_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:55:13
+ --> $DIR/unnecessary_lazy_eval.rs:56:13
|
LL | let _ = deep.0.and_then(|_| ext_opt);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `deep.0.and(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:56:13
+ --> $DIR/unnecessary_lazy_eval.rs:57:13
|
LL | let _ = deep.0.or_else(|| None);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(None)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:57:13
+ --> $DIR/unnecessary_lazy_eval.rs:58:13
|
LL | let _ = deep.0.get_or_insert_with(|| 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `deep.0.get_or_insert(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:58:13
+ --> $DIR/unnecessary_lazy_eval.rs:59:13
|
LL | let _ = deep.0.ok_or_else(|| 2);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `deep.0.ok_or(2)`
+error: unnecessary closure used to substitute value for `Option::None`
+ --> $DIR/unnecessary_lazy_eval.rs:79:28
+ |
+LL | let _: Option<usize> = None.or_else(|| Some(3));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(Some(3))`
+
+error: unnecessary closure used to substitute value for `Option::None`
+ --> $DIR/unnecessary_lazy_eval.rs:80:13
+ |
+LL | let _ = deep.0.or_else(|| Some(3));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(Some(3))`
+
+error: unnecessary closure used to substitute value for `Option::None`
+ --> $DIR/unnecessary_lazy_eval.rs:81:13
+ |
+LL | let _ = opt.or_else(|| Some(3));
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(Some(3))`
+
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:84:13
+ --> $DIR/unnecessary_lazy_eval.rs:87:13
|
LL | let _ = res2.unwrap_or_else(|_| 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(2)`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:85:13
+ --> $DIR/unnecessary_lazy_eval.rs:88:13
|
LL | let _ = res2.unwrap_or_else(|_| astronomers_pi);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(astronomers_pi)`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:86:13
+ --> $DIR/unnecessary_lazy_eval.rs:89:13
|
LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)`
-error: aborting due to 24 previous errors
+error: unnecessary closure used to substitute value for `Result::Err`
+ --> $DIR/unnecessary_lazy_eval.rs:111:35
+ |
+LL | let _: Result<usize, usize> = res.and_then(|_| Err(2));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(2))`
+
+error: unnecessary closure used to substitute value for `Result::Err`
+ --> $DIR/unnecessary_lazy_eval.rs:112:35
+ |
+LL | let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(astronomers_pi))`
+
+error: unnecessary closure used to substitute value for `Result::Err`
+ --> $DIR/unnecessary_lazy_eval.rs:113:35
+ |
+LL | let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(ext_str.some_field))`
+
+error: unnecessary closure used to substitute value for `Result::Err`
+ --> $DIR/unnecessary_lazy_eval.rs:115:35
+ |
+LL | let _: Result<usize, usize> = res.or_else(|_| Ok(2));
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(2))`
+
+error: unnecessary closure used to substitute value for `Result::Err`
+ --> $DIR/unnecessary_lazy_eval.rs:116:35
+ |
+LL | let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(astronomers_pi))`
+
+error: unnecessary closure used to substitute value for `Result::Err`
+ --> $DIR/unnecessary_lazy_eval.rs:117:35
+ |
+LL | let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(ext_str.some_field))`
+
+error: aborting due to 32 previous errors
-error: useless conversion to the same type
+error: useless conversion to the same type: `T`
--> $DIR/useless_conversion.rs:6:13
|
LL | let _ = T::from(val);
LL | #![deny(clippy::useless_conversion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: useless conversion to the same type
+error: useless conversion to the same type: `T`
--> $DIR/useless_conversion.rs:7:5
|
LL | val.into()
| ^^^^^^^^^^ help: consider removing `.into()`: `val`
-error: useless conversion to the same type
+error: useless conversion to the same type: `i32`
--> $DIR/useless_conversion.rs:19:22
|
LL | let _: i32 = 0i32.into();
| ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
--> $DIR/useless_conversion.rs:60:21
|
LL | let _: String = "foo".to_string().into();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
--> $DIR/useless_conversion.rs:61:21
|
LL | let _: String = From::from("foo".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
--> $DIR/useless_conversion.rs:62:13
|
LL | let _ = String::from("foo".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
--> $DIR/useless_conversion.rs:63:13
|
LL | let _ = String::from(format!("A: {:04}", 123));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::str::Lines`
--> $DIR/useless_conversion.rs:64:13
|
LL | let _ = "".lines().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::vec::IntoIter<i32>`
--> $DIR/useless_conversion.rs:65:13
|
LL | let _ = vec![1, 2, 3].into_iter().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
--> $DIR/useless_conversion.rs:66:21
|
LL | let _: String = format!("Hello {}", "world").into();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
-error: useless conversion to the same type
+error: useless conversion to the same type: `i32`
--> $DIR/useless_conversion.rs:71:13
|
LL | let _ = i32::from(a + b) * 3;
-error: useless conversion to the same type
+error: useless conversion to the same type: `T`
--> $DIR/useless_conversion_try.rs:6:13
|
LL | let _ = T::try_from(val).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider removing `T::try_from()`
-error: useless conversion to the same type
+error: useless conversion to the same type: `T`
--> $DIR/useless_conversion_try.rs:7:5
|
LL | val.try_into().unwrap()
|
= help: consider removing `.try_into()`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
--> $DIR/useless_conversion_try.rs:29:21
|
LL | let _: String = "foo".to_string().try_into().unwrap();
|
= help: consider removing `.try_into()`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
--> $DIR/useless_conversion_try.rs:30:21
|
LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap();
|
= help: consider removing `TryFrom::try_from()`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
--> $DIR/useless_conversion_try.rs:31:13
|
LL | let _ = String::try_from("foo".to_string()).unwrap();
|
= help: consider removing `String::try_from()`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
--> $DIR/useless_conversion_try.rs:32:13
|
LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap();
|
= help: consider removing `String::try_from()`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
--> $DIR/useless_conversion_try.rs:33:21
|
LL | let _: String = format!("Hello {}", "world").try_into().unwrap();
|
= help: consider removing `.try_into()`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
--> $DIR/useless_conversion_try.rs:34:21
|
LL | let _: String = "".to_owned().try_into().unwrap();
|
= help: consider removing `.try_into()`
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
--> $DIR/useless_conversion_try.rs:35:27
|
LL | let _: String = match String::from("_").try_into() {
write!(&mut v, "Hello {}\n", "world");
write!(&mut v, "Hello {} {}\n", "world", "#2");
write!(&mut v, "{}\n", 1265);
+ write!(&mut v, "\n");
// These should be fine
write!(&mut v, "");
| ^^^^^^^ --
error: using `write!()` with a format string that ends in a single newline
- --> $DIR/write_with_newline.rs:35:5
+ --> $DIR/write_with_newline.rs:17:5
+ |
+LL | write!(&mut v, "/n");
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+help: use `writeln!()` instead
+ |
+LL | writeln!(&mut v, );
+ | ^^^^^^^ --
+
+error: using `write!()` with a format string that ends in a single newline
+ --> $DIR/write_with_newline.rs:36:5
|
LL | write!(&mut v, "//n"); // should fail
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^ --
error: using `write!()` with a format string that ends in a single newline
- --> $DIR/write_with_newline.rs:42:5
+ --> $DIR/write_with_newline.rs:43:5
|
LL | / write!(
LL | | &mut v,
|
error: using `write!()` with a format string that ends in a single newline
- --> $DIR/write_with_newline.rs:47:5
+ --> $DIR/write_with_newline.rs:48:5
|
LL | / write!(
LL | | &mut v,
|
error: using `write!()` with a format string that ends in a single newline
- --> $DIR/write_with_newline.rs:56:5
+ --> $DIR/write_with_newline.rs:57:5
|
LL | write!(&mut v, "/r/n"); //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^ --
error: using `write!()` with a format string that ends in a single newline
- --> $DIR/write_with_newline.rs:57:5
+ --> $DIR/write_with_newline.rs:58:5
|
LL | write!(&mut v, "foo/rbar/n");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | writeln!(&mut v, "foo/rbar");
| ^^^^^^^ --
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
[relabel]
allow-unauthenticated = [
- "C-*", "A-*", "E-*", "L-*", "M-*", "O-*",
+ "C-*", "A-*", "E-*", "L-*", "M-*", "O-*", "S-*",
"good first issue", "needs test"
]