]> git.lizzy.rs Git - rust.git/commitdiff
add MSRV to more lints specified in #6097
authorsuyash458 <suyash.behera458@gmail.com>
Sat, 5 Dec 2020 12:59:22 +0000 (04:59 -0800)
committerSuyash458 <suyash.behera458@gmail.com>
Fri, 11 Dec 2020 05:30:03 +0000 (11:00 +0530)
update tests

clippy_lints/src/checked_conversions.rs
clippy_lints/src/lib.rs
clippy_lints/src/mem_replace.rs
clippy_lints/src/methods/mod.rs
clippy_lints/src/missing_const_for_fn.rs
clippy_lints/src/ranges.rs
clippy_lints/src/redundant_field_names.rs
clippy_lints/src/redundant_static_lifetimes.rs
clippy_lints/src/use_self.rs
tests/ui/min_rust_version_attr.rs
tests/ui/min_rust_version_attr.stderr

index 28c1a54d2c5a6a1c1ecc2749737c668b5da8f182..54bc69e058bc79460966385bec88e8cfce71f6bb 100644 (file)
@@ -6,9 +6,12 @@
 use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 
-use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq};
+use crate::utils::{meets_msrv, snippet_with_applicability, span_lint_and_sugg, SpanlessEq};
+
+const CHECKED_CONVERSIONS_MSRV: RustcVersion = RustcVersion::new(1, 34, 0);
 
 declare_clippy_lint! {
     /// **What it does:** Checks for explicit bounds checking when casting.
     "`try_from` could replace manual bounds checking when casting"
 }
 
-declare_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);
+pub struct CheckedConversions {
+    msrv: Option<RustcVersion>,
+}
+
+impl CheckedConversions {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
+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) {
+            return;
+        }
+
         let result = if_chain! {
             if !in_external_macro(cx.sess(), item.span);
             if let ExprKind::Binary(op, ref left, ref right) = &item.kind;
@@ -74,6 +92,8 @@ fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
             }
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 /// Searches for a single check from unsigned to _ is done
index a92ae9ed8d93545259366a3dc9c82566711b91ec..38a25d22aa26a0b186b20c0eb8a6ca0078df0fc4 100644 (file)
@@ -1003,6 +1003,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || box matches::Matches::new(msrv));
     store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv));
     store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv));
+    store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv));
+    store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv));
+    store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv));
+    store.register_late_pass(move || box mem_replace::MemReplace::new(msrv));
+    store.register_late_pass(move || box ranges::Ranges::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(|| box size_of_in_element_count::SizeOfInElementCount);
     store.register_late_pass(|| box map_clone::MapClone);
     store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
@@ -1013,7 +1021,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box main_recursion::MainRecursion::default());
     store.register_late_pass(|| box lifetimes::Lifetimes);
     store.register_late_pass(|| box entry::HashMapPass);
-    store.register_late_pass(|| box ranges::Ranges);
     store.register_late_pass(|| box types::Casts);
     let type_complexity_threshold = conf.type_complexity_threshold;
     store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold));
@@ -1058,7 +1065,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box neg_multiply::NegMultiply);
     store.register_late_pass(|| box mem_discriminant::MemDiscriminant);
     store.register_late_pass(|| box mem_forget::MemForget);
-    store.register_late_pass(|| box mem_replace::MemReplace);
     store.register_late_pass(|| box arithmetic::Arithmetic::default());
     store.register_late_pass(|| box assign_ops::AssignOps);
     store.register_late_pass(|| box let_if_seq::LetIfSeq);
@@ -1080,7 +1086,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || box pass_by_ref_or_value);
     store.register_late_pass(|| box ref_option_ref::RefOptionRef);
     store.register_late_pass(|| box try_err::TryErr);
-    store.register_late_pass(|| box use_self::UseSelf);
     store.register_late_pass(|| box bytecount::ByteCount);
     store.register_late_pass(|| box infinite_iter::InfiniteIter);
     store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
@@ -1106,10 +1111,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps);
     store.register_late_pass(|| box types::RefToMut);
     store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
-    store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn);
     store.register_late_pass(|| box transmuting_null::TransmutingNull);
     store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite);
-    store.register_late_pass(|| box checked_conversions::CheckedConversions);
     store.register_late_pass(|| box integer_division::IntegerDivision);
     store.register_late_pass(|| box inherent_to_string::InherentToString);
     let max_trait_bounds = conf.max_trait_bounds;
@@ -1138,7 +1141,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| box redundant_else::RedundantElse);
     store.register_late_pass(|| box create_dir::CreateDir);
     store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
-    store.register_early_pass(|| box redundant_static_lifetimes::RedundantStaticLifetimes);
     store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata);
     store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
     store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies);
@@ -1178,7 +1180,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
     store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
     store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
-    store.register_early_pass(|| box redundant_field_names::RedundantFieldNames);
     store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
     store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn);
     let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
index bb0acecc5a92d1a7a5d8fefdfad4ada9372ef443..19087b02077142fb84d86a62c87beffa7ac844d7 100644 (file)
@@ -1,13 +1,14 @@
 use crate::utils::{
-    in_macro, match_def_path, match_qpath, paths, snippet, snippet_with_applicability, span_lint_and_help,
+    in_macro, match_def_path, match_qpath, meets_msrv, paths, snippet, snippet_with_applicability, span_lint_and_help,
     span_lint_and_sugg, span_lint_and_then,
 };
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::sym;
 
@@ -94,7 +95,7 @@
     "replacing a value of type `T` with `T::default()` instead of using `std::mem::take`"
 }
 
-declare_lint_pass!(MemReplace =>
+impl_lint_pass!(MemReplace =>
     [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]);
 
 fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) {
@@ -224,6 +225,19 @@ 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>,
+}
+
+impl MemReplace {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for MemReplace {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
@@ -236,8 +250,11 @@ 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);
-                check_replace_with_default(cx, src, dest, expr.span);
+                if meets_msrv(self.msrv.as_ref(), &MEM_REPLACE_WITH_DEFAULT_MSRV) {
+                    check_replace_with_default(cx, src, dest, expr.span);
+                }
             }
         }
     }
+    extract_msrv_attr!(LateContext);
 }
index 8002c27a5e91b7e27b92818a5b51f47275832761..5133f31e0e7bf10dbb553247cdf1f3ecbd7854b2 100644 (file)
@@ -1487,7 +1487,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
             ["expect", ..] => lint_expect(cx, expr, arg_lists[0]),
             ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]),
             ["unwrap_or_else", "map"] => {
-                if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) {
+                if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0], self.msrv.as_ref()) {
                     unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or");
                 }
             },
@@ -1509,7 +1509,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
             ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]),
             ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]),
             ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]),
-            ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1]),
+            ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1], self.msrv.as_ref()),
             ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]),
             ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
             ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
@@ -2733,6 +2733,8 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
     }
 }
 
+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
 fn lint_map_unwrap_or_else<'tcx>(
@@ -2740,7 +2742,11 @@ fn lint_map_unwrap_or_else<'tcx>(
     expr: &'tcx hir::Expr<'_>,
     map_args: &'tcx [hir::Expr<'_>],
     unwrap_args: &'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(&map_args[0]), sym::option_type);
     let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::result_type);
@@ -2923,9 +2929,20 @@ fn lint_filter_map<'tcx>(
     }
 }
 
+const FILTER_MAP_NEXT_MSRV: RustcVersion = RustcVersion::new(1, 30, 0);
+
 /// lint use of `filter_map().next()` for `Iterators`
-fn lint_filter_map_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) {
+fn lint_filter_map_next<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'_>,
+    filter_args: &'tcx [hir::Expr<'_>],
+    msrv: Option<&RustcVersion>,
+) {
     if match_trait_method(cx, expr, &paths::ITERATOR) {
+        if !meets_msrv(msrv, &FILTER_MAP_NEXT_MSRV) {
+            return;
+        }
+
         let msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
                    `.find_map(..)` instead.";
         let filter_snippet = snippet(cx, filter_args[1].span, "..");
index 38e2ce563eeb2951feda3de9b0ae55633230111c..6ebeaced62a335fcb806115cf1a1ec9c9ae291bd 100644 (file)
@@ -1,14 +1,19 @@
 use crate::utils::qualify_min_const_fn::is_min_const_fn;
-use crate::utils::{fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method};
+use crate::utils::{
+    fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, meets_msrv, span_lint, trait_ref_of_method,
+};
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_semver::RustcVersion;
+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:**
     ///
     "Lint functions definitions that could be made `const fn`"
 }
 
-declare_lint_pass!(MissingConstForFn => [MISSING_CONST_FOR_FN]);
+impl_lint_pass!(MissingConstForFn => [MISSING_CONST_FOR_FN]);
+
+pub struct MissingConstForFn {
+    msrv: Option<RustcVersion>,
+}
+
+impl MissingConstForFn {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
     fn check_fn(
@@ -81,6 +97,10 @@ fn check_fn(
         span: Span,
         hir_id: HirId,
     ) {
+        if !meets_msrv(self.msrv.as_ref(), &MISSING_CONST_FOR_FN_MSRV) {
+            return;
+        }
+
         let def_id = cx.tcx.hir().local_def_id(hir_id);
 
         if in_external_macro(cx.tcx.sess, span) || is_entrypoint_fn(cx, def_id.to_def_id()) {
@@ -126,6 +146,7 @@ fn check_fn(
             span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`");
         }
     }
+    extract_msrv_attr!(LateContext);
 }
 
 /// Returns true if any of the method parameters is a type that implements `Drop`. The method
index 4b514bbd42ca7d0df4c0b5ebb5853974dec1f31a..f9173808089cc0d67b4df97b5803503c5becdc83 100644 (file)
@@ -3,9 +3,10 @@
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, QPath};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::{Span, Spanned};
 use rustc_span::sym;
 use rustc_span::symbol::Ident;
@@ -13,8 +14,8 @@
 
 use crate::utils::sugg::Sugg;
 use crate::utils::{
-    get_parent_expr, is_integer_const, single_segment_path, snippet, snippet_opt, snippet_with_applicability,
-    span_lint, span_lint_and_sugg, span_lint_and_then,
+    get_parent_expr, is_integer_const, meets_msrv, single_segment_path, snippet, snippet_opt,
+    snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then,
 };
 use crate::utils::{higher, SpanlessEq};
 
     "manually reimplementing {`Range`, `RangeInclusive`}`::contains`"
 }
 
-declare_lint_pass!(Ranges => [
+const MANUAL_RANGE_CONTAINS_MSRV: RustcVersion = RustcVersion::new(1, 35, 0);
+
+pub struct Ranges {
+    msrv: Option<RustcVersion>,
+}
+
+impl Ranges {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(Ranges => [
     RANGE_ZIP_WITH_LEN,
     RANGE_PLUS_ONE,
     RANGE_MINUS_ONE,
@@ -175,7 +189,9 @@ 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, ref l, ref r) => {
-                check_possible_range_contains(cx, op.node, l, r, expr.span);
+                if meets_msrv(self.msrv.as_ref(), &MANUAL_RANGE_CONTAINS_MSRV) {
+                    check_possible_range_contains(cx, op.node, l, r, expr.span);
+                }
             },
             _ => {},
         }
@@ -184,6 +200,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         check_inclusive_range_minus_one(cx, expr);
         check_reversed_empty_range(cx, expr);
     }
+    extract_msrv_attr!(LateContext);
 }
 
 fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'_>, r: &Expr<'_>, span: Span) {
index 2a81170e49e75026ce6c328adbb7eaa144ac30e6..38dcf7a192c823beadf6e5a07e43f3c013eac754 100644 (file)
@@ -1,9 +1,12 @@
-use crate::utils::span_lint_and_sugg;
+use crate::utils::{meets_msrv, span_lint_and_sugg};
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+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
     "checks for fields in struct literals where shorthands could be used"
 }
 
-declare_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]);
+pub struct RedundantFieldNames {
+    msrv: Option<RustcVersion>,
+}
+
+impl RedundantFieldNames {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
+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) {
+            return;
+        }
+
         if in_external_macro(cx.sess, expr.span) {
             return;
         }
@@ -64,4 +82,5 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
             }
         }
     }
+    extract_msrv_attr!(EarlyContext);
 }
index 7bbcc67aa2ddf13db6eb565df72047355c2f1666..fcfa3c12755af37e0979aac06021a48ee8473d99 100644 (file)
@@ -1,8 +1,11 @@
-use crate::utils::{snippet, span_lint_and_then};
+use crate::utils::{meets_msrv, snippet, span_lint_and_then};
 use rustc_ast::ast::{Item, ItemKind, Ty, TyKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+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.
     "Using explicit `'static` lifetime for constants or statics when elision rules would allow omitting them."
 }
 
-declare_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]);
+pub struct RedundantStaticLifetimes {
+    msrv: Option<RustcVersion>,
+}
+
+impl RedundantStaticLifetimes {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]);
 
 impl RedundantStaticLifetimes {
     // Recursively visit types
@@ -84,6 +98,10 @@ 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) {
+            return;
+        }
+
         if !item.span.from_expansion() {
             if let ItemKind::Const(_, ref var_type, _) = item.kind {
                 self.visit_type(var_type, cx, "constants have by default a `'static` lifetime");
@@ -96,4 +114,6 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
             }
         }
     }
+
+    extract_msrv_attr!(EarlyContext);
 }
index 5ac4797680bc167a38890abc5eeacdfeed9738aa..3b23f885e08d9584d9434efd03aa31c93ef7b345 100644 (file)
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_middle::ty::{DefIdTree, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::kw;
 use rustc_typeck::hir_ty_to_ty;
 
-use crate::utils::{differing_macro_contexts, span_lint_and_sugg};
+use crate::utils::{differing_macro_contexts, meets_msrv, span_lint_and_sugg};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for unnecessary repetition of structure name when a
@@ -53,7 +54,7 @@
     "unnecessary structure name repetition whereas `Self` is applicable"
 }
 
-declare_lint_pass!(UseSelf => [USE_SELF]);
+impl_lint_pass!(UseSelf => [USE_SELF]);
 
 const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";
 
@@ -157,8 +158,25 @@ fn check_trait_method_impl_decl<'tcx>(
     }
 }
 
+const USE_SELF_MSRV: RustcVersion = RustcVersion::new(1, 37, 0);
+
+pub struct UseSelf {
+    msrv: Option<RustcVersion>,
+}
+
+impl UseSelf {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for UseSelf {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        if !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) {
+            return;
+        }
+
         if in_external_macro(cx.sess(), item.span) {
             return;
         }
@@ -204,6 +222,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             }
         }
     }
+    extract_msrv_attr!(LateContext);
 }
 
 struct UseSelfVisitor<'a, 'tcx> {
index 1026cc40d3b0e20ce6824f1735472e02fbf8a1ca..ac75f5e46c3fdd703f05b3414c6b66a0016c5d56 100644 (file)
@@ -2,7 +2,7 @@
 #![feature(custom_inner_attributes)]
 #![clippy::msrv = "1.0.0"]
 
-use std::ops::Deref;
+use std::ops::{Deref, RangeFrom};
 
 fn option_as_ref_deref() {
     let mut opt = Some(String::from("123"));
@@ -42,12 +42,84 @@ pub fn manual_strip_msrv() {
     }
 }
 
+pub fn redundant_fieldnames() {
+    let start = 0;
+    let _ = RangeFrom { start: start };
+}
+
+pub fn redundant_static_lifetime() {
+    const VAR_ONE: &'static str = "Test constant #1";
+}
+
+pub fn checked_conversion() {
+    let value: i64 = 42;
+    let _ = value <= (u32::max_value() as i64) && value >= 0;
+    let _ = value <= (u32::MAX as i64) && value >= 0;
+}
+
+pub fn filter_map_next() {
+    let a = ["1", "lol", "3", "NaN", "5"];
+
+    #[rustfmt::skip]
+    let _: Option<u32> = vec![1, 2, 3, 4, 5, 6]
+        .into_iter()
+        .filter_map(|x| {
+            if x == 2 {
+                Some(x * 2)
+            } else {
+                None
+            }
+        })
+        .next();
+}
+
+pub fn manual_range_contains() {
+    x >= 8 && x < 12;
+}
+
+pub fn use_self() {
+    struct Foo {}
+
+    impl Foo {
+        fn new() -> Foo {
+            Foo {}
+        }
+        fn test() -> Foo {
+            Foo::new()
+        }
+    }
+}
+
+fn replace_with_default() {
+    let mut s = String::from("foo");
+    let _ = std::mem::replace(s, String::default());
+}
+
+fn map_unwrap_or() {
+    let opt = Some(1);
+
+    // Check for `option.map(_).unwrap_or(_)` use.
+    // Single line case.
+    let _ = opt
+        .map(|x| x + 1)
+        // Should lint even though this call is on a separate line.
+        .unwrap_or(0);
+}
+
 fn main() {
+    filter_map_next();
+    checked_conversion();
+    redundant_fieldnames();
+    redundant_static_lifetime();
     option_as_ref_deref();
     match_like_matches();
     match_same_arms();
     match_same_arms2();
     manual_strip_msrv();
+    manual_range_contains();
+    use_self();
+    replace_with_default();
+    map_unwrap_or();
 }
 
 mod meets_msrv {
index 3e1af046e7a2795127d85fdd27bcaf4f16c5e7f8..d3eafe7312f475f80026c3bf956740d085f149a8 100644 (file)
@@ -1,37 +1,28 @@
-error: stripping a prefix manually
-  --> $DIR/min_rust_version_attr.rs:60: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:59:9
-   |
-LL |         if s.starts_with("hello, ") {
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: try using the `strip_prefix` method
-   |
-LL |         if let Some(<stripped>) = s.strip_prefix("hello, ") {
-LL |             assert_eq!(<stripped>.to_uppercase(), "WORLD!");
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/min_rust_version_attr.rs:77:5
    |
+LL |     x >= 8 && x < 12;
+   |     ^ not found in this scope
 
-error: stripping a prefix manually
-  --> $DIR/min_rust_version_attr.rs:72:24
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/min_rust_version_attr.rs:77:15
    |
-LL |             assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
-   |                        ^^^^^^^^^^^^^^^^^^^^
-   |
-note: the prefix was tested here
-  --> $DIR/min_rust_version_attr.rs:71:9
-   |
-LL |         if s.starts_with("hello, ") {
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: try using the `strip_prefix` method
+LL |     x >= 8 && x < 12;
+   |               ^ not found in this scope
+
+error[E0308]: mismatched types
+  --> $DIR/min_rust_version_attr.rs:95:31
    |
-LL |         if let Some(<stripped>) = s.strip_prefix("hello, ") {
-LL |             assert_eq!(<stripped>.to_uppercase(), "WORLD!");
+LL |     let _ = std::mem::replace(s, String::default());
+   |                               ^
+   |                               |
+   |                               expected `&mut _`, found struct `std::string::String`
+   |                               help: consider mutably borrowing here: `&mut s`
    |
+   = note: expected mutable reference `&mut _`
+                         found struct `std::string::String`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
+Some errors have detailed explanations: E0308, E0425.
+For more information about an error, try `rustc --explain E0308`.