]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #7138 - mgacek8:issue6808_iter_cloned_collect_FN_with_large_array,...
authorbors <bors@rust-lang.org>
Tue, 27 Apr 2021 13:44:51 +0000 (13:44 +0000)
committerbors <bors@rust-lang.org>
Tue, 27 Apr 2021 13:44:51 +0000 (13:44 +0000)
Fix FN in `iter_cloned_collect` with a large array

fixes #6808
changelog: Fix FN in `iter_cloned_collect` with a large array

I spotted that [is_iterable_array](https://github.com/rust-lang/rust-clippy/blob/a362a4d1d0edb66aef186c1d27b28c60573078f4/clippy_lints/src/loops/explicit_iter_loop.rs#L67-L75) function that `explicit_iter_loop` lint is using only works for array sizes <= 32.
There is this comment:
> IntoIterator is currently only implemented for array sizes <= 32 in rustc

I'm a bit confused, because I read that [IntoIterator for arrays](https://doc.rust-lang.org/src/core/array/mod.rs.html#194-201) with const generic `N` is stable since = "1.0.0". Although Const Generics MVP were stabilized in Rust 1.51.

Should I set MSRV for the current change? I will try to test with older compilers soon.

31 files changed:
clippy_lints/src/casts/ptr_as_ptr.rs
clippy_lints/src/checked_conversions.rs
clippy_lints/src/from_over_into.rs
clippy_lints/src/if_then_some_else_none.rs
clippy_lints/src/lib.rs
clippy_lints/src/manual_non_exhaustive.rs
clippy_lints/src/manual_strip.rs
clippy_lints/src/manual_unwrap_or.rs
clippy_lints/src/matches.rs
clippy_lints/src/mem_replace.rs
clippy_lints/src/methods/cloned_instead_of_copied.rs
clippy_lints/src/methods/filter_map_next.rs
clippy_lints/src/methods/map_unwrap_or.rs
clippy_lints/src/methods/option_as_ref_deref.rs
clippy_lints/src/missing_const_for_fn.rs
clippy_lints/src/needless_question_mark.rs
clippy_lints/src/ranges.rs
clippy_lints/src/redundant_field_names.rs
clippy_lints/src/redundant_static_lifetimes.rs
clippy_lints/src/unnested_or_patterns.rs
clippy_lints/src/use_self.rs
clippy_lints/src/utils/conf.rs
clippy_utils/src/lib.rs
clippy_utils/src/msrvs.rs [new file with mode: 0644]
doc/adding_lints.md
tests/ui/manual_unwrap_or.fixed
tests/ui/manual_unwrap_or.rs
tests/ui/manual_unwrap_or.stderr
tests/ui/needless_question_mark.fixed
tests/ui/needless_question_mark.rs
tests/ui/needless_question_mark.stderr

index 9113e5a0920a250b57c849c6e13b9fac06c45114..3132d3a5cf0976d7dece539347c09c9f61832871 100644 (file)
@@ -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};
 
 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<RustcVersion>) {
-    if !meets_msrv(msrv.as_ref(), &PTR_AS_PTR_MSRV) {
+    if !meets_msrv(msrv.as_ref(), &msrvs::POINTER_CAST) {
         return;
     }
 
index 6a2666bc6c0111026890f8ef361af6cb1fa0682d..8d3123e1ec8eefa00ee7e5a4b4ba65fd82314066 100644 (file)
@@ -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_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 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 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;
         }
 
index 5e2baba8943498d5e321f94ae8c424c66a0d3e35..3560672a7481208b238a5cc8d96925f6ae267515 100644 (file)
@@ -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 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 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;
         }
 
index 85c95f1151f84b53db10ffdacc68cc98cdd92783..eadcd0867a8809c841f167dfcf7c397bf1d3d6e4 100644 (file)
@@ -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_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 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 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;
         }
 
index 2ff633bcda5f002debcf1960a61c910d9b2492a6..c84890299df09aaf38bf2237244b0f211c3154eb 100644 (file)
@@ -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));
 
index dc19805b50abdbec8ae3e04ca9b5f1426c6b4505..54f714b54b657f6f6e2f25040d2e2e3afd4f1b4d 100644 (file)
@@ -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_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 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 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;
         }
 
index dfa464ddb81ac4e1043cb17907b998092af7a5d5..23428524dee976f8a9994ba50fd4cdbe335023f0 100644 (file)
@@ -2,7 +2,7 @@
 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_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;
         }
 
index 65baa2552ccc6b7758b9ce9c7570beb914539368..520162559e50f74690bcaa67c2f93135dea73f7f 100644 (file)
@@ -112,6 +112,15 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'
         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 applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'
                 "replace with",
                 format!(
                     "{}.unwrap_or({})",
-                    sugg::Sugg::hir(cx, scrutinee, "..").maybe_par(),
+                    suggestion,
                     reindented_or_body,
                 ),
                 Applicability::MachineApplicable,
index 44b4eb2903531db3381b9ddb133dc9b08430e754..13b2a834b0a962ac4db369573dab48ddfc9bda16 100644 (file)
@@ -7,8 +7,9 @@
 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 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
     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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
         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);
             }
index ec60bffe95555fe0e256c47383519aa76b91f32f..183daee36177489843452fb7ce3350a2a6c742ff 100644 (file)
@@ -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<RustcVersion>,
 }
@@ -281,7 +279,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             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);
                 }
             }
index 9c1b6f55c88404e6e193dffc6620c6e5d6dbf450..ecec6da3aa0f62e6ad3be7317edb5bca59114f46 100644 (file)
@@ -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;
 
 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>` -> `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) {
                 // <T as Iterator>::Item
                 Some(ty) => ty,
index 2b19e4ee8c055b16c9b962465dbc43769ebbce98..f0d69a1f42e7b911a6c39e34ce4cb1091eeedb95 100644 (file)
@@ -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 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;
         }
 
index 4330fea727b3aad373ace7e667c9d61f568b9e10..4d8365fcda12681f72a45fd48e961c2e54ab8b23 100644 (file)
@@ -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 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.
index 7e9c8fa829decd77f9feb3ce6b1b5fe66ae30955..5a57135038fdc8beac4206c401c6e8167f176c3c 100644 (file)
@@ -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 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;
     }
 
index 93b7a897405aee42b368639e58ee6cca2a4bba11..27b5a07c1bc24ca5b85f1ebf8a72585f151922bb 100644 (file)
@@ -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_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 @@ fn check_fn(
         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;
         }
 
index cfe7ae6630e0472257e9284dcf0b3139aad5c980..7b156a8c49dd9d93aec449e7898ce3acb7c09dba 100644 (file)
@@ -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! {
     "Suggest `value.inner_option` instead of `Some(value.inner_option?)`. The same goes for `Result<T, E>`."
 }
 
-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<RustcVersion>,
-}
-
-impl NeedlessQuestionMark {
-    #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> 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 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
             _ => 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 @@ fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
 
         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<SomeOkCall<'a>> {
+fn is_some_or_ok_call<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<SomeOkCall<'a>> {
     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));
             }
         }
index 1c3c125e579132a7ef28745d57e65dcb81fb1034..7169f96eaf1f3c9160b3e87a5188bfdde3040bec 100644 (file)
@@ -2,7 +2,7 @@
 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;
     "manually reimplementing {`Range`, `RangeInclusive`}`::contains`"
 }
 
-const MANUAL_RANGE_CONTAINS_MSRV: RustcVersion = RustcVersion::new(1, 35, 0);
-
 pub struct Ranges {
     msrv: Option<RustcVersion>,
 }
@@ -187,7 +185,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 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);
                 }
             },
index abebd4227975ef3425c2edb2ffefc5ebc7613761..d5ee8d3468deb84aca1ad7017d66765a1d181b15 100644 (file)
@@ -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_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 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 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;
         }
 
index 32b57698ec54dc6481c0daa7468ec3b919860d25..48107d9c037db3abdae9caa08930c1cbbb2d9321 100644 (file)
@@ -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 @@ fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
 
 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;
         }
 
index 9376a2cf66a90b1bd497498906e2e7111ccf2671..3e985fa72b8fe77583ed58223778bf464a2eb04c 100644 (file)
@@ -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 @@
     "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<RustcVersion>,
@@ -72,13 +67,13 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 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 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
     }
 
     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);
         }
     }
index c6a3c58a9a2a45c391f7191e93c1287e55779965..aa4d16633ff80f3937f576017e3ad2d3ec689a19 100644 (file)
@@ -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<StackItem>,
 }
 
-const USE_SELF_MSRV: RustcVersion = RustcVersion::new(1, 37, 0);
-
 impl UseSelf {
     #[must_use]
     pub fn new(msrv: Option<RustcVersion>) -> Self {
@@ -236,7 +234,10 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) {
     }
 
     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 @@ fn expr_ty_matches(cx: &LateContext<'_>, expr: &Expr<'_>, self_ty: Ty<'_>) -> bo
             }
         }
 
-        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;
         }
 
index 2f8714b17997831cc4365932227e53c490b8b28d..d56855a71c159b2e1cdc351d7708e9f8371b3e46 100644 (file)
@@ -106,7 +106,7 @@ fn $config() -> $Ty {
 
 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<String>, 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<String>, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
index b7017411927daa5cf81f257296769f979f9e4fcc..9b60c92bca1bea53bcbc29d78763b0920bd1992b 100644 (file)
@@ -38,6 +38,7 @@
 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 (file)
index 0000000..00df04c
--- /dev/null
@@ -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 }
+}
index 50f0d724016ff1b33039de9ae471d68b04fc0ced..d6cc6d0c2c76394842dd80d085e811bf96b78725 100644 (file)
@@ -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;
 }
 ```
index f1d3252230bc2b7a23c57fa0037c7daa05df0040..e7a29596b73ac50f8fdb1723c089e9425dbdf3bb 100644 (file)
@@ -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() {}
index c9eee25a5b1538d96a38e36d8922f44ea1bae6ff..66006b6c616f08f9e1858e53ef451b57b26c130f 100644 (file)
@@ -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() {}
index fc174c4c2705dc3c6d7ea4b6df6b889b7b881c8c..99625b789b6a4d7d0728ca89eb19dd98e8d73125 100644 (file)
@@ -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
 
index fd8433870bb1b8e6bd07e4e45e4ef06b48d6f14f..52ddd9d2dc8266ac128e0c9bcc17f9d7394ecd21 100644 (file)
@@ -96,78 +96,6 @@ where
 
 fn main() {}
 
-mod question_mark_none {
-    #![clippy::msrv = "1.12.0"]
-    fn needless_question_mark_option() -> Option<usize> {
-        struct TO {
-            magic: Option<usize>,
-        }
-        let to = TO { magic: None };
-        Some(to.magic?) // should not be triggered
-    }
-
-    fn needless_question_mark_result() -> Result<usize, bool> {
-        struct TO {
-            magic: Result<usize, bool>,
-        }
-        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<usize> {
-        struct TO {
-            magic: Option<usize>,
-        }
-        let to = TO { magic: None };
-        Some(to.magic?) // should not be triggered
-    }
-
-    fn needless_question_mark_result() -> Result<usize, bool> {
-        struct TO {
-            magic: Result<usize, bool>,
-        }
-        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<usize> {
-        struct TO {
-            magic: Option<usize>,
-        }
-        let to = TO { magic: None };
-        to.magic // should be triggered
-    }
-
-    fn needless_question_mark_result() -> Result<usize, bool> {
-        struct TO {
-            magic: Result<usize, bool>,
-        }
-        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 {
index 36d45ac7e03e29789c7a43cde1150c57ce2a928e..1ea4ba0d83fd76da23c3ac13bb4dcb3caf9cc801 100644 (file)
@@ -96,78 +96,6 @@ fn false_positive_test<U, T>(x: Result<(), U>) -> Result<(), T>
 
 fn main() {}
 
-mod question_mark_none {
-    #![clippy::msrv = "1.12.0"]
-    fn needless_question_mark_option() -> Option<usize> {
-        struct TO {
-            magic: Option<usize>,
-        }
-        let to = TO { magic: None };
-        Some(to.magic?) // should not be triggered
-    }
-
-    fn needless_question_mark_result() -> Result<usize, bool> {
-        struct TO {
-            magic: Result<usize, bool>,
-        }
-        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<usize> {
-        struct TO {
-            magic: Option<usize>,
-        }
-        let to = TO { magic: None };
-        Some(to.magic?) // should not be triggered
-    }
-
-    fn needless_question_mark_result() -> Result<usize, bool> {
-        struct TO {
-            magic: Result<usize, bool>,
-        }
-        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<usize> {
-        struct TO {
-            magic: Option<usize>,
-        }
-        let to = TO { magic: None };
-        Some(to.magic?) // should be triggered
-    }
-
-    fn needless_question_mark_result() -> Result<usize, bool> {
-        struct TO {
-            magic: Result<usize, bool>,
-        }
-        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 {
index 7cbf1e505adf63dff27f884fb4315c971bb1a1a3..afd68d91e51fe54c022487f30388a72ea434511e 100644 (file)
@@ -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