Merge commit 'e636b88aa180e8cab9e28802aac90adbc984234d' into clippyup

This commit is contained in:
flip1995 2020-09-24 14:49:22 +02:00
commit f1f1e0ba8e
No known key found for this signature in database
GPG key ID: 693086869D506637
110 changed files with 3425 additions and 972 deletions

View file

@ -1672,10 +1672,12 @@ Released 2018-09-13
[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`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_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_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 [`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 [`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_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_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_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_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 [`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
@ -1755,6 +1757,7 @@ Released 2018-09-13
[`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing [`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 [`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`]: 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 [`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 [`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 [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
@ -1774,6 +1777,7 @@ Released 2018-09-13
[`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one [`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_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 [`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_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_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 [`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure

View file

@ -8,7 +8,7 @@ something. We appreciate any sort of contributions, and don't want a wall of rul
Clippy welcomes contributions from everyone. There are many ways to contribute to Clippy and the following document 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 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]. All contributors are expected to follow the [Rust Code of Conduct].
@ -23,7 +23,7 @@ All contributors are expected to follow the [Rust Code of Conduct].
- [Bors and Homu](#bors-and-homu) - [Bors and Homu](#bors-and-homu)
- [Contributions](#contributions) - [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 [Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
## Getting started ## Getting started
@ -242,7 +242,7 @@ to be run inside the `rust` directory):
``` ```
3. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to 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 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`] ### Syncing back changes in Clippy to [`rust-lang/rust`]

View file

@ -14,7 +14,7 @@ pub fn run(rustc_path: Option<&str>) {
// we can unwrap here because the arg is required here // we can unwrap here because the arg is required here
let rustc_path = PathBuf::from(rustc_path.unwrap()); let rustc_path = PathBuf::from(rustc_path.unwrap());
assert!(rustc_path.is_dir(), "path is not a directory"); 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!( assert!(
rustc_source_basedir.is_dir(), rustc_source_basedir.is_dir(),
"are you sure the path leads to a rustc repo?" "are you sure the path leads to a rustc repo?"
@ -61,7 +61,7 @@ fn inject_deps_into_manifest(
let new_deps = extern_crates.map(|dep| { let new_deps = extern_crates.map(|dep| {
// format the dependencies that are going to be put inside the Cargo.toml // format the dependencies that are going to be put inside the Cargo.toml
format!( format!(
"{dep} = {{ path = \"{source_path}/lib{dep}\" }}\n", "{dep} = {{ path = \"{source_path}/{dep}\" }}\n",
dep = dep, dep = dep,
source_path = rustc_source_dir.display() source_path = rustc_source_dir.display()
) )

View file

@ -21,7 +21,7 @@ cargo_metadata = "0.11.1"
if_chain = "1.0.0" if_chain = "1.0.0"
itertools = "0.9" itertools = "0.9"
lazy_static = "1.0.2" 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" quine-mc_cluskey = "0.2.2"
regex-syntax = "0.6" regex-syntax = "0.6"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }

View file

@ -8,7 +8,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! { declare_clippy_lint! {
/// **What it does:** Checks for usage of invalid atomic /// **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 /// **Why is this bad?** Using an invalid atomic ordering
/// will cause a panic at run-time. /// will cause a panic at run-time.
@ -17,22 +18,35 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust,no_run /// ```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::Release);
/// let _ = x.load(Ordering::AcqRel); /// let _ = x.load(Ordering::AcqRel);
/// ///
/// x.store(false, Ordering::Acquire); /// // Bad: `Acquire` and `AcqRel` cannot be used for `store`.
/// x.store(false, Ordering::AcqRel); /// 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::fence(Ordering::Relaxed);
/// atomic::compiler_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, pub INVALID_ATOMIC_ORDERING,
correctness, 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]); declare_lint_pass!(AtomicOrdering => [INVALID_ATOMIC_ORDERING]);
@ -127,9 +141,89 @@ fn check_memory_fence(cx: &LateContext<'_>, expr: &Expr<'_>) {
} }
} }
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 { impl<'tcx> LateLintPass<'tcx> for AtomicOrdering {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
check_atomic_load_store(cx, expr); check_atomic_load_store(cx, expr);
check_memory_fence(cx, expr); check_memory_fence(cx, expr);
check_atomic_compare_exchange(cx, expr);
} }
} }

View file

@ -10,7 +10,7 @@ declare_clippy_lint! {
/// **What it does:** Checks for calls to await while holding a /// **What it does:** Checks for calls to await while holding a
/// non-async-aware MutexGuard. /// 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. /// 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 /// There are two potential solutions. One is to use an asynx-aware Mutex

View file

@ -90,7 +90,7 @@ declare_clippy_lint! {
/// if x & 0b1111 == 0 { } /// if x & 0b1111 == 0 { }
/// ``` /// ```
pub VERBOSE_BIT_MASK, pub VERBOSE_BIT_MASK,
style, pedantic,
"expressions where a bit mask is less readable than the corresponding method call" "expressions where a bit mask is less readable than the corresponding method call"
} }

View file

@ -1,6 +1,5 @@
use crate::utils::{ use crate::utils::{
contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability, contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability, span_lint_and_sugg,
span_lint_and_sugg, walk_ptrs_ty,
}; };
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::UintTy; use rustc_ast::ast::UintTy;
@ -53,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
if let ExprKind::Binary(ref op, ref l, ref r) = body.value.kind; if let ExprKind::Binary(ref op, ref l, ref r) = body.value.kind;
if op.node == BinOpKind::Eq; if op.node == BinOpKind::Eq;
if match_type(cx, 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); &paths::SLICE_ITER);
then { then {
let needle = match get_path_name(l) { let needle = match get_path_name(l) {
@ -63,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
_ => { return; } _ => { 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; return;
} }
let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) = let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) =

View file

@ -21,7 +21,7 @@ pub enum Constant {
/// A `String` (e.g., "abc"). /// A `String` (e.g., "abc").
Str(String), Str(String),
/// A binary string (e.g., `b"abc"`). /// A binary string (e.g., `b"abc"`).
Binary(Lrc<Vec<u8>>), Binary(Lrc<[u8]>),
/// A single `char` (e.g., `'a'`). /// A single `char` (e.g., `'a'`).
Char(char), Char(char),
/// An integer's bit representation. /// An integer's bit representation.
@ -155,7 +155,7 @@ pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
match *lit { match *lit {
LitKind::Str(ref is, _) => Constant::Str(is.to_string()), LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
LitKind::Byte(b) => Constant::Int(u128::from(b)), 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::Char(c) => Constant::Char(c),
LitKind::Int(n, _) => Constant::Int(n), LitKind::Int(n, _) => Constant::Int(n),
LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty { LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {

View file

@ -534,7 +534,7 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
return false; 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().all(char::is_alphanumeric)
&& s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1

View file

@ -7,7 +7,7 @@ use rustc_span::source_map::Spanned;
use crate::consts::{constant, Constant}; use crate::consts::{constant, Constant};
use crate::utils::paths; 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! { declare_clippy_lint! {
/// **What it does:** Checks for calculation of subsecond microseconds or milliseconds /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds
@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for DurationSubsec {
if_chain! { if_chain! {
if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.kind; 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 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); if let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right);
then { then {
let suggested_fn = match (method_path.ident.as_str().as_ref(), divisor) { let suggested_fn = match (method_path.ident.as_str().as_ref(), divisor) {

View file

@ -1,6 +1,6 @@
use crate::utils::SpanlessEq; use crate::utils::SpanlessEq;
use crate::utils::{get_item_name, higher, is_type_diagnostic_item, match_type, paths, snippet, snippet_opt}; 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 if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
@ -106,7 +106,7 @@ fn check_cond<'a>(cx: &LateContext<'_>, check: &'a Expr<'a>) -> Option<(&'static
if let ExprKind::AddrOf(BorrowKind::Ref, _, ref key) = params[1].kind; if let ExprKind::AddrOf(BorrowKind::Ref, _, ref key) = params[1].kind;
then { then {
let map = &params[0]; let map = &params[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) { return if match_type(cx, obj_ty, &paths::BTREEMAP) {
Some(("BTreeMap", map, key)) Some(("BTreeMap", map, key))

View file

@ -1,7 +1,5 @@
use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT}; use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT};
use crate::utils::{ use crate::utils::{is_expn_of, is_type_diagnostic_item, match_def_path, method_chain_args, span_lint_and_then};
is_expn_of, is_type_diagnostic_item, match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty,
};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
@ -96,7 +94,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
// check for `unwrap` // check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["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)) if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
|| is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
{ {

View file

@ -1,7 +1,7 @@
use crate::utils::paths; use crate::utils::paths;
use crate::utils::{ use crate::utils::{
is_expn_of, is_type_diagnostic_item, last_path_segment, match_def_path, match_function_call, snippet, 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 if_chain::if_chain;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
@ -90,7 +90,7 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: &
if let PatKind::Tuple(ref pats, None) = arms[0].pat.kind; if let PatKind::Tuple(ref pats, None) = arms[0].pat.kind;
if pats.len() == 1; if pats.len() == 1;
then { 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)) { if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) {
return None; return None;
} }

View file

@ -88,7 +88,7 @@ declare_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]
impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Index(ref array, ref index) = &expr.kind { 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) { if let Some(range) = higher::range(index) {
// Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..] // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
if let ty::Array(_, s) = ty.kind() { if let ty::Array(_, s) = ty.kind() {

View file

@ -5,7 +5,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
use crate::utils::{ use crate::utils::{
get_trait_def_id, implements_trait, is_type_diagnostic_item, paths, return_ty, span_lint_and_help, 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! { declare_clippy_lint! {
@ -125,7 +125,7 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
// Get the real type of 'self' // Get the real type of 'self'
let fn_def_id = cx.tcx.hir().local_def_id(item.hir_id); 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 = 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 // Emit either a warning or an error
if implements_trait(cx, self_type, display_trait_id, &[]) { if implements_trait(cx, self_type, display_trait_id, &[]) {

View file

@ -1,4 +1,4 @@
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_ast::ast::LitKind;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -285,7 +285,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
}) })
} }
let ty = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)); let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
match ty.kind() { match ty.kind() {
ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| { ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| {
cx.tcx cx.tcx

View file

@ -230,7 +230,9 @@ mod macro_use;
mod main_recursion; mod main_recursion;
mod manual_async_fn; mod manual_async_fn;
mod manual_non_exhaustive; mod manual_non_exhaustive;
mod manual_strip;
mod map_clone; mod map_clone;
mod map_err_ignore;
mod map_identity; mod map_identity;
mod map_unit_fn; mod map_unit_fn;
mod match_on_vec_items; mod match_on_vec_items;
@ -269,6 +271,7 @@ mod open_options;
mod option_env_unwrap; mod option_env_unwrap;
mod option_if_let_else; mod option_if_let_else;
mod overflow_check_conditional; mod overflow_check_conditional;
mod panic_in_result_fn;
mod panic_unimplemented; mod panic_unimplemented;
mod partialeq_ne_impl; mod partialeq_ne_impl;
mod path_buf_push_overwrite; mod path_buf_push_overwrite;
@ -625,7 +628,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&main_recursion::MAIN_RECURSION, &main_recursion::MAIN_RECURSION,
&manual_async_fn::MANUAL_ASYNC_FN, &manual_async_fn::MANUAL_ASYNC_FN,
&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
&manual_strip::MANUAL_STRIP,
&map_clone::MAP_CLONE, &map_clone::MAP_CLONE,
&map_err_ignore::MAP_ERR_IGNORE,
&map_identity::MAP_IDENTITY, &map_identity::MAP_IDENTITY,
&map_unit_fn::OPTION_MAP_UNIT_FN, &map_unit_fn::OPTION_MAP_UNIT_FN,
&map_unit_fn::RESULT_MAP_UNIT_FN, &map_unit_fn::RESULT_MAP_UNIT_FN,
@ -751,6 +756,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&option_env_unwrap::OPTION_ENV_UNWRAP, &option_env_unwrap::OPTION_ENV_UNWRAP,
&option_if_let_else::OPTION_IF_LET_ELSE, &option_if_let_else::OPTION_IF_LET_ELSE,
&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
&panic_in_result_fn::PANIC_IN_RESULT_FN,
&panic_unimplemented::PANIC, &panic_unimplemented::PANIC,
&panic_unimplemented::PANIC_PARAMS, &panic_unimplemented::PANIC_PARAMS,
&panic_unimplemented::TODO, &panic_unimplemented::TODO,
@ -835,6 +841,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&types::LET_UNIT_VALUE, &types::LET_UNIT_VALUE,
&types::LINKEDLIST, &types::LINKEDLIST,
&types::OPTION_OPTION, &types::OPTION_OPTION,
&types::RC_BUFFER,
&types::REDUNDANT_ALLOCATION, &types::REDUNDANT_ALLOCATION,
&types::TYPE_COMPLEXITY, &types::TYPE_COMPLEXITY,
&types::UNIT_ARG, &types::UNIT_ARG,
@ -863,6 +870,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&utils::internal_lints::COMPILER_LINT_FUNCTIONS, &utils::internal_lints::COMPILER_LINT_FUNCTIONS,
&utils::internal_lints::DEFAULT_LINT, &utils::internal_lints::DEFAULT_LINT,
&utils::internal_lints::LINT_WITHOUT_LINT_PASS, &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::OUTER_EXPN_EXPN_DATA,
&utils::internal_lints::PRODUCE_ICE, &utils::internal_lints::PRODUCE_ICE,
&vec::USELESS_VEC, &vec::USELESS_VEC,
@ -918,6 +926,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub); store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
store.register_late_pass(|| box methods::Methods); store.register_late_pass(|| box methods::Methods);
store.register_late_pass(|| box map_clone::MapClone); 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 shadow::Shadow);
store.register_late_pass(|| box types::LetUnitValue); store.register_late_pass(|| box types::LetUnitValue);
store.register_late_pass(|| box types::UnitCmp); store.register_late_pass(|| box types::UnitCmp);
@ -1091,6 +1100,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); store.register_early_pass(|| box redundant_field_names::RedundantFieldNames);
store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero); 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; let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
store.register_early_pass(move || box non_expressive_names::NonExpressiveNames { store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
single_char_binding_names_threshold, single_char_binding_names_threshold,
@ -1105,6 +1116,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box self_assignment::SelfAssignment); store.register_late_pass(|| box self_assignment::SelfAssignment);
store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); 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![ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(&arithmetic::FLOAT_ARITHMETIC), LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@ -1135,6 +1148,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
LintId::of(&modulo_arithmetic::MODULO_ARITHMETIC), 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::PANIC),
LintId::of(&panic_unimplemented::TODO), LintId::of(&panic_unimplemented::TODO),
LintId::of(&panic_unimplemented::UNIMPLEMENTED), LintId::of(&panic_unimplemented::UNIMPLEMENTED),
@ -1152,6 +1166,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(&attrs::INLINE_ALWAYS), LintId::of(&attrs::INLINE_ALWAYS),
LintId::of(&await_holding_lock::AWAIT_HOLDING_LOCK), LintId::of(&await_holding_lock::AWAIT_HOLDING_LOCK),
LintId::of(&bit_mask::VERBOSE_BIT_MASK),
LintId::of(&checked_conversions::CHECKED_CONVERSIONS), LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
LintId::of(&copies::MATCH_SAME_ARMS), LintId::of(&copies::MATCH_SAME_ARMS),
LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION), LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
@ -1180,6 +1195,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
LintId::of(&loops::EXPLICIT_ITER_LOOP), LintId::of(&loops::EXPLICIT_ITER_LOOP),
LintId::of(&macro_use::MACRO_USE_IMPORTS), LintId::of(&macro_use::MACRO_USE_IMPORTS),
LintId::of(&map_err_ignore::MAP_ERR_IGNORE),
LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS),
LintId::of(&matches::MATCH_BOOL), LintId::of(&matches::MATCH_BOOL),
LintId::of(&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), LintId::of(&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
@ -1230,6 +1246,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS), LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS),
LintId::of(&utils::internal_lints::DEFAULT_LINT), LintId::of(&utils::internal_lints::DEFAULT_LINT),
LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS), 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::OUTER_EXPN_EXPN_DATA),
LintId::of(&utils::internal_lints::PRODUCE_ICE), LintId::of(&utils::internal_lints::PRODUCE_ICE),
]); ]);
@ -1249,7 +1266,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&attrs::USELESS_ATTRIBUTE), LintId::of(&attrs::USELESS_ATTRIBUTE),
LintId::of(&bit_mask::BAD_BIT_MASK), LintId::of(&bit_mask::BAD_BIT_MASK),
LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
LintId::of(&bit_mask::VERBOSE_BIT_MASK),
LintId::of(&blacklisted_name::BLACKLISTED_NAME), LintId::of(&blacklisted_name::BLACKLISTED_NAME),
LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
LintId::of(&booleans::LOGIC_BUG), LintId::of(&booleans::LOGIC_BUG),
@ -1330,6 +1346,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&main_recursion::MAIN_RECURSION), LintId::of(&main_recursion::MAIN_RECURSION),
LintId::of(&manual_async_fn::MANUAL_ASYNC_FN), LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
LintId::of(&manual_strip::MANUAL_STRIP),
LintId::of(&map_clone::MAP_CLONE), LintId::of(&map_clone::MAP_CLONE),
LintId::of(&map_identity::MAP_IDENTITY), LintId::of(&map_identity::MAP_IDENTITY),
LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
@ -1474,6 +1491,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&types::CHAR_LIT_AS_U8), LintId::of(&types::CHAR_LIT_AS_U8),
LintId::of(&types::FN_TO_NUMERIC_CAST), LintId::of(&types::FN_TO_NUMERIC_CAST),
LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
LintId::of(&types::RC_BUFFER),
LintId::of(&types::REDUNDANT_ALLOCATION), LintId::of(&types::REDUNDANT_ALLOCATION),
LintId::of(&types::TYPE_COMPLEXITY), LintId::of(&types::TYPE_COMPLEXITY),
LintId::of(&types::UNIT_ARG), LintId::of(&types::UNIT_ARG),
@ -1507,7 +1525,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&assign_ops::ASSIGN_OP_PATTERN), LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS), LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS),
LintId::of(&bit_mask::VERBOSE_BIT_MASK),
LintId::of(&blacklisted_name::BLACKLISTED_NAME), LintId::of(&blacklisted_name::BLACKLISTED_NAME),
LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
LintId::of(&collapsible_if::COLLAPSIBLE_IF), LintId::of(&collapsible_if::COLLAPSIBLE_IF),
@ -1622,6 +1639,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&loops::EXPLICIT_COUNTER_LOOP), LintId::of(&loops::EXPLICIT_COUNTER_LOOP),
LintId::of(&loops::MUT_RANGE_BOUND), LintId::of(&loops::MUT_RANGE_BOUND),
LintId::of(&loops::WHILE_LET_LOOP), LintId::of(&loops::WHILE_LET_LOOP),
LintId::of(&manual_strip::MANUAL_STRIP),
LintId::of(&map_identity::MAP_IDENTITY), LintId::of(&map_identity::MAP_IDENTITY),
LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
@ -1775,6 +1793,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
LintId::of(&types::BOX_VEC), LintId::of(&types::BOX_VEC),
LintId::of(&types::RC_BUFFER),
LintId::of(&types::REDUNDANT_ALLOCATION), LintId::of(&types::REDUNDANT_ALLOCATION),
LintId::of(&vec::USELESS_VEC), LintId::of(&vec::USELESS_VEC),
]); ]);

View file

@ -1114,7 +1114,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&
if let Some(self_expr) = args.get(0); if let Some(self_expr) = args.get(0);
if let Some(pushed_item) = args.get(1); if let Some(pushed_item) = args.get(1);
// Check that the method being called is push() on a Vec // 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"; if path.ident.name.as_str() == "push";
then { then {
return Some((self_expr, pushed_item)) return Some((self_expr, pushed_item))
@ -2601,11 +2601,9 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
span, span,
NEEDLESS_COLLECT_MSG, NEEDLESS_COLLECT_MSG,
|diag| { |diag| {
let (arg, pred) = if contains_arg.starts_with('&') { let (arg, pred) = contains_arg
("x", &contains_arg[1..]) .strip_prefix('&')
} else { .map_or(("&x", &*contains_arg), |s| ("x", s));
("&x", &*contains_arg)
};
diag.span_suggestion( diag.span_suggestion(
span, span,
"replace with", "replace with",

View file

@ -0,0 +1,245 @@
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
}

View file

@ -0,0 +1,147 @@
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",
);
}
}
}
}
}
}
}
}

View file

@ -1,4 +1,3 @@
use crate::utils::walk_ptrs_ty;
use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg}; use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -90,12 +89,12 @@ fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti
fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(expr); 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)) is_type_diagnostic_item(cx, ty, sym!(vec_type))
} }
fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(expr); 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) is_type_lang_item(cx, ty, LangItem::RangeFull)
} }

View file

@ -6,7 +6,7 @@ use crate::utils::{
expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, 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, 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, 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 if_chain::if_chain;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
@ -502,7 +502,7 @@ impl_lint_pass!(Matches => [
impl<'tcx> LateLintPass<'tcx> for Matches { impl<'tcx> LateLintPass<'tcx> for Matches {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { 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; return;
} }
@ -794,7 +794,7 @@ fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms
} }
fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { 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)) { if is_type_diagnostic_item(cx, ex_ty, sym!(result_type)) {
for arm in arms { for arm in arms {
if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind { if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind {

View file

@ -12,6 +12,7 @@ use rustc_middle::hir::map::Map;
use rustc_span::Span; use rustc_span::Span;
pub(crate) struct OptionAndThenSome; pub(crate) struct OptionAndThenSome;
impl BindInsteadOfMap for OptionAndThenSome { impl BindInsteadOfMap for OptionAndThenSome {
const TYPE_NAME: &'static str = "Option"; const TYPE_NAME: &'static str = "Option";
const TYPE_QPATH: &'static [&'static str] = &paths::OPTION; const TYPE_QPATH: &'static [&'static str] = &paths::OPTION;
@ -24,6 +25,7 @@ impl BindInsteadOfMap for OptionAndThenSome {
} }
pub(crate) struct ResultAndThenOk; pub(crate) struct ResultAndThenOk;
impl BindInsteadOfMap for ResultAndThenOk { impl BindInsteadOfMap for ResultAndThenOk {
const TYPE_NAME: &'static str = "Result"; const TYPE_NAME: &'static str = "Result";
const TYPE_QPATH: &'static [&'static str] = &paths::RESULT; const TYPE_QPATH: &'static [&'static str] = &paths::RESULT;
@ -36,6 +38,7 @@ impl BindInsteadOfMap for ResultAndThenOk {
} }
pub(crate) struct ResultOrElseErrInfo; pub(crate) struct ResultOrElseErrInfo;
impl BindInsteadOfMap for ResultOrElseErrInfo { impl BindInsteadOfMap for ResultOrElseErrInfo {
const TYPE_NAME: &'static str = "Result"; const TYPE_NAME: &'static str = "Result";
const TYPE_QPATH: &'static [&'static str] = &paths::RESULT; const TYPE_QPATH: &'static [&'static str] = &paths::RESULT;
@ -120,9 +123,9 @@ pub(crate) trait BindInsteadOfMap {
} }
} }
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 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_chain! {
if !in_macro(ret_expr.span); if !in_macro(ret_expr.span);
if let hir::ExprKind::Call(ref func_path, ref args) = ret_expr.kind; if let hir::ExprKind::Call(ref func_path, ref args) = ret_expr.kind;
@ -153,12 +156,13 @@ pub(crate) trait BindInsteadOfMap {
) )
}); });
} }
can_sugg
} }
/// Lint use of `_.and_then(|x| Some(y))` for `Option`s /// 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) { if !match_type(cx, cx.typeck_results().expr_ty(&args[0]), Self::TYPE_QPATH) {
return; return false;
} }
match args[1].kind { match args[1].kind {
@ -166,8 +170,10 @@ pub(crate) trait BindInsteadOfMap {
let closure_body = cx.tcx.hir().body(body_id); let closure_body = cx.tcx.hir().body(body_id);
let closure_expr = remove_blocks(&closure_body.value); let closure_expr = remove_blocks(&closure_body.value);
if !Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) { if Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) {
Self::lint_closure(cx, expr, closure_expr); true
} else {
Self::lint_closure(cx, expr, closure_expr)
} }
}, },
// `_.and_then(Some)` case, which is no-op. // `_.and_then(Some)` case, which is no-op.
@ -181,8 +187,9 @@ pub(crate) trait BindInsteadOfMap {
snippet(cx, args[0].span, "..").into(), snippet(cx, args[0].span, "..").into(),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
true
}, },
_ => {}, _ => false,
} }
} }
} }

View file

@ -25,14 +25,15 @@ use rustc_span::source_map::Span;
use rustc_span::symbol::{sym, SymbolStr}; use rustc_span::symbol::{sym, SymbolStr};
use crate::consts::{constant, Constant}; use crate::consts::{constant, Constant};
use crate::utils::eager_or_lazy::is_lazyness_candidate;
use crate::utils::usage::mutated_variables; use crate::utils::usage::mutated_variables;
use crate::utils::{ use crate::utils::{
contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, 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, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath,
last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty,
method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth,
span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, SpanlessEq,
}; };
declare_clippy_lint! { declare_clippy_lint! {
@ -1454,18 +1455,21 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]), ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]),
["unwrap_or_else", "map"] => { ["unwrap_or_else", "map"] => {
if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) { 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]), ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]),
["and_then", ..] => { ["and_then", ..] => {
unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "and"); let biom_option_linted = bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]);
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]);
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", ..] => { ["or_else", ..] => {
unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "or"); if !bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]) {
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", "filter"] => lint_filter_next(cx, expr, arg_lists[1]),
["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]), ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]),
@ -1508,9 +1512,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), ["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_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), ["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"), ["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], true, "get_or_insert"), ["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], true, "ok_or"), ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"),
_ => {}, _ => {},
} }
@ -1714,37 +1718,6 @@ fn lint_or_fun_call<'tcx>(
name: &str, name: &str,
args: &'tcx [hir::Expr<'_>], 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())`. /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
fn check_unwrap_or_default( fn check_unwrap_or_default(
cx: &LateContext<'_>, cx: &LateContext<'_>,
@ -1801,14 +1774,14 @@ fn lint_or_fun_call<'tcx>(
) { ) {
if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind { if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind {
if path.ident.as_str() == "len" { 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() { match ty.kind() {
ty::Slice(_) | ty::Array(_, _) => return, ty::Slice(_) | ty::Array(_, _) => return,
_ => (), _ => (),
} }
if match_type(cx, ty, &paths::VEC) { if is_type_diagnostic_item(cx, ty, sym!(vec_type)) {
return; return;
} }
} }
@ -1825,8 +1798,7 @@ fn lint_or_fun_call<'tcx>(
if_chain! { if_chain! {
if know_types.iter().any(|k| k.2.contains(&name)); if know_types.iter().any(|k| k.2.contains(&name));
let mut finder = FunCallFinder { cx: &cx, found: false }; if is_lazyness_candidate(cx, arg);
if { finder.visit_expr(&arg); finder.found };
if !contains_return(&arg); if !contains_return(&arg);
let self_ty = cx.typeck_results().expr_ty(self_expr); let self_ty = cx.typeck_results().expr_ty(self_expr);
@ -1909,7 +1881,7 @@ fn lint_expect_fun_call(
&& (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref)) && (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 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)) *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type))
} }
{ {
@ -2170,7 +2142,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp
} }
fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { 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() { if let ty::Adt(_, subst) = obj_ty.kind() {
let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) { let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
@ -2201,7 +2173,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E
let arg = &args[1]; let arg = &args[1];
if let Some(arglists) = method_chain_args(arg, &["chars"]) { if let Some(arglists) = method_chain_args(arg, &["chars"]) {
let target = &arglists[0][0]; 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 { let ref_str = if *self_ty.kind() == ty::Str {
"" ""
} else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) { } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
@ -2229,7 +2201,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E
} }
fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { 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)) { if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) {
lint_string_extend(cx, expr, args); lint_string_extend(cx, expr, args);
} }
@ -2412,7 +2384,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_
} }
} else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type)) } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type))
|| matches!( || matches!(
&walk_ptrs_ty(cx.typeck_results().expr_ty(caller_expr)).kind(), &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(),
ty::Array(_, _) ty::Array(_, _)
) )
{ {
@ -2615,7 +2587,7 @@ fn derefs_to_slice<'tcx>(
/// lint use of `unwrap()` for `Option`s and `Result`s /// lint use of `unwrap()` for `Option`s and `Result`s
fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) { 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)) { let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
Some((UNWRAP_USED, "an Option", "None")) Some((UNWRAP_USED, "an Option", "None"))
@ -2643,7 +2615,7 @@ fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::E
/// lint use of `expect()` for `Option`s and `Result`s /// lint use of `expect()` for `Option`s and `Result`s
fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) { 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)) { let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
Some((EXPECT_USED, "an Option", "None")) Some((EXPECT_USED, "an Option", "None"))
@ -3162,7 +3134,7 @@ fn lint_chars_cmp(
if segment.ident.name == sym!(Some); if segment.ident.name == sym!(Some);
then { then {
let mut applicability = Applicability::MachineApplicable; 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 { if *self_ty.kind() != ty::Str {
return false; return false;
@ -3374,7 +3346,7 @@ fn lint_into_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_
INTO_ITER_ON_REF, INTO_ITER_ON_REF,
method_span, method_span,
&format!( &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, method_name, kind,
), ),
"call directly", "call directly",

View file

@ -1,78 +1,17 @@
use crate::utils::{is_type_diagnostic_item, match_qpath, snippet, span_lint_and_sugg}; use crate::utils::{eager_or_lazy, usage};
use if_chain::if_chain; use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_sugg};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use super::UNNECESSARY_LAZY_EVALUATIONS; 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 /// lint use of `<fn>_else(simple closure)` for `Option`s and `Result`s that can be
/// replaced with `<fn>(return value of simple closure)` /// replaced with `<fn>(return value of simple closure)`
pub(super) fn lint<'tcx>( pub(super) fn lint<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
expr: &'tcx hir::Expr<'_>, expr: &'tcx hir::Expr<'_>,
args: &'tcx [hir::Expr<'_>], args: &'tcx [hir::Expr<'_>],
allow_variant_calls: bool,
simplify_using: &str, simplify_using: &str,
) { ) {
let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type)); let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type));
@ -81,10 +20,13 @@ pub(super) fn lint<'tcx>(
if is_option || is_result { if is_option || is_result {
if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind {
let body = cx.tcx.hir().body(eid); let body = cx.tcx.hir().body(eid);
let ex = &body.value; let body_expr = &body.value;
let params = &body.params;
if can_simplify(ex, params, allow_variant_calls) { if usage::BindingUsageFinder::are_params_used(cx, body) {
return;
}
if eager_or_lazy::is_eagerness_candidate(cx, body_expr) {
let msg = if is_option { let msg = if is_option {
"unnecessary closure used to substitute value for `Option::None`" "unnecessary closure used to substitute value for `Option::None`"
} else { } else {
@ -101,7 +43,7 @@ pub(super) fn lint<'tcx>(
"{0}.{1}({2})", "{0}.{1}({2})",
snippet(cx, args[0].span, ".."), snippet(cx, args[0].span, ".."),
simplify_using, simplify_using,
snippet(cx, ex.span, ".."), snippet(cx, body_expr.span, ".."),
), ),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );

View file

@ -17,7 +17,7 @@ use crate::utils::sugg::Sugg;
use crate::utils::{ use crate::utils::{
get_item_name, get_parent_expr, higher, implements_trait, in_constant, is_integer_const, iter_input_pats, 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, 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! { declare_clippy_lint! {
@ -99,11 +99,11 @@ declare_clippy_lint! {
/// if y != x {} // where both are floats /// if y != x {} // where both are floats
/// ///
/// // Good /// // 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. /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
/// // let error = std::f64::EPSILON; /// // let error_margin = std::f64::EPSILON;
/// if (y - 1.23f64).abs() < error { } /// if (y - 1.23f64).abs() < error_margin { }
/// if (y - x).abs() > error { } /// if (y - x).abs() > error_margin { }
/// ``` /// ```
pub FLOAT_CMP, pub FLOAT_CMP,
correctness, correctness,
@ -242,10 +242,10 @@ declare_clippy_lint! {
/// if x == ONE { } // where both are floats /// if x == ONE { } // where both are floats
/// ///
/// // Good /// // 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. /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
/// // let error = std::f64::EPSILON; /// // let error_margin = std::f64::EPSILON;
/// if (x - ONE).abs() < error { } /// if (x - ONE).abs() < error_margin { }
/// ``` /// ```
pub FLOAT_CMP_CONST, pub FLOAT_CMP_CONST,
restriction, restriction,
@ -411,16 +411,16 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
if !is_comparing_arrays { if !is_comparing_arrays {
diag.span_suggestion( diag.span_suggestion(
expr.span, expr.span,
"consider comparing them within some error", "consider comparing them within some margin of error",
format!( format!(
"({}).abs() {} error", "({}).abs() {} error_margin",
lhs - rhs, lhs - rhs,
if op == BinOpKind::Eq { '<' } else { '>' } if op == BinOpKind::Eq { '<' } else { '>' }
), ),
Applicability::HasPlaceholders, // snippet 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) { } 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"); span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0");
@ -561,7 +561,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
} }
fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { 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 { if let ty::Array(arr_ty, _) = value {
return matches!(arr_ty.kind(), ty::Float(_)); return matches!(arr_ty.kind(), ty::Float(_));
@ -571,7 +571,7 @@ fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
} }
fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { 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) { fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {

View file

@ -377,8 +377,8 @@ impl EarlyLintPass for MiscEarlyLints {
if let PatKind::Ident(_, ident, None) = arg.pat.kind { if let PatKind::Ident(_, ident, None) = arg.pat.kind {
let arg_name = ident.to_string(); let arg_name = ident.to_string();
if arg_name.starts_with('_') { if let Some(arg_name) = arg_name.strip_prefix('_') {
if let Some(correspondence) = registered_names.get(&arg_name[1..]) { if let Some(correspondence) = registered_names.get(arg_name) {
span_lint( span_lint(
cx, cx,
DUPLICATE_UNDERSCORE_ARGUMENT, DUPLICATE_UNDERSCORE_ARGUMENT,
@ -386,7 +386,7 @@ impl EarlyLintPass for MiscEarlyLints {
&format!( &format!(
"`{}` already exists, having another argument having almost the same \ "`{}` already exists, having another argument having almost the same \
name makes code comprehension and documentation more difficult", name makes code comprehension and documentation more difficult",
arg_name[1..].to_owned() arg_name
), ),
); );
} }

View file

@ -1,4 +1,4 @@
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_hir as hir;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut}; use rustc_middle::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut};
@ -12,8 +12,10 @@ declare_clippy_lint! {
/// `BtreeSet` rely on either the hash or the order of keys be unchanging, /// `BtreeSet` rely on either the hash or the order of keys be unchanging,
/// so having types with interior mutability is a bad idea. /// so having types with interior mutability is a bad idea.
/// ///
/// **Known problems:** We don't currently account for `Rc` or `Arc`, so /// **Known problems:** It's correct to use a struct, that contains interior mutability
/// this may yield false positives. /// 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:** /// **Example:**
/// ```rust /// ```rust
@ -96,7 +98,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir::
// We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased // 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). // generics (because the compiler cannot ensure immutability for unknown types).
fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { 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 let Adt(def, substs) = ty.kind() {
if [&paths::HASHMAP, &paths::BTREEMAP, &paths::HASHSET, &paths::BTREESET] if [&paths::HASHMAP, &paths::BTREEMAP, &paths::HASHSET, &paths::BTREESET]
.iter() .iter()

View file

@ -6,14 +6,16 @@ use std::ptr;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp}; 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_lint::{LateContext, LateLintPass, Lint};
use rustc_middle::ty::adjustment::Adjust; 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_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{InnerSpan, Span, DUMMY_SP}; use rustc_span::{InnerSpan, Span, DUMMY_SP};
use rustc_typeck::hir_ty_to_ty; 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! { declare_clippy_lint! {
/// **What it does:** Checks for declaration of `const` items which is interior /// **What it does:** Checks for declaration of `const` items which is interior
@ -83,11 +85,10 @@ declare_clippy_lint! {
"referencing `const` with interior mutability" "referencing `const` with interior mutability"
} }
#[allow(dead_code)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
enum Source { enum Source {
Item { item: Span }, Item { item: Span },
Assoc { item: Span, ty: Span }, Assoc { item: Span },
Expr { expr: Span }, Expr { expr: Span },
} }
@ -110,10 +111,15 @@ impl Source {
} }
fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) { 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) { // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
// An `UnsafeCell` is `!Copy`, and an `UnsafeCell` is also the only type which // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
// is `!Freeze`, thus if our type is `Copy` we can be sure it must be `Freeze` // 'unfrozen'. However, this code causes a false negative in which
// as well. // 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; return;
} }
@ -127,11 +133,7 @@ fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) {
let const_kw_span = span.from_inner(InnerSpan::new(0, 5)); 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)"); diag.span_label(const_kw_span, "make this a static item (maybe with lazy_static)");
}, },
Source::Assoc { ty: ty_span, .. } => { Source::Assoc { .. } => (),
if ty.flags().intersects(TypeFlags::HAS_FREE_LOCAL_NAMES) {
diag.span_label(ty_span, &format!("consider requiring `{}` to be `Copy`", ty));
}
},
Source::Expr { .. } => { Source::Expr { .. } => {
diag.help("assign this const to a local or static variable, and use the variable here"); diag.help("assign this const to a local or static variable, and use the variable here");
}, },
@ -152,14 +154,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) {
if let TraitItemKind::Const(hir_ty, ..) = &trait_item.kind { if let TraitItemKind::Const(hir_ty, ..) = &trait_item.kind {
let ty = hir_ty_to_ty(cx.tcx, hir_ty); let ty = hir_ty_to_ty(cx.tcx, hir_ty);
verify_ty_bound( // Normalize assoc types because ones originated from generic params
cx, // bounded other traits could have their bound.
ty, let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
Source::Assoc { verify_ty_bound(cx, normalized, Source::Assoc { item: trait_item.span });
ty: hir_ty.span,
item: trait_item.span,
},
);
} }
} }
@ -167,17 +165,50 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
if let ImplItemKind::Const(hir_ty, ..) = &impl_item.kind { 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_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id);
let item = cx.tcx.hir().expect_item(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 { match &item.kind {
let ty = hir_ty_to_ty(cx.tcx, hir_ty); ItemKind::Impl {
verify_ty_bound( of_trait: Some(of_trait_ref),
cx, ..
ty, } => {
Source::Assoc { if_chain! {
ty: hir_ty.span, // Lint a trait impl item only when the definition is a generic type,
item: impl_item.span, // 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 });
},
_ => (),
} }
} }
} }

View file

@ -1,4 +1,4 @@
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_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
@ -30,7 +30,7 @@ declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]);
impl<'tcx> LateLintPass<'tcx> for OpenOptions { impl<'tcx> LateLintPass<'tcx> for OpenOptions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if let ExprKind::MethodCall(ref path, _, ref arguments, _) = e.kind { 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) { if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) {
let mut options = Vec::new(); let mut options = Vec::new();
get_open_options(cx, &arguments[0], &mut options); get_open_options(cx, &arguments[0], &mut options);
@ -58,7 +58,7 @@ enum OpenOption {
fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) { fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
if let ExprKind::MethodCall(ref path, _, ref arguments, _) = argument.kind { 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 // 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 { if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 {

View file

@ -1,6 +1,7 @@
use crate::utils; use crate::utils;
use crate::utils::eager_or_lazy;
use crate::utils::sugg::Sugg; 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 if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -13,22 +14,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! { declare_clippy_lint! {
/// **What it does:** /// **What it does:**
/// Lints usage of `if let Some(v) = ... { y } else { x }` which is more /// 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 /// idiomatically done with `Option::map_or` (if the else bit is a pure
/// expression) or `Option::map_or_else` (if the else bit is a longer /// expression) or `Option::map_or_else` (if the else bit is an impure
/// block). /// expresion).
/// ///
/// **Why is this bad?** /// **Why is this bad?**
/// Using the dedicated functions of the Option type is clearer and /// Using the dedicated functions of the Option type is clearer and
/// more concise than an if let expression. /// more concise than an if let expression.
/// ///
/// **Known problems:** /// **Known problems:**
/// This lint uses whether the block is just an expression or if it has /// This lint uses a deliberately conservative metric for checking
/// 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
/// if the inside of either body contains breaks or continues which will /// 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 /// cause it to not suggest a fix if either block contains a loop with
/// continues or breaks contained within the loop. /// continues or breaks contained within the loop.
@ -73,7 +68,7 @@ declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]);
fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind { if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind {
path.ident.name.to_ident_string() == "ok" 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 { } else {
false false
} }
@ -92,6 +87,7 @@ struct OptionIfLetElseOccurence {
struct ReturnBreakContinueMacroVisitor { struct ReturnBreakContinueMacroVisitor {
seen_return_break_continue: bool, seen_return_break_continue: bool,
} }
impl ReturnBreakContinueMacroVisitor { impl ReturnBreakContinueMacroVisitor {
fn new() -> ReturnBreakContinueMacroVisitor { fn new() -> ReturnBreakContinueMacroVisitor {
ReturnBreakContinueMacroVisitor { ReturnBreakContinueMacroVisitor {
@ -99,6 +95,7 @@ impl ReturnBreakContinueMacroVisitor {
} }
} }
} }
impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor { impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor {
type Map = Map<'tcx>; type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@ -157,7 +154,7 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> {
} }
/// If this is the else body of an if/else expression, then we need to wrap /// 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 { fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
utils::get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| { utils::get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| {
if let Some(Expr { if let Some(Expr {
@ -199,7 +196,10 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo
/// If this expression is the option if let/else construct we're detecting, then /// If this expression is the option if let/else construct we're detecting, then
/// this function returns an `OptionIfLetElseOccurence` struct with details if /// this function returns an `OptionIfLetElseOccurence` struct with details if
/// this construct is found, or None if this construct is not found. /// 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_chain! {
if !utils::in_macro(expr.span); // Don't lint macros, because it behaves weirdly 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; if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind;
@ -214,10 +214,7 @@ fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Op
let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" }; let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
let some_body = extract_body_from_arm(&arms[0])?; let some_body = extract_body_from_arm(&arms[0])?;
let none_body = extract_body_from_arm(&arms[1])?; let none_body = extract_body_from_arm(&arms[1])?;
let method_sugg = match &none_body.kind { let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { "map_or" } else { "map_or_else" };
ExprKind::Block(..) => "map_or_else",
_ => "map_or",
};
let capture_name = id.name.to_ident_string(); let capture_name = id.name.to_ident_string();
let wrap_braces = should_wrap_in_braces(cx, expr); let wrap_braces = should_wrap_in_braces(cx, expr);
let (as_ref, as_mut) = match &cond_expr.kind { let (as_ref, as_mut) = match &cond_expr.kind {
@ -243,8 +240,8 @@ fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Op
} }
} }
impl<'a> LateLintPass<'a> for OptionIfLetElse { impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse {
fn check_expr(&mut self, cx: &LateContext<'a>, expr: &Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
if let Some(detection) = detect_option_if_let_else(cx, expr) { if let Some(detection) = detect_option_if_let_else(cx, expr) {
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,

View file

@ -0,0 +1,90 @@
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");
},
);
}
}

View file

@ -1,4 +1,4 @@
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 if_chain::if_chain;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite {
if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
if path.ident.name == sym!(push); if path.ident.name == sym!(push);
if args.len() == 2; 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 Some(get_index_arg) = args.get(1);
if let ExprKind::Lit(ref lit) = get_index_arg.kind; if let ExprKind::Lit(ref lit) = get_index_arg.kind;
if let LitKind::Str(ref path_lit, _) = lit.node; if let LitKind::Str(ref path_lit, _) = lit.node;

View file

@ -239,10 +239,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
); );
let mut app = Applicability::MaybeIncorrect; 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()` // Machine applicable when `call_snip` looks like `foobar()`
if call_snip.ends_with("()") { if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) {
call_snip = call_snip[..call_snip.len()-2].trim();
if call_snip.as_bytes().iter().all(|b| b.is_ascii_alphabetic() || *b == b'_') { if call_snip.as_bytes().iter().all(|b| b.is_ascii_alphabetic() || *b == b'_') {
app = Applicability::MachineApplicable; app = Applicability::MachineApplicable;
} }

View file

@ -1,5 +1,5 @@
use crate::consts::{constant_context, Constant}; 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 if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&count); if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&count);
if !in_macro(receiver.span); if !in_macro(receiver.span);
then { 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() { if ty.is_str() {
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,

View file

@ -25,7 +25,6 @@ declare_clippy_lint! {
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// # let x = 1; /// # let x = 1;
///
/// // Bad /// // Bad
/// let x = &x; /// let x = &x;
/// ///
@ -75,7 +74,9 @@ declare_clippy_lint! {
/// names to bindings or introducing more scopes to contain the bindings. /// names to bindings or introducing more scopes to contain the bindings.
/// ///
/// **Known problems:** This lint, as the other shadowing related lints, /// **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:** /// **Example:**
/// ```rust /// ```rust

View file

@ -8,7 +8,7 @@ use rustc_span::source_map::Spanned;
use if_chain::if_chain; use if_chain::if_chain;
use crate::utils::SpanlessEq; 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! { declare_clippy_lint! {
/// **What it does:** Checks for string appends of the form `x = x + y` (without /// **What it does:** Checks for string appends of the form `x = x + y` (without
@ -134,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd {
} }
fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { 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 { fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {

View file

@ -1,7 +1,6 @@
use crate::utils::sugg::Sugg; use crate::utils::sugg::Sugg;
use crate::utils::{ use crate::utils::{
differing_macro_contexts, eq_expr_value, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_then, 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 if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -194,7 +193,7 @@ fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr<
if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind { if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind {
if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind { if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind {
if eq_expr_value(cx, lhs1, lhs2) { 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(_)) if matches!(ty.kind(), ty::Slice(_))
|| matches!(ty.kind(), ty::Array(_, _)) || matches!(ty.kind(), ty::Array(_, _))

View file

@ -215,11 +215,41 @@ declare_clippy_lint! {
"redundant allocation" "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 { pub struct Types {
vec_box_size_threshold: u64, 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 { impl<'tcx> LateLintPass<'tcx> for Types {
fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) { fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
@ -272,6 +302,19 @@ fn match_type_parameter(cx: &LateContext<'_>, qpath: &QPath<'_>, path: &[&str])
None 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> { fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Span> {
let last = last_path_segment(qpath); let last = last_path_segment(qpath);
if_chain! { if_chain! {
@ -321,14 +364,15 @@ impl Types {
if let Some(def_id) = res.opt_def_id() { if let Some(def_id) = res.opt_def_id() {
if Some(def_id) == cx.tcx.lang_items().owned_box() { if Some(def_id) == cx.tcx.lang_items().owned_box() {
if let Some(span) = match_borrows_parameter(cx, qpath) { if let Some(span) = match_borrows_parameter(cx, qpath) {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
REDUNDANT_ALLOCATION, REDUNDANT_ALLOCATION,
hir_ty.span, hir_ty.span,
"usage of `Box<&T>`", "usage of `Box<&T>`",
"try", "try",
snippet(cx, span, "..").to_string(), snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
Applicability::MachineApplicable, applicability,
); );
return; // don't recurse into the type return; // don't recurse into the type
} }
@ -345,14 +389,15 @@ impl Types {
} }
} else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) { } else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
if let Some(span) = match_type_parameter(cx, qpath, &paths::RC) { if let Some(span) = match_type_parameter(cx, qpath, &paths::RC) {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
REDUNDANT_ALLOCATION, REDUNDANT_ALLOCATION,
hir_ty.span, hir_ty.span,
"usage of `Rc<Rc<T>>`", "usage of `Rc<Rc<T>>`",
"try", "try",
snippet(cx, span, "..").to_string(), snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
Applicability::MachineApplicable, applicability,
); );
return; // don't recurse into the type return; // don't recurse into the type
} }
@ -368,25 +413,109 @@ impl Types {
GenericArg::Type(ty) => ty.span, GenericArg::Type(ty) => ty.span,
_ => return, _ => return,
}; };
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
REDUNDANT_ALLOCATION, REDUNDANT_ALLOCATION,
hir_ty.span, hir_ty.span,
"usage of `Rc<Box<T>>`", "usage of `Rc<Box<T>>`",
"try", "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, Applicability::MachineApplicable,
); );
return; // don't recurse into the type return; // don't recurse into the type
} }
if let Some(span) = match_borrows_parameter(cx, qpath) { if let Some(span) = match_borrows_parameter(cx, qpath) {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
REDUNDANT_ALLOCATION, REDUNDANT_ALLOCATION,
hir_ty.span, hir_ty.span,
"usage of `Rc<&T>`", "usage of `Rc<&T>`",
"try", "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, Applicability::MachineApplicable,
); );
return; // don't recurse into the type return; // don't recurse into the type
@ -546,7 +675,6 @@ impl Types {
// details. // details.
return; return;
} }
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
BORROWED_BOX, BORROWED_BOX,
@ -556,8 +684,12 @@ impl Types {
format!( format!(
"&{}{}", "&{}{}",
ltopt, 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, Applicability::Unspecified,
); );
return; // don't recurse into the type return; // don't recurse into the type

View file

@ -1,4 +1,4 @@
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 if_chain::if_chain;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
@ -81,7 +81,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
// check for `expect` // check for `expect`
if let Some(arglists) = method_chain_args(expr, &["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)) if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
|| is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
{ {
@ -91,7 +91,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
// check for `unwrap` // check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["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)) if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
|| is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
{ {

View file

@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
cx, cx,
USELESS_CONVERSION, USELESS_CONVERSION,
e.span, e.span,
"useless conversion to the same type", &format!("useless conversion to the same type: `{}`", b),
"consider removing `.into()`", "consider removing `.into()`",
sugg, sugg,
Applicability::MachineApplicable, // snippet Applicability::MachineApplicable, // snippet
@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
cx, cx,
USELESS_CONVERSION, USELESS_CONVERSION,
e.span, e.span,
"useless conversion to the same type", &format!("useless conversion to the same type: `{}`", b),
"consider removing `.into_iter()`", "consider removing `.into_iter()`",
sugg, sugg,
Applicability::MachineApplicable, // snippet Applicability::MachineApplicable, // snippet
@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
cx, cx,
USELESS_CONVERSION, USELESS_CONVERSION,
e.span, e.span,
"useless conversion to the same type", &format!("useless conversion to the same type: `{}`", b),
None, None,
"consider removing `.try_into()`", "consider removing `.try_into()`",
); );
@ -147,7 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
cx, cx,
USELESS_CONVERSION, USELESS_CONVERSION,
e.span, e.span,
"useless conversion to the same type", &format!("useless conversion to the same type: `{}`", b),
None, None,
&hint, &hint,
); );
@ -166,7 +166,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
cx, cx,
USELESS_CONVERSION, USELESS_CONVERSION,
e.span, e.span,
"useless conversion to the same type", &format!("useless conversion to the same type: `{}`", b),
&sugg_msg, &sugg_msg,
sugg.to_string(), sugg.to_string(),
Applicability::MachineApplicable, // snippet Applicability::MachineApplicable, // snippet

View file

@ -51,6 +51,8 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
/// ///
/// The `help` message can be optionally attached to a `Span`. /// The `help` message can be optionally attached to a `Span`.
/// ///
/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
///
/// # Example /// # Example
/// ///
/// ```ignore /// ```ignore
@ -87,6 +89,8 @@ pub fn span_lint_and_help<'a, T: LintContext>(
/// The `note` message is presented separately from the main lint message /// The `note` message is presented separately from the main lint message
/// and is attached to a specific span: /// and is attached to a specific span:
/// ///
/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
///
/// # Example /// # Example
/// ///
/// ```ignore /// ```ignore
@ -126,6 +130,7 @@ pub fn span_lint_and_note<'a, T: LintContext>(
/// Like `span_lint` but allows to add notes, help and suggestions using a closure. /// 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 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) pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
where where
F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>), F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
@ -168,6 +173,10 @@ pub fn span_lint_hir_and_then(
/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x > /// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x >
/// 2)"`. /// 2)"`.
/// ///
/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
///
/// # Example
///
/// ```ignore /// ```ignore
/// error: This `.fold` can be more succinctly expressed as `.any` /// error: This `.fold` can be more succinctly expressed as `.any`
/// --> $DIR/methods.rs:390:13 /// --> $DIR/methods.rs:390:13

View file

@ -0,0 +1,128 @@
//! 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)
}

View file

@ -1,6 +1,6 @@
use crate::utils::{ use crate::utils::{
is_expn_of, match_def_path, match_qpath, match_type, method_calls, paths, run_lints, snippet, span_lint, is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, qpath_res, run_lints,
span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty, SpanlessEq, snippet, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq,
}; };
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId}; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId};
@ -11,7 +11,7 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; 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_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
use rustc_middle::hir::map::Map; use rustc_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
@ -206,6 +206,29 @@ declare_clippy_lint! {
"found collapsible `span_lint_and_then` calls" "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]); declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
impl EarlyLintPass for ClippyLintsInternal { impl EarlyLintPass for ClippyLintsInternal {
@ -404,7 +427,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
let fn_name = path.ident; let fn_name = path.ident;
if let Some(sugg) = self.map.get(&*fn_name.as_str()); 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) if match_type(cx, ty, &paths::EARLY_CONTEXT)
|| match_type(cx, ty, &paths::LATE_CONTEXT); || match_type(cx, ty, &paths::LATE_CONTEXT);
then { then {
@ -437,7 +460,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
let args = arg_lists[1]; let args = arg_lists[1];
if args.len() == 1; if args.len() == 1;
let self_arg = &args[0]; 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); if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
then { then {
span_lint_and_sugg( span_lint_and_sugg(
@ -652,3 +675,89 @@ fn suggest_note(
Applicability::MachineApplicable, 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
}

View file

@ -10,6 +10,7 @@ pub mod comparisons;
pub mod conf; pub mod conf;
pub mod constants; pub mod constants;
mod diagnostics; mod diagnostics;
pub mod eager_or_lazy;
pub mod higher; pub mod higher;
mod hir_utils; mod hir_utils;
pub mod inspector; pub mod inspector;
@ -130,6 +131,9 @@ pub fn is_wild<'tcx>(pat: &impl std::ops::Deref<Target = Pat<'tcx>>) -> bool {
} }
/// Checks if type is struct, enum or union type with the given def path. /// 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 { pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
match ty.kind() { match ty.kind() {
ty::Adt(adt, _) => match_def_path(cx, adt.did, path), ty::Adt(adt, _) => match_def_path(cx, adt.did, path),
@ -138,6 +142,8 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
} }
/// Checks if the type is equal to a diagnostic item /// 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 { pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
match ty.kind() { match ty.kind() {
ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did), ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did),
@ -748,14 +754,6 @@ pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
} }
} }
/// 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 /// Returns the base type for references and raw pointers, and count reference
/// depth. /// depth.
pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {

View file

@ -113,8 +113,12 @@ pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"];
pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; 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_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"];
pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"]; 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_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_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 SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"]; pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"];
pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"]; pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];

View file

@ -49,7 +49,7 @@ impl<'a> Sugg<'a> {
/// Convenience function around `hir_opt` for suggestions with a default /// Convenience function around `hir_opt` for suggestions with a default
/// text. /// text.
pub fn hir(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self { 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: /// Same as `hir`, but it adapts the applicability level by following rules:

View file

@ -1,6 +1,8 @@
use crate::utils::match_var; use crate::utils::match_var;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::intravisit;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{Expr, HirId, Path}; use rustc_hir::{Expr, HirId, Path};
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
@ -108,3 +110,67 @@ pub fn is_unused<'tcx>(ident: &'tcx Ident, body: &'tcx Expr<'_>) -> bool {
walk_expr(&mut visitor, body); walk_expr(&mut visitor, body);
!visitor.used !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())
}
}

View file

@ -322,11 +322,15 @@ impl EarlyLintPass for Write {
} }
/// Given a format string that ends in a newline and its span, calculates the span of the /// 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 { fn newline_span(fmtstr: &StrLit) -> Span {
let sp = fmtstr.span; let sp = fmtstr.span;
let contents = &fmtstr.symbol.as_str(); let contents = &fmtstr.symbol.as_str();
if *contents == r"\n" {
return sp;
}
let newline_sp_hi = sp.hi() let newline_sp_hi = sp.hi()
- match fmtstr.style { - match fmtstr.style {
StrStyle::Cooked => BytePos(1), StrStyle::Cooked => BytePos(1),

View file

@ -488,7 +488,7 @@ For `LateLintPass` lints:
While most of Clippy's lint utils are documented, most of rustc's internals lack 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 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, 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 [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/ [if_chain]: https://docs.rs/if_chain/*/if_chain/
@ -500,4 +500,4 @@ don't hesitate to ask on [Discord] or in the issue/PR.
[nightly_docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ [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 [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 [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

View file

@ -60,7 +60,7 @@ impl LateLintPass<'_> for MyStructLint {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if_chain! { if_chain! {
// Check our expr is calling a method // 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` // Check the name of this method is `some_method`
if path.ident.name == sym!(some_method); if path.ident.name == sym!(some_method);
then { then {

View file

@ -930,7 +930,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
Lint { Lint {
name: "invalid_atomic_ordering", name: "invalid_atomic_ordering",
group: "correctness", 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, deprecation: None,
module: "atomic_ordering", module: "atomic_ordering",
}, },
@ -1144,6 +1144,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
deprecation: None, deprecation: None,
module: "methods", 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 { Lint {
name: "manual_swap", name: "manual_swap",
group: "complexity", group: "complexity",
@ -1172,6 +1179,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
deprecation: None, deprecation: None,
module: "entry", 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 { Lint {
name: "map_flatten", name: "map_flatten",
group: "pedantic", group: "pedantic",
@ -1718,6 +1732,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
deprecation: None, deprecation: None,
module: "panic_unimplemented", 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 { Lint {
name: "panic_params", name: "panic_params",
group: "style", group: "style",
@ -1844,6 +1865,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
deprecation: None, deprecation: None,
module: "ranges", module: "ranges",
}, },
Lint {
name: "rc_buffer",
group: "perf",
desc: "shared ownership of a buffer type",
deprecation: None,
module: "types",
},
Lint { Lint {
name: "redundant_allocation", name: "redundant_allocation",
group: "perf", group: "perf",
@ -2630,7 +2658,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
}, },
Lint { Lint {
name: "verbose_bit_mask", name: "verbose_bit_mask",
group: "style", group: "pedantic",
desc: "expressions where a bit mask is less readable than the corresponding method call", desc: "expressions where a bit mask is less readable than the corresponding method call",
deprecation: None, deprecation: None,
module: "bit_mask", module: "bit_mask",

View file

@ -0,0 +1,45 @@
#![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);
}

View file

@ -0,0 +1,131 @@
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

View file

@ -0,0 +1,47 @@
#![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);
}

View file

@ -0,0 +1,131 @@
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

View file

@ -0,0 +1,45 @@
#![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));
}

View file

@ -0,0 +1,131 @@
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

View file

@ -19,16 +19,30 @@ const NO_ANN: &dyn Display = &70;
static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
const ONCE_INIT: Once = Once::new(); const ONCE_INIT: Once = Once::new();
trait Trait<T>: Copy { trait Trait<T> {
type NonCopyType; type AssocType;
const ATOMIC: AtomicUsize; const ATOMIC: AtomicUsize;
const INPUT: T;
const ASSOC: Self::AssocType;
fn function() {
let _ = &Self::INPUT;
let _ = &Self::ASSOC;
}
} }
impl Trait<u32> for u64 { impl Trait<u32> for u64 {
type NonCopyType = u16; type AssocType = AtomicUsize;
const ATOMIC: AtomicUsize = AtomicUsize::new(9); 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, // This is just a pointer that can be safely dereferended,

View file

@ -1,14 +1,22 @@
error: a `const` item with interior mutability should not be borrowed 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 | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability LL | let _ = &Self::ASSOC; //~ ERROR interior mutability
| ^^^^^^ | ^^^^^^^^^^^
| |
= note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` = 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 = 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 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:80:5
|
LL | ATOMIC.store(1, 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:81:16
| |
LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
| ^^^^^^ | ^^^^^^
@ -16,7 +24,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi
= help: assign this const to a local or static variable, and use the variable here = 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 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 LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
| ^^^^^^^^^ | ^^^^^^^^^
@ -24,7 +32,7 @@ LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
= help: assign this const to a local or static variable, and use the variable here = 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 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 LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
| ^^^^^^^^^ | ^^^^^^^^^
@ -32,7 +40,7 @@ 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 = 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 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 LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
| ^^^^^^^^^ | ^^^^^^^^^
@ -40,7 +48,7 @@ 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 = 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 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 LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
| ^^^^^^^^^ | ^^^^^^^^^
@ -48,7 +56,7 @@ 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 = 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 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 LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
@ -56,7 +64,7 @@ LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
= help: assign this const to a local or static variable, and use the variable here = 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 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 LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
@ -64,7 +72,7 @@ LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
= help: assign this const to a local or static variable, and use the variable here = 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 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 LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
@ -72,7 +80,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
= help: assign this const to a local or static variable, and use the variable here = 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 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 LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
@ -80,7 +88,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
= help: assign this const to a local or static variable, and use the variable here = 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 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 LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
@ -88,7 +96,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu
= help: assign this const to a local or static variable, and use the variable here = 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 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 LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
@ -96,7 +104,7 @@ LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
= help: assign this const to a local or static variable, and use the variable here = 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 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 LL | CELL.set(2); //~ ERROR interior mutability
| ^^^^ | ^^^^
@ -104,7 +112,7 @@ LL | CELL.set(2); //~ ERROR interior mutability
= help: assign this const to a local or static variable, and use the variable here = 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 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 LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
| ^^^^ | ^^^^
@ -112,7 +120,7 @@ LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
= help: assign this const to a local or static variable, and use the variable here = 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 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 LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -120,12 +128,12 @@ 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 = 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 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 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 = 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

View file

@ -1,22 +0,0 @@
#![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);
}

View file

@ -1,17 +0,0 @@
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

View file

@ -34,60 +34,141 @@ static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
#[allow(clippy::declare_interior_mutable_const)] #[allow(clippy::declare_interior_mutable_const)]
const ONCE_INIT: Once = Once::new(); const ONCE_INIT: Once = Once::new();
trait Trait<T>: Copy { // a constant whose type is a concrete type should be linted at the definition site.
type NonCopyType; trait ConcreteTypes {
const ATOMIC: AtomicUsize; //~ ERROR interior mutable const ATOMIC: AtomicUsize; //~ ERROR interior mutable
const INTEGER: u64; const INTEGER: u64;
const STRING: String; const STRING: String;
const SELF: Self; // (no error) declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable
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`
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
} }
trait Trait2 { impl ConcreteTypes for u64 {
type CopyType: Copy;
const SELF_2: Self;
//~^ ERROR interior mutable
//~| HELP consider requiring `Self` to be `Copy`
const ASSOC_2: Self::CopyType; // (no error)
}
// 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;
const ATOMIC: AtomicUsize = AtomicUsize::new(9); const ATOMIC: AtomicUsize = AtomicUsize::new(9);
const INTEGER: u64 = 10; const INTEGER: u64 = 10;
const STRING: String = String::new(); const STRING: String = String::new();
const SELF: Self = 11;
const INPUT: u32 = 12;
const ASSOC: Self::NonCopyType = 13;
} }
struct Local<T, U>(T, U); // a helper trait used below
trait ConstDefault {
const DEFAULT: Self;
}
impl<T: Trait2 + Trait<u32>, U: Trait2> Local<T, U> { // a constant whose type is a generic type should be linted at the implementation site.
const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable trait GenericTypes<T, U> {
const TO_REMAIN_GENERIC: T;
const TO_BE_CONCRETE: U;
const HAVING_DEFAULT: T = Self::TO_REMAIN_GENERIC;
declare_const!(IN_MACRO: T = Self::TO_REMAIN_GENERIC);
}
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
}
// 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>;
}
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;
}
// 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 COW: Cow<'static, str> = Cow::Borrowed("tuvwxy");
const T_SELF: T = T::SELF_2;
const U_SELF: U = U::SELF_2; const GENERIC_TYPE: T = T::DEFAULT;
//~^ ERROR interior mutable
//~| HELP consider requiring `U` to be `Copy` const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
const T_ASSOC: T::NonCopyType = T::ASSOC; const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable
//~^ ERROR interior mutable
//~| HELP consider requiring `<T as Trait<u32>>::NonCopyType` to be `Copy`
const U_ASSOC: U::CopyType = U::ASSOC_2;
} }
fn main() {} fn main() {}

View file

@ -36,75 +36,75 @@ LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) = 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 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 LL | const ATOMIC: AtomicUsize; //~ ERROR interior mutable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a `const` item should never be interior mutable
--> $DIR/declare_interior_mutable_const.rs:44:5
|
LL | const INPUT: T;
| ^^^^^^^^^^^^^-^
| |
| consider requiring `T` to be `Copy`
error: a `const` item should never be interior mutable
--> $DIR/declare_interior_mutable_const.rs:47:5
|
LL | const ASSOC: Self::NonCopyType;
| ^^^^^^^^^^^^^-----------------^
| |
| consider requiring `<Self as Trait<T>>::NonCopyType` to be `Copy`
error: a `const` item should never be interior mutable
--> $DIR/declare_interior_mutable_const.rs:51:5
|
LL | const AN_INPUT: T = Self::INPUT;
| ^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^
| |
| consider requiring `T` to be `Copy`
error: a `const` item should never be 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:16:9
| |
LL | const $name: $ty = $e; LL | const $name: $ty = $e;
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
... ...
LL | declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable
| ----------------------------------------------- in this macro invocation | ----------------------------------------------------------- in this macro invocation
| |
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) = 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 error: a `const` item should never be interior mutable
--> $DIR/declare_interior_mutable_const.rs:60:5 --> $DIR/declare_interior_mutable_const.rs:67:5
| |
LL | const SELF_2: Self; LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable
| ^^^^^^^^^^^^^^----^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| consider requiring `Self` to be `Copy`
error: a `const` item should never be 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:92:5
| |
LL | const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a `const` item should never be 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:93:5
| |
LL | const U_SELF: U = U::SELF_2; LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable
| ^^^^^^^^^^^^^^-^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| consider requiring `U` to be `Copy`
error: a `const` item should never be 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:112:5
| |
LL | const T_ASSOC: T::NonCopyType = T::ASSOC; LL | const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable
| ^^^^^^^^^^^^^^^--------------^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| consider requiring `<T as Trait<u32>>::NonCopyType` to be `Copy`
error: aborting due to 13 previous errors 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:141:5
|
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:149:5
|
LL | const INDIRECT: Cell<*const T>; //~ ERROR interior mutable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a `const` item should never be interior mutable
--> $DIR/declare_interior_mutable_const.rs:165:5
|
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:171:5
|
LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 15 previous errors

View file

@ -1,5 +1,6 @@
#![warn(clippy::drop_ref)] #![warn(clippy::drop_ref)]
#![allow(clippy::toplevel_ref_arg)] #![allow(clippy::toplevel_ref_arg)]
#![allow(clippy::map_err_ignore)]
use std::mem::drop; use std::mem::drop;

View file

@ -1,108 +1,108 @@
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. 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); LL | drop(&SomeStruct);
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
| |
= note: `-D clippy::drop-ref` implied by `-D warnings` = note: `-D clippy::drop-ref` implied by `-D warnings`
note: argument has type `&SomeStruct` note: argument has type `&SomeStruct`
--> $DIR/drop_ref.rs:9:10 --> $DIR/drop_ref.rs:10:10
| |
LL | drop(&SomeStruct); LL | drop(&SomeStruct);
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. 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); LL | drop(&owned1);
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
| |
note: argument has type `&SomeStruct` note: argument has type `&SomeStruct`
--> $DIR/drop_ref.rs:12:10 --> $DIR/drop_ref.rs:13:10
| |
LL | drop(&owned1); LL | drop(&owned1);
| ^^^^^^^ | ^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. 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); LL | drop(&&owned1);
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
| |
note: argument has type `&&SomeStruct` note: argument has type `&&SomeStruct`
--> $DIR/drop_ref.rs:13:10 --> $DIR/drop_ref.rs:14:10
| |
LL | drop(&&owned1); LL | drop(&&owned1);
| ^^^^^^^^ | ^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. 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); LL | drop(&mut owned1);
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
| |
note: argument has type `&mut SomeStruct` note: argument has type `&mut SomeStruct`
--> $DIR/drop_ref.rs:14:10 --> $DIR/drop_ref.rs:15:10
| |
LL | drop(&mut owned1); LL | drop(&mut owned1);
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. 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); LL | drop(reference1);
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
| |
note: argument has type `&SomeStruct` note: argument has type `&SomeStruct`
--> $DIR/drop_ref.rs:18:10 --> $DIR/drop_ref.rs:19:10
| |
LL | drop(reference1); LL | drop(reference1);
| ^^^^^^^^^^ | ^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. 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); LL | drop(reference2);
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
| |
note: argument has type `&mut SomeStruct` note: argument has type `&mut SomeStruct`
--> $DIR/drop_ref.rs:21:10 --> $DIR/drop_ref.rs:22:10
| |
LL | drop(reference2); LL | drop(reference2);
| ^^^^^^^^^^ | ^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. 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); LL | drop(reference3);
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
| |
note: argument has type `&SomeStruct` note: argument has type `&SomeStruct`
--> $DIR/drop_ref.rs:24:10 --> $DIR/drop_ref.rs:25:10
| |
LL | drop(reference3); LL | drop(reference3);
| ^^^^^^^^^^ | ^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. 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); LL | drop(&val);
| ^^^^^^^^^^ | ^^^^^^^^^^
| |
note: argument has type `&T` note: argument has type `&T`
--> $DIR/drop_ref.rs:29:10 --> $DIR/drop_ref.rs:30:10
| |
LL | drop(&val); LL | drop(&val);
| ^^^^ | ^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. 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); LL | std::mem::drop(&SomeStruct);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
note: argument has type `&SomeStruct` note: argument has type `&SomeStruct`
--> $DIR/drop_ref.rs:37:20 --> $DIR/drop_ref.rs:38:20
| |
LL | std::mem::drop(&SomeStruct); LL | std::mem::drop(&SomeStruct);
| ^^^^^^^^^^^ | ^^^^^^^^^^^

View file

@ -2,34 +2,34 @@ error: strict comparison of `f32` or `f64`
--> $DIR/float_cmp.rs:65:5 --> $DIR/float_cmp.rs:65:5
| |
LL | ONE as f64 != 2.0; 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: `-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` error: strict comparison of `f32` or `f64`
--> $DIR/float_cmp.rs:70:5 --> $DIR/float_cmp.rs:70:5
| |
LL | x == 1.0; 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` error: strict comparison of `f32` or `f64`
--> $DIR/float_cmp.rs:73:5 --> $DIR/float_cmp.rs:73:5
| |
LL | twice(x) != twice(ONE as f64); 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` error: strict comparison of `f32` or `f64`
--> $DIR/float_cmp.rs:93:5 --> $DIR/float_cmp.rs:93:5
| |
LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; 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 error: strict comparison of `f32` or `f64` arrays
--> $DIR/float_cmp.rs:98:5 --> $DIR/float_cmp.rs:98:5
@ -37,15 +37,15 @@ error: strict comparison of `f32` or `f64` arrays
LL | a1 == a2; 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` error: strict comparison of `f32` or `f64`
--> $DIR/float_cmp.rs:99:5 --> $DIR/float_cmp.rs:99:5
| |
LL | a1[0] == a2[0]; 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 error: aborting due to 6 previous errors

View file

@ -2,58 +2,58 @@ error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:20:5 --> $DIR/float_cmp_const.rs:20:5
| |
LL | 1f32 == ONE; 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: `-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 error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:21:5 --> $DIR/float_cmp_const.rs:21:5
| |
LL | TWO == ONE; 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 error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:22:5 --> $DIR/float_cmp_const.rs:22:5
| |
LL | TWO != ONE; 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 error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:23:5 --> $DIR/float_cmp_const.rs:23:5
| |
LL | ONE + ONE == TWO; 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 error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:25:5 --> $DIR/float_cmp_const.rs:25:5
| |
LL | x as f32 == ONE; 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 error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:28:5 --> $DIR/float_cmp_const.rs:28:5
| |
LL | v == ONE; 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 error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:29:5 --> $DIR/float_cmp_const.rs:29:5
| |
LL | v != ONE; 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 error: strict comparison of `f32` or `f64` constant arrays
--> $DIR/float_cmp_const.rs:61:5 --> $DIR/float_cmp_const.rs:61:5
@ -61,7 +61,7 @@ error: strict comparison of `f32` or `f64` constant arrays
LL | NON_ZERO_ARRAY == NON_ZERO_ARRAY2; 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 error: aborting due to 8 previous errors

View file

@ -15,7 +15,8 @@ fn main() {
x[3]; // Ok, should not produce stderr. x[3]; // Ok, should not produce stderr.
let y = &x; 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]; let v = vec![0; 5];
v[0]; v[0];

View file

@ -8,15 +8,7 @@ LL | x[index];
= help: Consider using `.get(n)` or `.get_mut(n)` instead = help: Consider using `.get(n)` or `.get_mut(n)` instead
error: indexing may panic. error: indexing may panic.
--> $DIR/indexing_slicing_index.rs:18:5 --> $DIR/indexing_slicing_index.rs:22: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
| |
LL | v[0]; LL | v[0];
| ^^^^ | ^^^^
@ -24,7 +16,7 @@ LL | v[0];
= help: Consider using `.get(n)` or `.get_mut(n)` instead = help: Consider using `.get(n)` or `.get_mut(n)` instead
error: indexing may panic. error: indexing may panic.
--> $DIR/indexing_slicing_index.rs:22:5 --> $DIR/indexing_slicing_index.rs:23:5
| |
LL | v[10]; LL | v[10];
| ^^^^^ | ^^^^^
@ -32,7 +24,7 @@ LL | v[10];
= help: Consider using `.get(n)` or `.get_mut(n)` instead = help: Consider using `.get(n)` or `.get_mut(n)` instead
error: indexing may panic. error: indexing may panic.
--> $DIR/indexing_slicing_index.rs:23:5 --> $DIR/indexing_slicing_index.rs:24:5
| |
LL | v[1 << 3]; LL | v[1 << 3];
| ^^^^^^^^^ | ^^^^^^^^^
@ -40,7 +32,7 @@ LL | v[1 << 3];
= help: Consider using `.get(n)` or `.get_mut(n)` instead = help: Consider using `.get(n)` or `.get_mut(n)` instead
error: indexing may panic. error: indexing may panic.
--> $DIR/indexing_slicing_index.rs:29:5 --> $DIR/indexing_slicing_index.rs:30:5
| |
LL | v[N]; LL | v[N];
| ^^^^ | ^^^^
@ -48,12 +40,12 @@ LL | v[N];
= help: Consider using `.get(n)` or `.get_mut(n)` instead = help: Consider using `.get(n)` or `.get_mut(n)` instead
error: indexing may panic. error: indexing may panic.
--> $DIR/indexing_slicing_index.rs:30:5 --> $DIR/indexing_slicing_index.rs:31:5
| |
LL | v[M]; LL | v[M];
| ^^^^ | ^^^^
| |
= help: Consider using `.get(n)` or `.get_mut(n)` instead = help: Consider using `.get(n)` or `.get_mut(n)` instead
error: aborting due to 7 previous errors error: aborting due to 6 previous errors

View file

@ -71,29 +71,17 @@ LL | &x[1..][..5];
| |
= help: Consider using `.get(..n)`or `.get_mut(..n)` instead = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
error: slicing may panic. error: range is out of bounds
--> $DIR/indexing_slicing_slice.rs:24:6 --> $DIR/indexing_slicing_slice.rs:25:12
|
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
| |
LL | &y[0..=4]; LL | &y[0..=4];
| ^^^^^^^^ | ^
|
= help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead
error: slicing may panic. error: range is out of bounds
--> $DIR/indexing_slicing_slice.rs:26:6 --> $DIR/indexing_slicing_slice.rs:26:11
| |
LL | &y[..=4]; LL | &y[..=4];
| ^^^^^^^ | ^
|
= help: Consider using `.get(..n)`or `.get_mut(..n)` instead
error: slicing may panic. error: slicing may panic.
--> $DIR/indexing_slicing_slice.rs:31:6 --> $DIR/indexing_slicing_slice.rs:31:6
@ -133,5 +121,5 @@ LL | &v[..100];
| |
= help: Consider using `.get(..n)`or `.get_mut(..n)` instead = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
error: aborting due to 17 previous errors error: aborting due to 16 previous errors

View file

@ -1,4 +1,4 @@
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 --> $DIR/into_iter_on_ref.rs:14:30
| |
LL | let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter() LL | let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter()
@ -6,157 +6,157 @@ LL | let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter()
| |
= note: `-D clippy::into-iter-on-ref` implied by `-D warnings` = 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 --> $DIR/into_iter_on_ref.rs:15:46
| |
LL | let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter() LL | let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:16:41
| |
LL | let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter() LL | let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:17:44
| |
LL | let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter() LL | let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:19:32
| |
LL | let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter() LL | let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:20:36
| |
LL | let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter() LL | let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:21:40
| |
LL | let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter_mut() LL | let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:23:24
| |
LL | let _ = (&Some(4)).into_iter(); //~ WARN equivalent to .iter() LL | let _ = (&Some(4)).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:24:28
| |
LL | let _ = (&mut Some(5)).into_iter(); //~ WARN equivalent to .iter_mut() LL | let _ = (&mut Some(5)).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:25:32
| |
LL | let _ = (&Ok::<_, i32>(6)).into_iter(); //~ WARN equivalent to .iter() LL | let _ = (&Ok::<_, i32>(6)).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:26:37
| |
LL | let _ = (&mut Err::<i32, _>(7)).into_iter(); //~ WARN equivalent to .iter_mut() LL | let _ = (&mut Err::<i32, _>(7)).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:27:34
| |
LL | let _ = (&Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter() LL | let _ = (&Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:28:38
| |
LL | let _ = (&mut Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut() LL | let _ = (&mut Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:29:44
| |
LL | let _ = (&BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter() LL | let _ = (&BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:30:48
| |
LL | let _ = (&mut BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut() LL | let _ = (&mut BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:31:39
| |
LL | let _ = (&VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter() LL | let _ = (&VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:32:43
| |
LL | let _ = (&mut VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut() LL | let _ = (&mut VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:33:41
| |
LL | let _ = (&LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter() LL | let _ = (&LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:34:45
| |
LL | let _ = (&mut LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut() LL | let _ = (&mut LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:35:43
| |
LL | let _ = (&HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter() LL | let _ = (&HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:36:47
| |
LL | let _ = (&mut HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut() LL | let _ = (&mut HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:38:39
| |
LL | let _ = (&BTreeSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter() LL | let _ = (&BTreeSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:39:41
| |
LL | let _ = (&BinaryHeap::<i32>::new()).into_iter(); //~ WARN equivalent to .iter() LL | let _ = (&BinaryHeap::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:40:38
| |
LL | let _ = (&HashSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter() LL | let _ = (&HashSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:41:43
| |
LL | let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter() LL | let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:42:47
| |
LL | let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter() LL | let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter()
| ^^^^^^^^^ help: call directly: `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 --> $DIR/into_iter_on_ref.rs:44:26
| |
LL | let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter() LL | let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter()

View file

@ -33,6 +33,7 @@ fn issue985_alt() -> i32 {
x x
} }
#[allow(clippy::manual_strip)]
fn issue975() -> String { fn issue975() -> String {
let mut udn = "dummy".to_string(); let mut udn = "dummy".to_string();
if udn.starts_with("uuid:") { if udn.starts_with("uuid:") {

View file

@ -1,5 +1,5 @@
error: `if _ { .. } else { .. }` is an expression 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 | / let mut foo = 0;
LL | | if f() { LL | | if f() {
@ -11,7 +11,7 @@ LL | | }
= note: you might not need `mut` at all = note: you might not need `mut` at all
error: `if _ { .. } else { .. }` is an expression 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 | / let mut bar = 0;
LL | | if f() { LL | | if f() {
@ -25,7 +25,7 @@ LL | | }
= note: you might not need `mut` at all = note: you might not need `mut` at all
error: `if _ { .. } else { .. }` is an expression error: `if _ { .. } else { .. }` is an expression
--> $DIR/let_if_seq.rs:76:5 --> $DIR/let_if_seq.rs:77:5
| |
LL | / let quz; LL | / let quz;
LL | | if f() { LL | | if f() {
@ -36,7 +36,7 @@ LL | | }
| |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };` | |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };`
error: `if _ { .. } else { .. }` is an expression 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 | / let mut baz = 0;
LL | | if f() { LL | | if f() {

View file

@ -0,0 +1,66 @@
#![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();
}
}

View file

@ -0,0 +1,132 @@
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

View file

@ -0,0 +1,25 @@
#![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(())
}

View file

@ -0,0 +1,11 @@
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

View file

@ -0,0 +1,50 @@
#![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() {}

View file

@ -0,0 +1,33 @@
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

View file

@ -1,5 +1,6 @@
// run-rustfix // run-rustfix
#![warn(clippy::option_if_let_else)] #![warn(clippy::option_if_let_else)]
#![allow(clippy::redundant_closure)]
fn bad1(string: Option<&str>) -> (bool, &str) { fn bad1(string: Option<&str>) -> (bool, &str) {
string.map_or((false, "hello"), |x| (true, x)) string.map_or((false, "hello"), |x| (true, x))
@ -36,6 +37,14 @@ fn longer_body(arg: Option<u32>) -> u32 {
}) })
} }
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>) { fn test_map_or_else(arg: Option<u32>) {
let _ = arg.map_or_else(|| { let _ = arg.map_or_else(|| {
let mut y = 1; let mut y = 1;
@ -71,4 +80,5 @@ fn main() {
let _ = longer_body(None); let _ = longer_body(None);
test_map_or_else(None); test_map_or_else(None);
let _ = negative_tests(None); let _ = negative_tests(None);
let _ = impure_else(None);
} }

View file

@ -1,5 +1,6 @@
// run-rustfix // run-rustfix
#![warn(clippy::option_if_let_else)] #![warn(clippy::option_if_let_else)]
#![allow(clippy::redundant_closure)]
fn bad1(string: Option<&str>) -> (bool, &str) { fn bad1(string: Option<&str>) -> (bool, &str) {
if let Some(x) = string { if let Some(x) = string {
@ -52,6 +53,19 @@ fn longer_body(arg: Option<u32>) -> u32 {
} }
} }
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>) { fn test_map_or_else(arg: Option<u32>) {
let _ = if let Some(x) = arg { let _ = if let Some(x) = arg {
x * x * x * x x * x * x * x
@ -89,4 +103,5 @@ fn main() {
let _ = longer_body(None); let _ = longer_body(None);
test_map_or_else(None); test_map_or_else(None);
let _ = negative_tests(None); let _ = negative_tests(None);
let _ = impure_else(None);
} }

View file

@ -1,5 +1,5 @@
error: use Option::map_or instead of an if let/else 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 | / if let Some(x) = string {
LL | | (true, x) LL | | (true, x)
@ -11,7 +11,7 @@ LL | | }
= note: `-D clippy::option-if-let-else` implied by `-D warnings` = note: `-D clippy::option-if-let-else` implied by `-D warnings`
error: use Option::map_or instead of an if let/else 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 { LL | } else if let Some(x) = string {
| ____________^ | ____________^
@ -22,19 +22,19 @@ LL | | }
| |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }` | |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }`
error: use Option::map_or instead of an if let/else 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 }; LL | let _ = if let Some(s) = *string { s.len() } else { 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
error: use Option::map_or instead of an if let/else 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 }; LL | let _ = if let Some(s) = &num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else 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 { LL | let _ = if let Some(s) = &mut num {
| _____________^ | _____________^
@ -54,13 +54,13 @@ LL | });
| |
error: use Option::map_or instead of an if let/else 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 }; LL | let _ = if let Some(ref s) = num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else 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 { LL | let _ = if let Some(mut s) = num {
| _____________^ | _____________^
@ -80,7 +80,7 @@ LL | });
| |
error: use Option::map_or instead of an if let/else 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 { LL | let _ = if let Some(ref mut s) = num {
| _____________^ | _____________^
@ -100,7 +100,7 @@ LL | });
| |
error: use Option::map_or instead of an if let/else 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 | / if let Some(x) = arg {
LL | | let y = x * x; LL | | let y = x * x;
@ -119,7 +119,19 @@ LL | })
| |
error: use Option::map_or_else instead of an if let/else 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 { LL | let _ = if let Some(x) = arg {
| _____________^ | _____________^
@ -142,10 +154,10 @@ LL | }, |x| x * x * x * x);
| |
error: use Option::map_or instead of an if let/else 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 }; LL | let _ = if let Some(x) = optional { x + 2 } else { 5 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
error: aborting due to 11 previous errors error: aborting due to 12 previous errors

View file

@ -0,0 +1,70 @@
#![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(())
}

View file

@ -0,0 +1,105 @@
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

View file

@ -9,6 +9,7 @@ fn main() {
print!("Hello {}\n", "world"); print!("Hello {}\n", "world");
print!("Hello {} {}\n", "world", "#2"); print!("Hello {} {}\n", "world", "#2");
print!("{}\n", 1265); print!("{}\n", 1265);
print!("\n");
// these are all fine // these are all fine
print!(""); print!("");

View file

@ -44,7 +44,18 @@ LL | println!("{}", 1265);
| ^^^^^^^ -- | ^^^^^^^ --
error: using `print!()` with a format string that ends in a single newline 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 LL | print!("//n"); // should fail
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
@ -55,7 +66,7 @@ LL | println!("/"); // should fail
| ^^^^^^^ -- | ^^^^^^^ --
error: using `print!()` with a format string that ends in a single newline 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 | / print!(
LL | | " LL | | "
@ -70,7 +81,7 @@ LL | ""
| |
error: using `print!()` with a format string that ends in a single newline 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 | / print!(
LL | | r" LL | | r"
@ -85,7 +96,7 @@ LL | r""
| |
error: using `print!()` with a format string that ends in a single newline 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 LL | print!("/r/n"); //~ ERROR
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
@ -96,7 +107,7 @@ LL | println!("/r"); //~ ERROR
| ^^^^^^^ -- | ^^^^^^^ --
error: using `print!()` with a format string that ends in a single newline 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 | print!("foo/rbar/n") // ~ ERROR
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^
@ -106,5 +117,5 @@ help: use `println!` instead
LL | println!("foo/rbar") // ~ ERROR LL | println!("foo/rbar") // ~ ERROR
| ^^^^^^^ -- | ^^^^^^^ --
error: aborting due to 9 previous errors error: aborting due to 10 previous errors

View file

@ -0,0 +1,26 @@
#![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() {}

View file

@ -0,0 +1,52 @@
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

View file

@ -0,0 +1,25 @@
#![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() {}

View file

@ -0,0 +1,52 @@
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

View file

@ -0,0 +1,12 @@
#![warn(clippy::rc_buffer)]
use std::rc::Rc;
struct String;
struct S {
// does not trigger lint
good1: Rc<String>,
}
fn main() {}

View file

@ -18,39 +18,14 @@ fn main() {
if Err::<i32, i32>(42).is_err() {} 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_ok() {}
while Ok::<i32, i32>(10).is_err() {} 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 Ok::<i32, i32>(42).is_ok() {}
if Err::<i32, i32>(42).is_err() {} 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) { if let Ok(x) = Ok::<i32, i32>(42) {
println!("{}", x); println!("{}", x);
} }
@ -63,48 +38,25 @@ fn main() {
Err::<i32, i32>(42).is_ok(); 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 _ = 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(); issue5504();
issue6067(); issue6067();
issue6065();
let _ = if gen_opt().is_some() { let _ = if gen_res().is_ok() {
1 1
} else if gen_opt().is_none() {
2
} else if gen_res().is_ok() {
3
} else if gen_res().is_err() { } else if gen_res().is_err() {
4 2
} else { } else {
5 3
}; };
} }
fn gen_opt() -> Option<()> {
None
}
fn gen_res() -> Result<(), ()> { fn gen_res() -> Result<(), ()> {
Ok(()) Ok(())
} }
fn takes_bool(_: bool) {}
fn foo() {}
fn bar() {}
macro_rules! m { macro_rules! m {
() => { () => {
Some(42u32) Some(42u32)
@ -128,31 +80,30 @@ fn issue5504() {
while m!().is_some() {} 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. // 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` // However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const,
// of `Option` were stabilized as const, so the following should be linted. // so the following should be linted.
const fn issue6067() { const fn issue6067() {
if Ok::<i32, i32>(42).is_ok() {} if Ok::<i32, i32>(42).is_ok() {}
if Err::<i32, i32>(42).is_err() {} 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_ok() {}
while Ok::<i32, i32>(10).is_err() {} while Ok::<i32, i32>(10).is_err() {}
while Some(42).is_some() {}
while None::<()>.is_none() {}
Ok::<i32, i32>(42).is_ok(); Ok::<i32, i32>(42).is_ok();
Err::<i32, i32>(42).is_err(); Err::<i32, i32>(42).is_err();
Some(42).is_some();
None::<()>.is_none();
} }

View file

@ -18,39 +18,14 @@ fn main() {
if let Err(_) = Err::<i32, i32>(42) {} 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 Ok(_) = Ok::<i32, i32>(10) {}
while let Err(_) = 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 Ok::<i32, i32>(42).is_ok() {}
if Err::<i32, i32>(42).is_err() {} 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) { if let Ok(x) = Ok::<i32, i32>(42) {
println!("{}", x); println!("{}", x);
} }
@ -75,57 +50,25 @@ fn main() {
Err(_) => false, 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 _ = 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(); issue5504();
issue6067(); issue6067();
issue6065();
let _ = if let Some(_) = gen_opt() { let _ = if let Ok(_) = gen_res() {
1 1
} else if let None = gen_opt() {
2
} else if let Ok(_) = gen_res() {
3
} else if let Err(_) = gen_res() { } else if let Err(_) = gen_res() {
4 2
} else { } else {
5 3
}; };
} }
fn gen_opt() -> Option<()> {
None
}
fn gen_res() -> Result<(), ()> { fn gen_res() -> Result<(), ()> {
Ok(()) Ok(())
} }
fn takes_bool(_: bool) {}
fn foo() {}
fn bar() {}
macro_rules! m { macro_rules! m {
() => { () => {
Some(42u32) Some(42u32)
@ -149,26 +92,29 @@ fn issue5504() {
while let Some(_) = m!() {} 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. // 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` // However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const,
// of `Option` were stabilized as const, so the following should be linted. // so the following should be linted.
const fn issue6067() { const fn issue6067() {
if let Ok(_) = Ok::<i32, i32>(42) {} if let Ok(_) = Ok::<i32, i32>(42) {}
if let Err(_) = Err::<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 Ok(_) = Ok::<i32, i32>(10) {}
while let Err(_) = 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) { match Ok::<i32, i32>(42) {
Ok(_) => true, Ok(_) => true,
Err(_) => false, Err(_) => false,
@ -178,14 +124,4 @@ const fn issue6067() {
Ok(_) => false, Ok(_) => false,
Err(_) => true, Err(_) => true,
}; };
match Some(42) {
Some(_) => true,
None => false,
};
match None::<()> {
Some(_) => false,
None => true,
};
} }

View file

@ -18,62 +18,20 @@ error: redundant pattern matching, consider using `is_err()`
LL | if let Err(_) = Err::<i32, i32>(42) {} LL | if let Err(_) = Err::<i32, i32>(42) {}
| -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()` | -------^^^^^^---------------------- 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()` 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) {} LL | while let Ok(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()` | ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
error: redundant pattern matching, consider using `is_err()` 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) {} LL | while let Err(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()` | ----------^^^^^^--------------------- 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()` 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 | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => true, LL | | Ok(_) => true,
@ -82,7 +40,7 @@ LL | | };
| |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()` | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()` 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 | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => false, LL | | Ok(_) => false,
@ -91,7 +49,7 @@ LL | | };
| |_____^ help: try this: `Ok::<i32, i32>(42).is_err()` | |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `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 | / match Err::<i32, i32>(42) {
LL | | Ok(_) => false, LL | | Ok(_) => false,
@ -100,7 +58,7 @@ LL | | };
| |_____^ help: try this: `Err::<i32, i32>(42).is_err()` | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()` 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 | / match Err::<i32, i32>(42) {
LL | | Ok(_) => true, LL | | Ok(_) => true,
@ -108,144 +66,74 @@ LL | | Err(_) => false,
LL | | }; LL | | };
| |_____^ help: try this: `Err::<i32, i32>(42).is_ok()` | |_____^ 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()` 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 }; LL | let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
| -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()` | -------^^^^^--------------------- 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()` 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() { LL | let _ = if let Ok(_) = gen_res() {
| -------^^^^^------------ help: try this: `if gen_res().is_ok()` | -------^^^^^------------ help: try this: `if gen_res().is_ok()`
error: redundant pattern matching, consider using `is_err()` 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() { LL | } else if let Err(_) = gen_res() {
| -------^^^^^^------------ help: try this: `if gen_res().is_err()` | -------^^^^^^------------ help: try this: `if gen_res().is_err()`
error: redundant pattern matching, consider using `is_some()` 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()) {} LL | while let Some(_) = r#try!(result_opt()) {}
| ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `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()) {} LL | if let Some(_) = r#try!(result_opt()) {}
| -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `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!() {} LL | if let Some(_) = m!() {}
| -------^^^^^^^------- help: try this: `if m!().is_some()` | -------^^^^^^^------- help: try this: `if m!().is_some()`
error: redundant pattern matching, consider using `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!() {} LL | while let Some(_) = m!() {}
| ----------^^^^^^^------- help: try this: `while m!().is_some()` | ----------^^^^^^^------- help: try this: `while m!().is_some()`
error: redundant pattern matching, consider using `is_ok()` 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) {} LL | if let Ok(_) = Ok::<i32, i32>(42) {}
| -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()` | -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()` 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) {} LL | if let Err(_) = Err::<i32, i32>(42) {}
| -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()` | -------^^^^^^---------------------- 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()` 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) {} LL | while let Ok(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()` | ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
error: redundant pattern matching, consider using `is_err()` 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) {} LL | while let Err(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()` | ----------^^^^^^--------------------- 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()` 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 | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => true, LL | | Ok(_) => true,
@ -254,7 +142,7 @@ LL | | };
| |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()` | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()` 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 | / match Err::<i32, i32>(42) {
LL | | Ok(_) => false, LL | | Ok(_) => false,
@ -262,23 +150,5 @@ LL | | Err(_) => true,
LL | | }; LL | | };
| |_____^ help: try this: `Err::<i32, i32>(42).is_err()` | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_some()` error: aborting due to 22 previous errors
--> $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

View file

@ -0,0 +1,85 @@
// 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();
}

View file

@ -0,0 +1,100 @@
// 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,
};
}

View file

@ -0,0 +1,134 @@
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

Some files were not shown because too many files have changed in this diff Show more