From b48699e4cfd8af15669227049f3c6056d4084aba Mon Sep 17 00:00:00 2001 From: cherryblossom <31467609+cherryblossom000@users.noreply.github.com> Date: Thu, 22 Apr 2021 19:34:36 +1000 Subject: [PATCH 01/12] `single_component_path_imports`: ignore `pub(crate) use some_macro;` (fixes #7106) --- .../src/single_component_path_imports.rs | 36 +++++++++++++++---- .../single_component_path_imports_macro.fixed | 21 +++++++++++ .../ui/single_component_path_imports_macro.rs | 21 +++++++++++ ...single_component_path_imports_macro.stderr | 10 ++++++ 4 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 tests/ui/single_component_path_imports_macro.fixed create mode 100644 tests/ui/single_component_path_imports_macro.rs create mode 100644 tests/ui/single_component_path_imports_macro.stderr diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index 6104103580e98..a45bb1023899d 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::in_macro; -use rustc_ast::{ptr::P, Crate, Item, ItemKind, ModKind, UseTreeKind}; +use rustc_ast::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -60,8 +60,21 @@ fn check_mod(cx: &EarlyContext<'_>, items: &[P]) { // ``` let mut single_use_usages = Vec::new(); + // keep track of macros defined in the module as we don't want it to trigger on this (#7106) + // ```rust,ignore + // macro_rules! foo { () => {} }; + // pub(crate) use foo; + // ``` + let mut macros = Vec::new(); + for item in items { - track_uses(cx, &item, &mut imports_reused_with_self, &mut single_use_usages); + track_uses( + cx, + &item, + &mut imports_reused_with_self, + &mut single_use_usages, + &mut macros, + ); } for single_use in &single_use_usages { @@ -96,6 +109,7 @@ fn track_uses( item: &Item, imports_reused_with_self: &mut Vec, single_use_usages: &mut Vec<(Symbol, Span, bool)>, + macros: &mut Vec, ) { if in_macro(item.span) || item.vis.kind.is_pub() { return; @@ -105,14 +119,22 @@ fn track_uses( ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => { check_mod(cx, &items); }, + ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => { + macros.push(item.ident.name); + }, ItemKind::Use(use_tree) => { let segments = &use_tree.prefix.segments; + let should_report = + |name: &Symbol| !macros.contains(name) || matches!(item.vis.kind, VisibilityKind::Inherited); + // keep track of `use some_module;` usages if segments.len() == 1 { if let UseTreeKind::Simple(None, _, _) = use_tree.kind { - let ident = &segments[0].ident; - single_use_usages.push((ident.name, item.span, true)); + let name = segments[0].ident.name; + if should_report(&name) { + single_use_usages.push((name, item.span, true)); + } } return; } @@ -124,8 +146,10 @@ fn track_uses( let segments = &tree.0.prefix.segments; if segments.len() == 1 { if let UseTreeKind::Simple(None, _, _) = tree.0.kind { - let ident = &segments[0].ident; - single_use_usages.push((ident.name, tree.0.span, false)); + let name = segments[0].ident.name; + if should_report(&name) { + single_use_usages.push((name, tree.0.span, false)); + } } } } diff --git a/tests/ui/single_component_path_imports_macro.fixed b/tests/ui/single_component_path_imports_macro.fixed new file mode 100644 index 0000000000000..05863f9a2bf48 --- /dev/null +++ b/tests/ui/single_component_path_imports_macro.fixed @@ -0,0 +1,21 @@ +// run-rustfix +// edition:2018 +#![warn(clippy::single_component_path_imports)] +#![allow(unused_imports)] + +// #7106: use statements exporting a macro within a crate should not trigger lint + +macro_rules! m1 { + () => {}; +} +pub(crate) use m1; // ok + +macro_rules! m2 { + () => {}; +} + // fail + +fn main() { + m1!(); + m2!(); +} diff --git a/tests/ui/single_component_path_imports_macro.rs b/tests/ui/single_component_path_imports_macro.rs new file mode 100644 index 0000000000000..633deea348b81 --- /dev/null +++ b/tests/ui/single_component_path_imports_macro.rs @@ -0,0 +1,21 @@ +// run-rustfix +// edition:2018 +#![warn(clippy::single_component_path_imports)] +#![allow(unused_imports)] + +// #7106: use statements exporting a macro within a crate should not trigger lint + +macro_rules! m1 { + () => {}; +} +pub(crate) use m1; // ok + +macro_rules! m2 { + () => {}; +} +use m2; // fail + +fn main() { + m1!(); + m2!(); +} diff --git a/tests/ui/single_component_path_imports_macro.stderr b/tests/ui/single_component_path_imports_macro.stderr new file mode 100644 index 0000000000000..239efb393b1ab --- /dev/null +++ b/tests/ui/single_component_path_imports_macro.stderr @@ -0,0 +1,10 @@ +error: this import is redundant + --> $DIR/single_component_path_imports_macro.rs:16:1 + | +LL | use m2; // fail + | ^^^^^^^ help: remove it entirely + | + = note: `-D clippy::single-component-path-imports` implied by `-D warnings` + +error: aborting due to previous error + From 5625d58f9f3fbff3d81cbab76fbbcfc5ff06c833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=C3=A9nore=20Bouttefeux?= Date: Fri, 16 Apr 2021 20:12:16 +0200 Subject: [PATCH 02/12] add detection unused_io_amount of "or", "or_else" and "ok" --- clippy_lints/src/unused_io_amount.rs | 20 ++++++++++---- tests/ui/unused_io_amount.rs | 41 +++++++++++++++++++++++++++- tests/ui/unused_io_amount.stderr | 30 +++++++++++++++++++- 3 files changed, 84 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 5e8e530f480fb..3387f35bac3d4 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -47,25 +47,35 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { func.kind, hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryIntoResult, _)) ) { - check_method_call(cx, &args[0], expr); + check_map_error(cx, &args[0], expr); } } else { - check_method_call(cx, res, expr); + check_map_error(cx, res, expr); } }, - hir::ExprKind::MethodCall(path, _, args, _) => match &*path.ident.as_str() { "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => { - check_method_call(cx, &args[0], expr); + check_map_error(cx, &args[0], expr); }, _ => (), }, - _ => (), } } } +fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) { + let mut call = call; + while let hir::ExprKind::MethodCall(ref path, _, ref args, _) = call.kind { + if matches!(&*path.ident.as_str(), "or" | "or_else" | "ok") { + call = &args[0]; + } else { + break; + } + } + check_method_call(cx, call, expr); +} + fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) { if let hir::ExprKind::MethodCall(path, _, _, _) = call.kind { let symbol = &*path.ident.as_str(); diff --git a/tests/ui/unused_io_amount.rs b/tests/ui/unused_io_amount.rs index ebaba9629db16..8b141e25942d7 100644 --- a/tests/ui/unused_io_amount.rs +++ b/tests/ui/unused_io_amount.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] #![warn(clippy::unused_io_amount)] -use std::io; +use std::io::{self, Read}; fn question_mark(s: &mut T) -> io::Result<()> { s.write(b"test")?; @@ -22,4 +22,43 @@ fn vectored(s: &mut T) -> io::Result<()> { Ok(()) } +fn ok(file: &str) -> Option<()> { + let mut reader = std::fs::File::open(file).ok()?; + let mut result = [0u8; 0]; + reader.read(&mut result).ok()?; + Some(()) +} + +#[allow(clippy::redundant_closure)] +#[allow(clippy::bind_instead_of_map)] +fn or_else(file: &str) -> io::Result<()> { + let mut reader = std::fs::File::open(file)?; + let mut result = [0u8; 0]; + reader.read(&mut result).or_else(|err| Err(err))?; + Ok(()) +} + +#[derive(Debug)] +enum Error { + Kind, +} + +fn or(file: &str) -> Result<(), Error> { + let mut reader = std::fs::File::open(file).unwrap(); + let mut result = [0u8; 0]; + reader.read(&mut result).or(Err(Error::Kind))?; + Ok(()) +} + +fn combine_or(file: &str) -> Result<(), Error> { + let mut reader = std::fs::File::open(file).unwrap(); + let mut result = [0u8; 0]; + reader + .read(&mut result) + .or(Err(Error::Kind)) + .or(Err(Error::Kind)) + .expect("error"); + Ok(()) +} + fn main() {} diff --git a/tests/ui/unused_io_amount.stderr b/tests/ui/unused_io_amount.stderr index 5219d63980b4b..d8dfc0e5a798c 100644 --- a/tests/ui/unused_io_amount.stderr +++ b/tests/ui/unused_io_amount.stderr @@ -36,5 +36,33 @@ error: written amount is not handled LL | s.write_vectored(&[io::IoSlice::new(&[])])?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: read amount is not handled. Use `Read::read_exact` instead + --> $DIR/unused_io_amount.rs:28:5 + | +LL | reader.read(&mut result).ok()?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: read amount is not handled. Use `Read::read_exact` instead + --> $DIR/unused_io_amount.rs:37:5 + | +LL | reader.read(&mut result).or_else(|err| Err(err))?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: read amount is not handled. Use `Read::read_exact` instead + --> $DIR/unused_io_amount.rs:49:5 + | +LL | reader.read(&mut result).or(Err(Error::Kind))?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: read amount is not handled. Use `Read::read_exact` instead + --> $DIR/unused_io_amount.rs:56:5 + | +LL | / reader +LL | | .read(&mut result) +LL | | .or(Err(Error::Kind)) +LL | | .or(Err(Error::Kind)) +LL | | .expect("error"); + | |________________________^ + +error: aborting due to 10 previous errors From 6c423757dd677c88c38ae32e4ee528a064fd3057 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 22 Apr 2021 13:12:10 -0400 Subject: [PATCH 03/12] Fix lintcheck on windows --- lintcheck/src/main.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index bfb0c3b3f74ec..f6a75595c986b 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -22,9 +22,16 @@ use rayon::prelude::*; use serde::{Deserialize, Serialize}; use serde_json::Value; +#[cfg(not(windows))] const CLIPPY_DRIVER_PATH: &str = "target/debug/clippy-driver"; +#[cfg(not(windows))] const CARGO_CLIPPY_PATH: &str = "target/debug/cargo-clippy"; +#[cfg(windows)] +const CLIPPY_DRIVER_PATH: &str = "target/debug/clippy-driver.exe"; +#[cfg(windows)] +const CARGO_CLIPPY_PATH: &str = "target/debug/cargo-clippy.exe"; + const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads"; const LINTCHECK_SOURCES: &str = "target/lintcheck/sources"; From db7ad648e7e17eff0f66de2c25c4d581982f981f Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 25 Apr 2021 10:07:01 -0400 Subject: [PATCH 04/12] Fix ICE checking for feature gated const fn --- clippy_utils/src/qualify_min_const_fn.rs | 10 ++++------ tests/ui/crashes/ice-7126.rs | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 tests/ui/crashes/ice-7126.rs diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index b2ce58b597b3d..a08dcf19e5b51 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -364,7 +364,7 @@ fn check_terminator( fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<&RustcVersion>) -> bool { rustc_mir::const_eval::is_const_fn(tcx, def_id) - && if let Some(const_stab) = tcx.lookup_const_stability(def_id) { + && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| { if let rustc_attr::StabilityLevel::Stable { since } = const_stab.level { // Checking MSRV is manually necessary because `rustc` has no such concept. This entire // function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`. @@ -375,10 +375,8 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<&RustcVersion>) -> b .expect("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted"), ) } else { - // `rustc_mir::const_eval::is_const_fn` should return false for unstably const functions. - unreachable!(); + // Unstable const fn with the feature enabled. + msrv.is_none() } - } else { - true - } + }) } diff --git a/tests/ui/crashes/ice-7126.rs b/tests/ui/crashes/ice-7126.rs new file mode 100644 index 0000000000000..ca563ba097851 --- /dev/null +++ b/tests/ui/crashes/ice-7126.rs @@ -0,0 +1,14 @@ +// This test requires a feature gated const fn and will stop working in the future. + +#![feature(const_btree_new)] + +use std::collections::BTreeMap; + +struct Foo(BTreeMap); +impl Foo { + fn new() -> Self { + Self(BTreeMap::new()) + } +} + +fn main() {} From 3f5be5e2357d11ed3273d4e286e2cb9efe46cd28 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sun, 25 Apr 2021 09:51:44 -0500 Subject: [PATCH 05/12] Fix cloned_instead_of_copied MSRV --- .../src/methods/cloned_instead_of_copied.rs | 24 +++++++++++++------ clippy_lints/src/methods/mod.rs | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/methods/cloned_instead_of_copied.rs b/clippy_lints/src/methods/cloned_instead_of_copied.rs index ba97ab3900ca4..9c1b6f55c8840 100644 --- a/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -1,23 +1,33 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_trait_method; use clippy_utils::ty::{get_iterator_item_ty, is_copy}; +use clippy_utils::{is_trait_method, meets_msrv}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; +use rustc_semver::RustcVersion; use rustc_span::{sym, Span}; use super::CLONED_INSTEAD_OF_COPIED; -pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) { +const ITERATOR_COPIED_MSRV: RustcVersion = RustcVersion::new(1, 36, 0); +const OPTION_COPIED_MSRV: RustcVersion = RustcVersion::new(1, 35, 0); + +pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<&RustcVersion>) { let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); let inner_ty = match recv_ty.kind() { // `Option` -> `T` - ty::Adt(adt, subst) if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) => subst.type_at(0), - _ if is_trait_method(cx, expr, sym::Iterator) => match get_iterator_item_ty(cx, recv_ty) { - // ::Item - Some(ty) => ty, - _ => return, + ty::Adt(adt, subst) + if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) && meets_msrv(msrv, &OPTION_COPIED_MSRV) => + { + subst.type_at(0) + }, + _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, &ITERATOR_COPIED_MSRV) => { + match get_iterator_item_ty(cx, recv_ty) { + // ::Item + Some(ty) => ty, + _ => return, + } }, _ => return, }; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c2cd3011d1493..e15dbb899b36a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1959,7 +1959,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv), ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv), ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv), - ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span), + ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv), ("collect", []) => match method_call!(recv) { Some(("cloned", [recv2], _)) => iter_cloned_collect::check(cx, expr, recv2), Some(("map", [m_recv, m_arg], _)) => { From efc4c6c957ea2b0d870f4728fa934042213da5e8 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sun, 25 Apr 2021 18:10:38 +0200 Subject: [PATCH 06/12] extend `single_element_loop` to match `.iter()` --- clippy_lints/src/loops/single_element_loop.rs | 8 +++++++- tests/ui/single_element_loop.fixed | 5 +++++ tests/ui/single_element_loop.rs | 4 ++++ tests/ui/single_element_loop.stderr | 18 +++++++++++++++++- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index fc067e81bcafb..0fd09ff7197ae 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -14,8 +14,14 @@ pub(super) fn check<'tcx>( body: &'tcx Expr<'_>, expr: &'tcx Expr<'_>, ) { + let arg_expr = match arg.kind { + ExprKind::AddrOf(BorrowKind::Ref, _, ref_arg) => ref_arg, + ExprKind::MethodCall(method, _, args, _) if args.len() == 1 && method.ident.name == rustc_span::sym::iter => { + &args[0] + }, + _ => return, + }; if_chain! { - if let ExprKind::AddrOf(BorrowKind::Ref, _, arg_expr) = arg.kind; if let PatKind::Binding(.., target, _) = pat.kind; if let ExprKind::Array([arg_expression]) = arg_expr.kind; if let ExprKind::Path(ref list_item) = arg_expression.kind; diff --git a/tests/ui/single_element_loop.fixed b/tests/ui/single_element_loop.fixed index 8ca068293a611..c307afffcb863 100644 --- a/tests/ui/single_element_loop.fixed +++ b/tests/ui/single_element_loop.fixed @@ -8,4 +8,9 @@ fn main() { let item = &item1; println!("{}", item); } + + { + let item = &item1; + println!("{:?}", item); + } } diff --git a/tests/ui/single_element_loop.rs b/tests/ui/single_element_loop.rs index 57e9336a31fcf..2c0c03b721199 100644 --- a/tests/ui/single_element_loop.rs +++ b/tests/ui/single_element_loop.rs @@ -7,4 +7,8 @@ fn main() { for item in &[item1] { println!("{}", item); } + + for item in [item1].iter() { + println!("{:?}", item); + } } diff --git a/tests/ui/single_element_loop.stderr b/tests/ui/single_element_loop.stderr index 90be1dc328371..0e35a33ded5ba 100644 --- a/tests/ui/single_element_loop.stderr +++ b/tests/ui/single_element_loop.stderr @@ -15,5 +15,21 @@ LL | println!("{}", item); LL | } | -error: aborting due to previous error +error: for loop over a single element + --> $DIR/single_element_loop.rs:11:5 + | +LL | / for item in [item1].iter() { +LL | | println!("{:?}", item); +LL | | } + | |_____^ + | +help: try + | +LL | { +LL | let item = &item1; +LL | println!("{:?}", item); +LL | } + | + +error: aborting due to 2 previous errors From dcf4e07458c4136f2107d5ff26590c47f9590b1a Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 26 Apr 2021 11:09:24 -0500 Subject: [PATCH 07/12] Finish MSRV for cloned_instead_of_copied --- clippy_lints/src/utils/conf.rs | 2 +- tests/ui/min_rust_version_attr.rs | 4 ++++ tests/ui/min_rust_version_attr.stderr | 8 ++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 147f823491d6d..2f8714b179978 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -106,7 +106,7 @@ macro_rules! define_Conf { pub use self::helpers::Conf; define_Conf! { - /// Lint: REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, NEEDLESS_QUESTION_MARK, PTR_AS_PTR. The minimum rust version that the project supports + /// Lint: CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, NEEDLESS_QUESTION_MARK, PTR_AS_PTR. The minimum rust version that the project supports (msrv, "msrv": Option, None), /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses (blacklisted_names, "blacklisted_names": Vec, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()), diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs index 49ace1ca128c1..7f9f7ddc53575 100644 --- a/tests/ui/min_rust_version_attr.rs +++ b/tests/ui/min_rust_version_attr.rs @@ -4,6 +4,10 @@ use std::ops::{Deref, RangeFrom}; +fn cloned_instead_of_copied() { + let _ = [1].iter().cloned(); +} + fn option_as_ref_deref() { let mut opt = Some(String::from("123")); diff --git a/tests/ui/min_rust_version_attr.stderr b/tests/ui/min_rust_version_attr.stderr index 8d3575c2da83b..ddb1e1f372409 100644 --- a/tests/ui/min_rust_version_attr.stderr +++ b/tests/ui/min_rust_version_attr.stderr @@ -1,12 +1,12 @@ error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:156:24 + --> $DIR/min_rust_version_attr.rs:160:24 | LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::manual-strip` implied by `-D warnings` note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:155:9 + --> $DIR/min_rust_version_attr.rs:159:9 | LL | if s.starts_with("hello, ") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,13 +17,13 @@ LL | assert_eq!(.to_uppercase(), "WORLD!"); | error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:168:24 + --> $DIR/min_rust_version_attr.rs:172:24 | LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); | ^^^^^^^^^^^^^^^^^^^^ | note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:167:9 + --> $DIR/min_rust_version_attr.rs:171:9 | LL | if s.starts_with("hello, ") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 84003aa7a18f2673b20340dd20344dda8265ba7a Mon Sep 17 00:00:00 2001 From: Mateusz Gacek <96mateusz.gacek@gmail.com> Date: Mon, 26 Apr 2021 12:08:24 -0700 Subject: [PATCH 08/12] fix invalid code suggestion in `manual_unwrap_or`, due to macro expansion --- clippy_lints/src/manual_unwrap_or.rs | 11 ++++++++++- tests/ui/manual_unwrap_or.fixed | 12 ++++++++++++ tests/ui/manual_unwrap_or.rs | 15 +++++++++++++++ tests/ui/manual_unwrap_or.stderr | 12 +++++++++++- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 65baa2552ccc6..520162559e50f 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -112,6 +112,15 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { then { let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent)); + + let suggestion = if scrutinee.span.from_expansion() { + // we don't want parenthesis around macro, e.g. `(some_macro!()).unwrap_or(0)` + sugg::Sugg::hir_with_macro_callsite(cx, scrutinee, "..") + } + else { + sugg::Sugg::hir(cx, scrutinee, "..").maybe_par() + }; + span_lint_and_sugg( cx, MANUAL_UNWRAP_OR, expr.span, @@ -119,7 +128,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { "replace with", format!( "{}.unwrap_or({})", - sugg::Sugg::hir(cx, scrutinee, "..").maybe_par(), + suggestion, reindented_or_body, ), Applicability::MachineApplicable, diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index f1d3252230bc2..e7a29596b73ac 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -151,4 +151,16 @@ const fn const_fn_result_unwrap_or() { }; } +mod issue6965 { + macro_rules! some_macro { + () => { + if 1 > 2 { Some(1) } else { None } + }; + } + + fn test() { + let _ = some_macro!().unwrap_or(0); + } +} + fn main() {} diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index c9eee25a5b153..66006b6c616f0 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -190,4 +190,19 @@ const fn const_fn_result_unwrap_or() { }; } +mod issue6965 { + macro_rules! some_macro { + () => { + if 1 > 2 { Some(1) } else { None } + }; + } + + fn test() { + let _ = match some_macro!() { + Some(val) => val, + None => 0, + }; + } +} + fn main() {} diff --git a/tests/ui/manual_unwrap_or.stderr b/tests/ui/manual_unwrap_or.stderr index fc174c4c2705d..99625b789b6a4 100644 --- a/tests/ui/manual_unwrap_or.stderr +++ b/tests/ui/manual_unwrap_or.stderr @@ -141,5 +141,15 @@ LL | | Err(_) => "Alice", LL | | }; | |_____^ help: replace with: `Ok::<&str, &str>("Bob").unwrap_or("Alice")` -error: aborting due to 13 previous errors +error: this pattern reimplements `Option::unwrap_or` + --> $DIR/manual_unwrap_or.rs:201:17 + | +LL | let _ = match some_macro!() { + | _________________^ +LL | | Some(val) => val, +LL | | None => 0, +LL | | }; + | |_________^ help: replace with: `some_macro!().unwrap_or(0)` + +error: aborting due to 14 previous errors From d7627dcfc8a60aaedccf002738dc44a2576fa8fd Mon Sep 17 00:00:00 2001 From: Mateusz Gacek <96mateusz.gacek@gmail.com> Date: Mon, 26 Apr 2021 13:03:51 -0700 Subject: [PATCH 09/12] Fix FN in `iter_cloned_collect` with a large array --- clippy_lints/src/methods/utils.rs | 4 +--- tests/ui/iter_cloned_collect.fixed | 4 ++++ tests/ui/iter_cloned_collect.rs | 4 ++++ tests/ui/iter_cloned_collect.stderr | 8 +++++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index f6bf37e08b966..0daea47816a51 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -18,9 +18,7 @@ pub(super) fn derefs_to_slice<'tcx>( ty::Slice(_) => true, ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type), - ty::Array(_, size) => size - .try_eval_usize(cx.tcx, cx.param_env) - .map_or(false, |size| size < 32), + ty::Array(_, size) => size.try_eval_usize(cx.tcx, cx.param_env).is_some(), ty::Ref(_, inner, _) => may_slice(cx, inner), _ => false, } diff --git a/tests/ui/iter_cloned_collect.fixed b/tests/ui/iter_cloned_collect.fixed index 2773227e26bca..39cc58cd29843 100644 --- a/tests/ui/iter_cloned_collect.fixed +++ b/tests/ui/iter_cloned_collect.fixed @@ -19,4 +19,8 @@ fn main() { let _: Vec = std::ffi::CStr::from_ptr(std::ptr::null()) .to_bytes().to_vec(); } + + // Issue #6808 + let arr: [u8; 64] = [0; 64]; + let _: Vec<_> = arr.to_vec(); } diff --git a/tests/ui/iter_cloned_collect.rs b/tests/ui/iter_cloned_collect.rs index 60a4eac23c79f..c2a036ec09f1e 100644 --- a/tests/ui/iter_cloned_collect.rs +++ b/tests/ui/iter_cloned_collect.rs @@ -22,4 +22,8 @@ fn main() { .cloned() .collect(); } + + // Issue #6808 + let arr: [u8; 64] = [0; 64]; + let _: Vec<_> = arr.iter().cloned().collect(); } diff --git a/tests/ui/iter_cloned_collect.stderr b/tests/ui/iter_cloned_collect.stderr index b90a1e6c91967..e1df61794cece 100644 --- a/tests/ui/iter_cloned_collect.stderr +++ b/tests/ui/iter_cloned_collect.stderr @@ -22,5 +22,11 @@ LL | | .cloned() LL | | .collect(); | |______________________^ help: try: `.to_vec()` -error: aborting due to 3 previous errors +error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable + --> $DIR/iter_cloned_collect.rs:28:24 + | +LL | let _: Vec<_> = arr.iter().cloned().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` + +error: aborting due to 4 previous errors From 33ed8b5b24caf1e3d1d4d8020f61ca65102c87f8 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 26 Apr 2021 15:49:25 -0500 Subject: [PATCH 10/12] Remove needless_question_mark MSRV --- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/needless_question_mark.rs | 42 +++---------- clippy_lints/src/utils/conf.rs | 2 +- tests/ui/needless_question_mark.fixed | 72 ---------------------- tests/ui/needless_question_mark.rs | 72 ---------------------- tests/ui/needless_question_mark.stderr | 22 +------ 6 files changed, 13 insertions(+), 199 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2ff633bcda5f0..c84890299df09 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1076,7 +1076,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv)); store.register_late_pass(move || box use_self::UseSelf::new(msrv)); store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv)); - store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark::new(msrv)); + store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark); store.register_late_pass(move || box casts::Casts::new(msrv)); store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv)); diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index cfe7ae6630e04..7b156a8c49dd9 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -1,15 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_lang_ctor; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{differing_macro_contexts, meets_msrv}; +use clippy_utils::{differing_macro_contexts, is_lang_ctor}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionSome, ResultOk}; use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { @@ -63,21 +61,7 @@ declare_clippy_lint! { "Suggest `value.inner_option` instead of `Some(value.inner_option?)`. The same goes for `Result`." } -const NEEDLESS_QUESTION_MARK_RESULT_MSRV: RustcVersion = RustcVersion::new(1, 13, 0); -const NEEDLESS_QUESTION_MARK_OPTION_MSRV: RustcVersion = RustcVersion::new(1, 22, 0); - -pub struct NeedlessQuestionMark { - msrv: Option, -} - -impl NeedlessQuestionMark { - #[must_use] - pub fn new(msrv: Option) -> Self { - Self { msrv } - } -} - -impl_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]); +declare_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]); #[derive(Debug)] enum SomeOkCall<'a> { @@ -111,7 +95,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark { _ => return, }; - if let Some(ok_some_call) = is_some_or_ok_call(self, cx, e) { + if let Some(ok_some_call) = is_some_or_ok_call(cx, e) { emit_lint(cx, &ok_some_call); } } @@ -127,14 +111,12 @@ impl LateLintPass<'_> for NeedlessQuestionMark { if_chain! { if let Some(expr) = expr_opt; - if let Some(ok_some_call) = is_some_or_ok_call(self, cx, expr); + if let Some(ok_some_call) = is_some_or_ok_call(cx, expr); then { emit_lint(cx, &ok_some_call); } }; } - - extract_msrv_attr!(LateContext); } fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) { @@ -153,11 +135,7 @@ fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) { ); } -fn is_some_or_ok_call<'a>( - nqml: &NeedlessQuestionMark, - cx: &'a LateContext<'_>, - expr: &'a Expr<'_>, -) -> Option> { +fn is_some_or_ok_call<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option> { if_chain! { // Check outer expression matches CALL_IDENT(ARGUMENT) format if let ExprKind::Call(path, args) = &expr.kind; @@ -188,8 +166,7 @@ fn is_some_or_ok_call<'a>( let inner_is_some = is_type_diagnostic_item(cx, inner_ty, sym::option_type); // Check for Option MSRV - let meets_option_msrv = meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_OPTION_MSRV); - if outer_is_some && inner_is_some && meets_option_msrv { + if outer_is_some && inner_is_some { return Some(SomeOkCall::SomeCall(expr, inner_expr)); } @@ -202,8 +179,7 @@ fn is_some_or_ok_call<'a>( let does_not_call_from = !has_implicit_error_from(cx, expr, inner_expr); // Must meet Result MSRV - let meets_result_msrv = meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_RESULT_MSRV); - if outer_is_result && inner_is_result && does_not_call_from && meets_result_msrv { + if outer_is_result && inner_is_result && does_not_call_from { return Some(SomeOkCall::OkCall(expr, inner_expr)); } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 2f8714b179978..d56855a71c159 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -106,7 +106,7 @@ macro_rules! define_Conf { pub use self::helpers::Conf; define_Conf! { - /// Lint: CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, NEEDLESS_QUESTION_MARK, PTR_AS_PTR. The minimum rust version that the project supports + /// Lint: CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR. The minimum rust version that the project supports (msrv, "msrv": Option, None), /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses (blacklisted_names, "blacklisted_names": Vec, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()), diff --git a/tests/ui/needless_question_mark.fixed b/tests/ui/needless_question_mark.fixed index fd8433870bb1b..52ddd9d2dc826 100644 --- a/tests/ui/needless_question_mark.fixed +++ b/tests/ui/needless_question_mark.fixed @@ -96,78 +96,6 @@ where fn main() {} -mod question_mark_none { - #![clippy::msrv = "1.12.0"] - fn needless_question_mark_option() -> Option { - struct TO { - magic: Option, - } - let to = TO { magic: None }; - Some(to.magic?) // should not be triggered - } - - fn needless_question_mark_result() -> Result { - struct TO { - magic: Result, - } - let to = TO { magic: Ok(1_usize) }; - Ok(to.magic?) // should not be triggered - } - - fn main() { - needless_question_mark_option(); - needless_question_mark_result(); - } -} - -mod question_mark_result { - #![clippy::msrv = "1.21.0"] - fn needless_question_mark_option() -> Option { - struct TO { - magic: Option, - } - let to = TO { magic: None }; - Some(to.magic?) // should not be triggered - } - - fn needless_question_mark_result() -> Result { - struct TO { - magic: Result, - } - let to = TO { magic: Ok(1_usize) }; - to.magic // should be triggered - } - - fn main() { - needless_question_mark_option(); - needless_question_mark_result(); - } -} - -mod question_mark_both { - #![clippy::msrv = "1.22.0"] - fn needless_question_mark_option() -> Option { - struct TO { - magic: Option, - } - let to = TO { magic: None }; - to.magic // should be triggered - } - - fn needless_question_mark_result() -> Result { - struct TO { - magic: Result, - } - let to = TO { magic: Ok(1_usize) }; - to.magic // should be triggered - } - - fn main() { - needless_question_mark_option(); - needless_question_mark_result(); - } -} - // #6921 if a macro wraps an expr in Some( ) and the ? is in the macro use, // the suggestion fails to apply; do not lint macro_rules! some_in_macro { diff --git a/tests/ui/needless_question_mark.rs b/tests/ui/needless_question_mark.rs index 36d45ac7e03e2..1ea4ba0d83fd7 100644 --- a/tests/ui/needless_question_mark.rs +++ b/tests/ui/needless_question_mark.rs @@ -96,78 +96,6 @@ where fn main() {} -mod question_mark_none { - #![clippy::msrv = "1.12.0"] - fn needless_question_mark_option() -> Option { - struct TO { - magic: Option, - } - let to = TO { magic: None }; - Some(to.magic?) // should not be triggered - } - - fn needless_question_mark_result() -> Result { - struct TO { - magic: Result, - } - let to = TO { magic: Ok(1_usize) }; - Ok(to.magic?) // should not be triggered - } - - fn main() { - needless_question_mark_option(); - needless_question_mark_result(); - } -} - -mod question_mark_result { - #![clippy::msrv = "1.21.0"] - fn needless_question_mark_option() -> Option { - struct TO { - magic: Option, - } - let to = TO { magic: None }; - Some(to.magic?) // should not be triggered - } - - fn needless_question_mark_result() -> Result { - struct TO { - magic: Result, - } - let to = TO { magic: Ok(1_usize) }; - Ok(to.magic?) // should be triggered - } - - fn main() { - needless_question_mark_option(); - needless_question_mark_result(); - } -} - -mod question_mark_both { - #![clippy::msrv = "1.22.0"] - fn needless_question_mark_option() -> Option { - struct TO { - magic: Option, - } - let to = TO { magic: None }; - Some(to.magic?) // should be triggered - } - - fn needless_question_mark_result() -> Result { - struct TO { - magic: Result, - } - let to = TO { magic: Ok(1_usize) }; - Ok(to.magic?) // should be triggered - } - - fn main() { - needless_question_mark_option(); - needless_question_mark_result(); - } -} - // #6921 if a macro wraps an expr in Some( ) and the ? is in the macro use, // the suggestion fails to apply; do not lint macro_rules! some_in_macro { diff --git a/tests/ui/needless_question_mark.stderr b/tests/ui/needless_question_mark.stderr index 7cbf1e505adf6..afd68d91e51fe 100644 --- a/tests/ui/needless_question_mark.stderr +++ b/tests/ui/needless_question_mark.stderr @@ -67,25 +67,7 @@ LL | return Ok(t.magic?); | ^^^^^^^^^^^^ help: try: `t.magic` error: question mark operator is useless here - --> $DIR/needless_question_mark.rs:138:9 - | -LL | Ok(to.magic?) // should be triggered - | ^^^^^^^^^^^^^ help: try: `to.magic` - -error: question mark operator is useless here - --> $DIR/needless_question_mark.rs:154:9 - | -LL | Some(to.magic?) // should be triggered - | ^^^^^^^^^^^^^^^ help: try: `to.magic` - -error: question mark operator is useless here - --> $DIR/needless_question_mark.rs:162:9 - | -LL | Ok(to.magic?) // should be triggered - | ^^^^^^^^^^^^^ help: try: `to.magic` - -error: question mark operator is useless here - --> $DIR/needless_question_mark.rs:187:27 + --> $DIR/needless_question_mark.rs:115:27 | LL | || -> Option<_> { Some(Some($expr)?) }() | ^^^^^^^^^^^^^^^^^^ help: try: `Some($expr)` @@ -95,5 +77,5 @@ LL | let _x = some_and_qmark_in_macro!(x?); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 15 previous errors +error: aborting due to 12 previous errors From 340b570ea0479dc3a9f9bbe1031f8686c9f660e1 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 26 Apr 2021 14:10:32 -0500 Subject: [PATCH 11/12] Refactor MSRV aliases --- clippy_lints/src/casts/ptr_as_ptr.rs | 6 ++-- clippy_lints/src/checked_conversions.rs | 6 ++-- clippy_lints/src/from_over_into.rs | 6 ++-- clippy_lints/src/if_then_some_else_none.rs | 6 ++-- clippy_lints/src/manual_non_exhaustive.rs | 6 ++-- clippy_lints/src/manual_strip.rs | 6 ++-- clippy_lints/src/matches.rs | 9 +++--- clippy_lints/src/mem_replace.rs | 6 ++-- .../src/methods/cloned_instead_of_copied.rs | 9 ++---- clippy_lints/src/methods/filter_map_next.rs | 6 ++-- clippy_lints/src/methods/map_unwrap_or.rs | 11 ++++--- .../src/methods/option_as_ref_deref.rs | 6 ++-- clippy_lints/src/missing_const_for_fn.rs | 6 ++-- clippy_lints/src/ranges.rs | 6 ++-- clippy_lints/src/redundant_field_names.rs | 6 ++-- .../src/redundant_static_lifetimes.rs | 6 ++-- clippy_lints/src/unnested_or_patterns.rs | 17 ++++------- clippy_lints/src/use_self.rs | 11 +++---- clippy_utils/src/lib.rs | 1 + clippy_utils/src/msrvs.rs | 29 +++++++++++++++++++ 20 files changed, 80 insertions(+), 85 deletions(-) create mode 100644 clippy_utils/src/msrvs.rs diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 9113e5a0920a2..3132d3a5cf097 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::meets_msrv; use clippy_utils::sugg::Sugg; +use clippy_utils::{meets_msrv, msrvs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability, TyKind}; @@ -12,10 +12,8 @@ use rustc_semver::RustcVersion; use super::PTR_AS_PTR; -const PTR_AS_PTR_MSRV: RustcVersion = RustcVersion::new(1, 38, 0); - pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: &Option) { - if !meets_msrv(msrv.as_ref(), &PTR_AS_PTR_MSRV) { + if !meets_msrv(msrv.as_ref(), &msrvs::POINTER_CAST) { return; } diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 6a2666bc6c011..8d3123e1ec8ee 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{meets_msrv, SpanlessEq}; +use clippy_utils::{meets_msrv, msrvs, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -12,8 +12,6 @@ use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -const CHECKED_CONVERSIONS_MSRV: RustcVersion = RustcVersion::new(1, 34, 0); - declare_clippy_lint! { /// **What it does:** Checks for explicit bounds checking when casting. /// @@ -58,7 +56,7 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); impl<'tcx> LateLintPass<'tcx> for CheckedConversions { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { - if !meets_msrv(self.msrv.as_ref(), &CHECKED_CONVERSIONS_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::TRY_FROM) { return; } diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 5e2baba894349..3560672a74812 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -1,14 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::paths::INTO; -use clippy_utils::{match_def_path, meets_msrv}; +use clippy_utils::{match_def_path, meets_msrv, msrvs}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -const FROM_OVER_INTO_MSRV: RustcVersion = RustcVersion::new(1, 41, 0); - declare_clippy_lint! { /// **What it does:** Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead. /// @@ -57,7 +55,7 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]); impl LateLintPass<'_> for FromOverInto { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - if !meets_msrv(self.msrv.as_ref(), &FROM_OVER_INTO_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::RE_REBALANCING_COHERENCE) { return; } diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 85c95f1151f84..eadcd0867a880 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_with_macro_callsite; -use clippy_utils::{is_else_clause, is_lang_ctor, meets_msrv}; +use clippy_utils::{is_else_clause, is_lang_ctor, meets_msrv, msrvs}; use if_chain::if_chain; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind}; @@ -9,8 +9,6 @@ use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -const IF_THEN_SOME_ELSE_NONE_MSRV: RustcVersion = RustcVersion::new(1, 50, 0); - declare_clippy_lint! { /// **What it does:** Checks for if-else that could be written to `bool::then`. /// @@ -59,7 +57,7 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]); impl LateLintPass<'_> for IfThenSomeElseNone { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv.as_ref(), &IF_THEN_SOME_ELSE_NONE_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::BOOL_THEN) { return; } diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index dc19805b50abd..54f714b54b657 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,7 +1,7 @@ use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::meets_msrv; use clippy_utils::source::snippet_opt; +use clippy_utils::{meets_msrv, msrvs}; use if_chain::if_chain; use rustc_ast::ast::{FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind}; use rustc_errors::Applicability; @@ -10,8 +10,6 @@ use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; -const MANUAL_NON_EXHAUSTIVE_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); - declare_clippy_lint! { /// **What it does:** Checks for manual implementations of the non-exhaustive pattern. /// @@ -76,7 +74,7 @@ impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]); impl EarlyLintPass for ManualNonExhaustive { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if !meets_msrv(self.msrv.as_ref(), &MANUAL_NON_EXHAUSTIVE_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) { return; } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index dfa464ddb81ac..23428524dee97 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -2,7 +2,7 @@ use crate::consts::{constant, Constant}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::usage::mutated_variables; -use clippy_utils::{eq_expr_value, higher, match_def_path, meets_msrv, paths}; +use clippy_utils::{eq_expr_value, higher, match_def_path, meets_msrv, msrvs, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_hir::def::Res; @@ -17,8 +17,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; use rustc_span::Span; -const MANUAL_STRIP_MSRV: RustcVersion = RustcVersion::new(1, 45, 0); - declare_clippy_lint! { /// **What it does:** /// Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using @@ -74,7 +72,7 @@ enum StripKind { impl<'tcx> LateLintPass<'tcx> for ManualStrip { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::STR_STRIP_PREFIX) { return; } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 44b4eb2903531..13b2a834b0a96 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -7,8 +7,9 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs}; use clippy_utils::visitors::LocalUsedVisitor; use clippy_utils::{ - get_parent_expr, in_macro, is_allowed, is_expn_of, is_lang_ctor, is_refutable, is_wild, meets_msrv, path_to_local, - path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks, strip_pat_refs, + get_parent_expr, in_macro, is_allowed, is_expn_of, is_lang_ctor, is_refutable, is_wild, meets_msrv, msrvs, + path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks, + strip_pat_refs, }; use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash}; use if_chain::if_chain; @@ -578,8 +579,6 @@ impl_lint_pass!(Matches => [ MATCH_SAME_ARMS, ]); -const MATCH_LIKE_MATCHES_MACRO_MSRV: RustcVersion = RustcVersion::new(1, 42, 0); - impl<'tcx> LateLintPass<'tcx> for Matches { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) { @@ -588,7 +587,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { redundant_pattern_match::check(cx, expr); - if meets_msrv(self.msrv.as_ref(), &MATCH_LIKE_MATCHES_MACRO_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) { if !check_match_like_matches(cx, expr) { lint_match_arms(cx, expr); } diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index ec60bffe95555..183daee361774 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::{in_macro, is_diag_trait_item, is_lang_ctor, match_def_path, meets_msrv, paths}; +use clippy_utils::{in_macro, is_diag_trait_item, is_lang_ctor, match_def_path, meets_msrv, msrvs, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; @@ -256,8 +256,6 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< } } -const MEM_REPLACE_WITH_DEFAULT_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); - pub struct MemReplace { msrv: Option, } @@ -281,7 +279,7 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { then { check_replace_option_with_none(cx, src, dest, expr.span); check_replace_with_uninit(cx, src, dest, expr.span); - if meets_msrv(self.msrv.as_ref(), &MEM_REPLACE_WITH_DEFAULT_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::MEM_TAKE) { check_replace_with_default(cx, src, dest, expr.span); } } diff --git a/clippy_lints/src/methods/cloned_instead_of_copied.rs b/clippy_lints/src/methods/cloned_instead_of_copied.rs index 9c1b6f55c8840..ecec6da3aa0f6 100644 --- a/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::{get_iterator_item_ty, is_copy}; -use clippy_utils::{is_trait_method, meets_msrv}; +use clippy_utils::{is_trait_method, meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; @@ -10,19 +10,16 @@ use rustc_span::{sym, Span}; use super::CLONED_INSTEAD_OF_COPIED; -const ITERATOR_COPIED_MSRV: RustcVersion = RustcVersion::new(1, 36, 0); -const OPTION_COPIED_MSRV: RustcVersion = RustcVersion::new(1, 35, 0); - pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<&RustcVersion>) { let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); let inner_ty = match recv_ty.kind() { // `Option` -> `T` ty::Adt(adt, subst) - if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) && meets_msrv(msrv, &OPTION_COPIED_MSRV) => + if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) && meets_msrv(msrv, &msrvs::OPTION_COPIED) => { subst.type_at(0) }, - _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, &ITERATOR_COPIED_MSRV) => { + _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) => { match get_iterator_item_ty(cx, recv_ty) { // ::Item Some(ty) => ty, diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index 2b19e4ee8c055..f0d69a1f42e7b 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet; -use clippy_utils::{is_trait_method, meets_msrv}; +use clippy_utils::{is_trait_method, meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -9,8 +9,6 @@ use rustc_span::sym; use super::FILTER_MAP_NEXT; -const FILTER_MAP_NEXT_MSRV: RustcVersion = RustcVersion::new(1, 30, 0); - pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, @@ -19,7 +17,7 @@ pub(super) fn check<'tcx>( msrv: Option<&RustcVersion>, ) { if is_trait_method(cx, expr, sym::Iterator) { - if !meets_msrv(msrv, &FILTER_MAP_NEXT_MSRV) { + if !meets_msrv(msrv, &msrvs::ITERATOR_FIND_MAP) { return; } diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 4330fea727b3a..4d8365fcda126 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::meets_msrv; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::mutated_variables; +use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -11,8 +11,6 @@ use rustc_span::symbol::sym; use super::MAP_UNWRAP_OR; -const MAP_UNWRAP_OR_MSRV: RustcVersion = RustcVersion::new(1, 41, 0); - /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s /// Return true if lint triggered pub(super) fn check<'tcx>( @@ -23,13 +21,14 @@ pub(super) fn check<'tcx>( unwrap_arg: &'tcx hir::Expr<'_>, msrv: Option<&RustcVersion>, ) -> bool { - if !meets_msrv(msrv, &MAP_UNWRAP_OR_MSRV) { - return false; - } // lint if the caller of `map()` is an `Option` let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type); + if is_result && !meets_msrv(msrv, &msrvs::RESULT_MAP_OR_ELSE) { + return false; + } + if is_option || is_result { // Don't make a suggestion that may fail to compile due to mutably borrowing // the same variable twice. diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 7e9c8fa829dec..5a57135038fdc 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks}; +use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, remove_blocks}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -12,8 +12,6 @@ use rustc_span::sym; use super::OPTION_AS_REF_DEREF; -const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); - /// lint use of `_.as_ref().map(Deref::deref)` for `Option`s pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -23,7 +21,7 @@ pub(super) fn check<'tcx>( is_mut: bool, msrv: Option<&RustcVersion>, ) { - if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) { + if !meets_msrv(msrv, &msrvs::OPTION_AS_DEREF) { return; } diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 93b7a897405ae..27b5a07c1bc24 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::ty::has_drop; -use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, trait_ref_of_method}; +use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method}; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; @@ -12,8 +12,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; use rustc_typeck::hir_ty_to_ty; -const MISSING_CONST_FOR_FN_MSRV: RustcVersion = RustcVersion::new(1, 37, 0); - declare_clippy_lint! { /// **What it does:** /// @@ -97,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { span: Span, hir_id: HirId, ) { - if !meets_msrv(self.msrv.as_ref(), &MISSING_CONST_FOR_FN_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::CONST_IF_MATCH) { return; } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 1c3c125e57913..7169f96eaf1f3 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -2,7 +2,7 @@ use crate::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; -use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, single_segment_path}; +use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, single_segment_path}; use clippy_utils::{higher, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::RangeLimits; @@ -159,8 +159,6 @@ declare_clippy_lint! { "manually reimplementing {`Range`, `RangeInclusive`}`::contains`" } -const MANUAL_RANGE_CONTAINS_MSRV: RustcVersion = RustcVersion::new(1, 35, 0); - pub struct Ranges { msrv: Option, } @@ -187,7 +185,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges { check_range_zip_with_len(cx, path, args, expr.span); }, ExprKind::Binary(ref op, l, r) => { - if meets_msrv(self.msrv.as_ref(), &MANUAL_RANGE_CONTAINS_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::RANGE_CONTAINS) { check_possible_range_contains(cx, op.node, l, r, expr); } }, diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index abebd4227975e..d5ee8d3468deb 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::meets_msrv; +use clippy_utils::{meets_msrv, msrvs}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -7,8 +7,6 @@ use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -const REDUNDANT_FIELD_NAMES_MSRV: RustcVersion = RustcVersion::new(1, 17, 0); - declare_clippy_lint! { /// **What it does:** Checks for fields in struct literals where shorthands /// could be used. @@ -52,7 +50,7 @@ impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]); impl EarlyLintPass for RedundantFieldNames { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if !meets_msrv(self.msrv.as_ref(), &REDUNDANT_FIELD_NAMES_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::FIELD_INIT_SHORTHAND) { return; } diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 32b57698ec54d..48107d9c037db 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,14 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::meets_msrv; use clippy_utils::source::snippet; +use clippy_utils::{meets_msrv, msrvs}; use rustc_ast::ast::{Item, ItemKind, Ty, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -const REDUNDANT_STATIC_LIFETIMES_MSRV: RustcVersion = RustcVersion::new(1, 17, 0); - declare_clippy_lint! { /// **What it does:** Checks for constants and statics with an explicit `'static` lifetime. /// @@ -100,7 +98,7 @@ impl RedundantStaticLifetimes { impl EarlyLintPass for RedundantStaticLifetimes { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if !meets_msrv(self.msrv.as_ref(), &REDUNDANT_STATIC_LIFETIMES_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::STATIC_IN_CONST) { return; } diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 9376a2cf66a90..3e985fa72b8fe 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -1,11 +1,8 @@ #![allow(clippy::wildcard_imports, clippy::enum_glob_use)] +use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::over; -use clippy_utils::{ - ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path}, - meets_msrv, -}; +use clippy_utils::{meets_msrv, msrvs, over}; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID}; @@ -54,8 +51,6 @@ declare_clippy_lint! { "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`" } -const UNNESTED_OR_PATTERNS_MSRV: RustcVersion = RustcVersion::new(1, 53, 0); - #[derive(Clone, Copy)] pub struct UnnestedOrPatterns { msrv: Option, @@ -72,13 +67,13 @@ impl_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]); impl EarlyLintPass for UnnestedOrPatterns { fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) { - if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { lint_unnested_or_patterns(cx, &a.pat); } } fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { if let ast::ExprKind::Let(pat, _) = &e.kind { lint_unnested_or_patterns(cx, pat); } @@ -86,13 +81,13 @@ impl EarlyLintPass for UnnestedOrPatterns { } fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) { - if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { lint_unnested_or_patterns(cx, &p.pat); } } fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) { - if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { lint_unnested_or_patterns(cx, &l.pat); } } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index c6a3c58a9a2a4..aa4d16633ff80 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use clippy_utils::{in_macro, meets_msrv}; +use clippy_utils::{in_macro, meets_msrv, msrvs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -62,8 +62,6 @@ pub struct UseSelf { stack: Vec, } -const USE_SELF_MSRV: RustcVersion = RustcVersion::new(1, 37, 0); - impl UseSelf { #[must_use] pub fn new(msrv: Option) -> Self { @@ -236,7 +234,10 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) { - if in_macro(hir_ty.span) | in_impl(cx, hir_ty) | !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) { + if in_macro(hir_ty.span) + || in_impl(cx, hir_ty) + || !meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS) + { return; } @@ -288,7 +289,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } } - if in_macro(expr.span) | !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) { + if in_macro(expr.span) || !meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS) { return; } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index b7017411927da..9b60c92bca1be 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -38,6 +38,7 @@ pub mod diagnostics; pub mod eager_or_lazy; pub mod higher; mod hir_utils; +pub mod msrvs; pub mod numeric_literal; pub mod paths; pub mod ptr; diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs new file mode 100644 index 0000000000000..00df04c0144c1 --- /dev/null +++ b/clippy_utils/src/msrvs.rs @@ -0,0 +1,29 @@ +use rustc_semver::RustcVersion; + +macro_rules! msrv_aliases { + ($($major:literal,$minor:literal,$patch:literal { + $($name:ident),* $(,)? + })*) => { + $($( + pub const $name: RustcVersion = RustcVersion::new($major, $minor, $patch); + )*)* + }; +} + +// names may refer to stabilized feature flags or library items +msrv_aliases! { + 1,53,0 { OR_PATTERNS } + 1,50,0 { BOOL_THEN } + 1,46,0 { CONST_IF_MATCH } + 1,45,0 { STR_STRIP_PREFIX } + 1,42,0 { MATCHES_MACRO } + 1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE } + 1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF } + 1,38,0 { POINTER_CAST } + 1,37,0 { TYPE_ALIAS_ENUM_VARIANTS } + 1,36,0 { ITERATOR_COPIED } + 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } + 1,34,0 { TRY_FROM } + 1,30,0 { ITERATOR_FIND_MAP } + 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST } +} From 3a8e759d8a6250b77c37fd43a13aab34b82bbfbb Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 26 Apr 2021 15:47:39 -0500 Subject: [PATCH 12/12] Update MSRV contribution docs --- doc/adding_lints.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 50f0d724016ff..d6cc6d0c2c763 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -390,17 +390,23 @@ pass. ## Specifying the lint's minimum supported Rust version (MSRV) -Projects supporting older versions of Rust would need to disable a lint if it -targets features present in later versions. Support for this can be added by -specifying an MSRV in your lint like so, +Sometimes a lint makes suggestions that require a certain version of Rust. For example, the `manual_strip` lint suggests +using `str::strip_prefix` and `str::strip_suffix` which is only available after Rust 1.45. In such cases, you need to +ensure that the MSRV configured for the project is >= the MSRV of the required Rust feature. If multiple features are +required, just use the one with a lower MSRV. + +First, add an MSRV alias for the required feature in [`clippy_utils::msrvs`](/clippy_utils/src/msrvs.rs). This can be +accessed later as `msrvs::STR_STRIP_PREFIX`, for example. ```rust -const MANUAL_STRIP_MSRV: RustcVersion = RustcVersion::new(1, 45, 0); +msrv_aliases! { + .. + 1,45,0 { STR_STRIP_PREFIX } +} ``` -The project's MSRV will also have to be an attribute in the lint so you'll have -to add a struct and constructor for your lint. The project's MSRV needs to be -passed when the lint is registered in `lib.rs` +In order to access the project-configured MSRV, you need to have an `msrv` field in the LintPass struct, and a +constructor to initialize the field. The `msrv` value is passed to the constructor in `clippy_lints/lib.rs`. ```rust pub struct ManualStrip { @@ -415,11 +421,11 @@ impl ManualStrip { } ``` -The project's MSRV can then be matched against the lint's `msrv` in the LintPass +The project's MSRV can then be matched against the feature MSRV in the LintPass using the `meets_msrv` utility function. ``` rust -if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) { +if !meets_msrv(self.msrv.as_ref(), &msrvs::STR_STRIP_PREFIX) { return; } ```