1
Fork 0

Add clippy_utils::msrv::Msrv to keep track of the current MSRV

This commit is contained in:
Alex Macleod 2022-11-21 14:37:51 +00:00
parent 51ec465cc3
commit 637139d2ff
56 changed files with 466 additions and 433 deletions

View file

@ -443,22 +443,22 @@ value is passed to the constructor in `clippy_lints/lib.rs`.
```rust ```rust
pub struct ManualStrip { pub struct ManualStrip {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl ManualStrip { impl ManualStrip {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
``` ```
The project's MSRV can then be matched against the feature 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. using the `Msrv::meets` method.
``` rust ``` rust
if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) { if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) {
return; return;
} }
``` ```

View file

@ -120,7 +120,7 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
let new_lint = if enable_msrv { let new_lint = if enable_msrv {
format!( format!(
"store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv)));\n ", "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv())));\n ",
lint_pass = lint.pass, lint_pass = lint.pass,
ctor_arg = if lint.pass == "late" { "_" } else { "" }, ctor_arg = if lint.pass == "late" { "_" } else { "" },
module_name = lint.name, module_name = lint.name,
@ -238,10 +238,9 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
result.push_str(&if enable_msrv { result.push_str(&if enable_msrv {
formatdoc!( formatdoc!(
r#" r#"
use clippy_utils::msrvs; use clippy_utils::msrvs::{{self, Msrv}};
{pass_import} {pass_import}
use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
use rustc_semver::RustcVersion;
use rustc_session::{{declare_tool_lint, impl_lint_pass}}; use rustc_session::{{declare_tool_lint, impl_lint_pass}};
"# "#
@ -263,12 +262,12 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
formatdoc!( formatdoc!(
r#" r#"
pub struct {name_camel} {{ pub struct {name_camel} {{
msrv: Option<RustcVersion>, msrv: Msrv,
}} }}
impl {name_camel} {{ impl {name_camel} {{
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self {{ pub fn new(msrv: Msrv) -> Self {{
Self {{ msrv }} Self {{ msrv }}
}} }}
}} }}
@ -357,15 +356,14 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
let _ = writedoc!( let _ = writedoc!(
lint_file_contents, lint_file_contents,
r#" r#"
use clippy_utils::{{meets_msrv, msrvs}}; use clippy_utils::msrvs::{{self, Msrv}};
use rustc_lint::{{{context_import}, LintContext}}; use rustc_lint::{{{context_import}, LintContext}};
use rustc_semver::RustcVersion;
use super::{name_upper}; use super::{name_upper};
// TODO: Adjust the parameters as necessary // TODO: Adjust the parameters as necessary
pub(super) fn check(cx: &{context_import}, msrv: Option<RustcVersion>) {{ pub(super) fn check(cx: &{context_import}, msrv: &Msrv) {{
if !meets_msrv(msrv, todo!("Add a new entry in `clippy_utils/src/msrvs`")) {{ if !msrv.meets(todo!("Add a new entry in `clippy_utils/src/msrvs`")) {{
return; return;
}} }}
todo!(); todo!();

View file

@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{trim_span, walk_span_to_context}; use clippy_utils::source::{trim_span, walk_span_to_context};
use clippy_utils::{meets_msrv, msrvs};
use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span; use rustc_span::Span;
@ -33,10 +32,10 @@ declare_clippy_lint! {
impl_lint_pass!(AlmostCompleteLetterRange => [ALMOST_COMPLETE_LETTER_RANGE]); impl_lint_pass!(AlmostCompleteLetterRange => [ALMOST_COMPLETE_LETTER_RANGE]);
pub struct AlmostCompleteLetterRange { pub struct AlmostCompleteLetterRange {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl AlmostCompleteLetterRange { impl AlmostCompleteLetterRange {
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -46,7 +45,7 @@ impl EarlyLintPass for AlmostCompleteLetterRange {
let ctxt = e.span.ctxt(); let ctxt = e.span.ctxt();
let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt) let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt)
&& let Some(end) = walk_span_to_context(end.span, ctxt) && let Some(end) = walk_span_to_context(end.span, ctxt)
&& meets_msrv(self.msrv, msrvs::RANGE_INCLUSIVE) && self.msrv.meets(msrvs::RANGE_INCLUSIVE)
{ {
Some((trim_span(cx.sess().source_map(), start.between(end)), "..=")) Some((trim_span(cx.sess().source_map(), start.between(end)), "..="))
} else { } else {
@ -60,7 +59,7 @@ impl EarlyLintPass for AlmostCompleteLetterRange {
if let PatKind::Range(Some(start), Some(end), kind) = &p.kind if let PatKind::Range(Some(start), Some(end), kind) = &p.kind
&& matches!(kind.node, RangeEnd::Excluded) && matches!(kind.node, RangeEnd::Excluded)
{ {
let sugg = if meets_msrv(self.msrv, msrvs::RANGE_INCLUSIVE) { let sugg = if self.msrv.meets(msrvs::RANGE_INCLUSIVE) {
"..=" "..="
} else { } else {
"..." "..."

View file

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{meets_msrv, msrvs}; use clippy_utils::msrvs::{self, Msrv};
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
@ -63,12 +63,12 @@ const KNOWN_CONSTS: [(f64, &str, usize, Option<RustcVersion>); 19] = [
]; ];
pub struct ApproxConstant { pub struct ApproxConstant {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl ApproxConstant { impl ApproxConstant {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
@ -87,7 +87,7 @@ impl ApproxConstant {
let s = s.as_str(); let s = s.as_str();
if s.parse::<f64>().is_ok() { if s.parse::<f64>().is_ok() {
for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS { for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| meets_msrv(self.msrv, msrv)) { if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| self.msrv.meets(msrv)) {
span_lint_and_help( span_lint_and_help(
cx, cx,
APPROX_CONSTANT, APPROX_CONSTANT,

View file

@ -2,9 +2,8 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::macros::{is_panic, macro_backtrace}; use clippy_utils::macros::{is_panic, macro_backtrace};
use clippy_utils::msrvs; use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
use clippy_utils::{extract_msrv_attr, meets_msrv};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -14,7 +13,6 @@ use rustc_hir::{
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_semver::RustcVersion;
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
@ -599,7 +597,7 @@ fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool {
} }
pub struct EarlyAttributes { pub struct EarlyAttributes {
pub msrv: Option<RustcVersion>, pub msrv: Msrv,
} }
impl_lint_pass!(EarlyAttributes => [ impl_lint_pass!(EarlyAttributes => [
@ -614,7 +612,7 @@ impl EarlyLintPass for EarlyAttributes {
} }
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
check_deprecated_cfg_attr(cx, attr, self.msrv); check_deprecated_cfg_attr(cx, attr, &self.msrv);
check_mismatched_target_os(cx, attr); check_mismatched_target_os(cx, attr);
} }
@ -654,9 +652,9 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It
} }
} }
fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Option<RustcVersion>) { fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msrv) {
if_chain! { if_chain! {
if meets_msrv(msrv, msrvs::TOOL_ATTRIBUTES); if msrv.meets(msrvs::TOOL_ATTRIBUTES);
// check cfg_attr // check cfg_attr
if attr.has_name(sym::cfg_attr); if attr.has_name(sym::cfg_attr);
if let Some(items) = attr.meta_item_list(); if let Some(items) = attr.meta_item_list();

View file

@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::{meets_msrv, msrvs};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_semver::RustcVersion;
use super::CAST_ABS_TO_UNSIGNED; use super::CAST_ABS_TO_UNSIGNED;
@ -15,9 +14,9 @@ pub(super) fn check(
cast_expr: &Expr<'_>, cast_expr: &Expr<'_>,
cast_from: Ty<'_>, cast_from: Ty<'_>,
cast_to: Ty<'_>, cast_to: Ty<'_>,
msrv: Option<RustcVersion>, msrv: &Msrv,
) { ) {
if meets_msrv(msrv, msrvs::UNSIGNED_ABS) if msrv.meets(msrvs::UNSIGNED_ABS)
&& let ty::Int(from) = cast_from.kind() && let ty::Int(from) = cast_from.kind()
&& let ty::Uint(to) = cast_to.kind() && let ty::Uint(to) = cast_to.kind()
&& let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind && let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind

View file

@ -1,12 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_constant;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_isize_or_usize; use clippy_utils::ty::is_isize_or_usize;
use clippy_utils::{in_constant, meets_msrv, msrvs};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, FloatTy, Ty}; use rustc_middle::ty::{self, FloatTy, Ty};
use rustc_semver::RustcVersion;
use super::{utils, CAST_LOSSLESS}; use super::{utils, CAST_LOSSLESS};
@ -16,7 +16,7 @@ pub(super) fn check(
cast_op: &Expr<'_>, cast_op: &Expr<'_>,
cast_from: Ty<'_>, cast_from: Ty<'_>,
cast_to: Ty<'_>, cast_to: Ty<'_>,
msrv: Option<RustcVersion>, msrv: &Msrv,
) { ) {
if !should_lint(cx, expr, cast_from, cast_to, msrv) { if !should_lint(cx, expr, cast_from, cast_to, msrv) {
return; return;
@ -57,13 +57,7 @@ pub(super) fn check(
); );
} }
fn should_lint( fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool {
cx: &LateContext<'_>,
expr: &Expr<'_>,
cast_from: Ty<'_>,
cast_to: Ty<'_>,
msrv: Option<RustcVersion>,
) -> bool {
// Do not suggest using From in consts/statics until it is valid to do so (see #2267). // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
if in_constant(cx, expr.hir_id) { if in_constant(cx, expr.hir_id) {
return false; return false;
@ -89,7 +83,7 @@ fn should_lint(
}; };
!is_isize_or_usize(cast_from) && from_nbits < to_nbits !is_isize_or_usize(cast_from) && from_nbits < to_nbits
}, },
(false, true) if matches!(cast_from.kind(), ty::Bool) && meets_msrv(msrv, msrvs::FROM_BOOL) => true, (false, true) if matches!(cast_from.kind(), ty::Bool) && msrv.meets(msrvs::FROM_BOOL) => true,
(_, _) => { (_, _) => {
matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)) matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64))
}, },

View file

@ -1,16 +1,16 @@
use clippy_utils::{diagnostics::span_lint_and_then, meets_msrv, msrvs, source}; use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::{diagnostics::span_lint_and_then, source};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::Mutability; use rustc_ast::Mutability;
use rustc_hir::{Expr, ExprKind, Node}; use rustc_hir::{Expr, ExprKind, Node};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, layout::LayoutOf, Ty, TypeAndMut}; use rustc_middle::ty::{self, layout::LayoutOf, Ty, TypeAndMut};
use rustc_semver::RustcVersion;
use super::CAST_SLICE_DIFFERENT_SIZES; use super::CAST_SLICE_DIFFERENT_SIZES;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Option<RustcVersion>) { pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv) {
// suggestion is invalid if `ptr::slice_from_raw_parts` does not exist // suggestion is invalid if `ptr::slice_from_raw_parts` does not exist
if !meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS) { if !msrv.meets(msrvs::PTR_SLICE_RAW_PARTS) {
return; return;
} }

View file

@ -1,12 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{match_def_path, meets_msrv, msrvs, paths}; use clippy_utils::{match_def_path, paths};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{def_id::DefId, Expr, ExprKind}; use rustc_hir::{def_id::DefId, Expr, ExprKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_semver::RustcVersion;
use super::CAST_SLICE_FROM_RAW_PARTS; use super::CAST_SLICE_FROM_RAW_PARTS;
@ -25,15 +25,9 @@ fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option<RawPartsKind> {
} }
} }
pub(super) fn check( pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>, msrv: &Msrv) {
cx: &LateContext<'_>,
expr: &Expr<'_>,
cast_expr: &Expr<'_>,
cast_to: Ty<'_>,
msrv: Option<RustcVersion>,
) {
if_chain! { if_chain! {
if meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS); if msrv.meets(msrvs::PTR_SLICE_RAW_PARTS);
if let ty::RawPtr(ptrty) = cast_to.kind(); if let ty::RawPtr(ptrty) = cast_to.kind();
if let ty::Slice(_) = ptrty.ty.kind(); if let ty::Slice(_) = ptrty.ty.kind();
if let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind; if let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind;

View file

@ -21,11 +21,11 @@ mod ptr_as_ptr;
mod unnecessary_cast; mod unnecessary_cast;
mod utils; mod utils;
use clippy_utils::{is_hir_ty_cfg_dependant, meets_msrv, msrvs}; use clippy_utils::is_hir_ty_cfg_dependant;
use clippy_utils::msrvs::{self, Msrv};
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! { declare_clippy_lint! {
@ -648,12 +648,12 @@ declare_clippy_lint! {
} }
pub struct Casts { pub struct Casts {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl Casts { impl Casts {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -686,7 +686,7 @@ impl_lint_pass!(Casts => [
impl<'tcx> LateLintPass<'tcx> for Casts { impl<'tcx> LateLintPass<'tcx> for Casts {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !in_external_macro(cx.sess(), expr.span) { if !in_external_macro(cx.sess(), expr.span) {
ptr_as_ptr::check(cx, expr, self.msrv); ptr_as_ptr::check(cx, expr, &self.msrv);
} }
if expr.span.from_expansion() { if expr.span.from_expansion() {
@ -705,7 +705,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) { if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
return; return;
} }
cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, self.msrv); cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv);
as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to); as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to);
fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
@ -717,16 +717,16 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_possible_wrap::check(cx, expr, cast_from, cast_to);
cast_precision_loss::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to);
cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to); cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv); cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to); cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
} }
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv); cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
cast_enum_constructor::check(cx, expr, cast_expr, cast_from); cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
} }
as_underscore::check(cx, expr, cast_to_hir); as_underscore::check(cx, expr, cast_to_hir);
if meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) { if self.msrv.meets(msrvs::BORROW_AS_PTR) {
borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir); borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
} }
} }
@ -734,8 +734,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
cast_ref_to_mut::check(cx, expr); cast_ref_to_mut::check(cx, expr);
cast_ptr_alignment::check(cx, expr); cast_ptr_alignment::check(cx, expr);
char_lit_as_u8::check(cx, expr); char_lit_as_u8::check(cx, expr);
ptr_as_ptr::check(cx, expr, self.msrv); ptr_as_ptr::check(cx, expr, &self.msrv);
cast_slice_different_sizes::check(cx, expr, self.msrv); cast_slice_different_sizes::check(cx, expr, &self.msrv);
} }
extract_msrv_attr!(LateContext); extract_msrv_attr!(LateContext);

View file

@ -1,19 +1,18 @@
use std::borrow::Cow; use std::borrow::Cow;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::{meets_msrv, msrvs};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Mutability, TyKind}; use rustc_hir::{Expr, ExprKind, Mutability, TyKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, TypeAndMut}; use rustc_middle::ty::{self, TypeAndMut};
use rustc_semver::RustcVersion;
use super::PTR_AS_PTR; use super::PTR_AS_PTR;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option<RustcVersion>) { pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
if !meets_msrv(msrv, msrvs::POINTER_CAST) { if !msrv.meets(msrvs::POINTER_CAST) {
return; return;
} }

View file

@ -1,14 +1,14 @@
//! lint on manually implemented checked conversions that could be transformed into `try_from` //! lint on manually implemented checked conversions that could be transformed into `try_from`
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{in_constant, is_integer_literal, meets_msrv, msrvs, SpanlessEq}; use clippy_utils::{in_constant, is_integer_literal, SpanlessEq};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! { declare_clippy_lint! {
@ -37,12 +37,12 @@ declare_clippy_lint! {
} }
pub struct CheckedConversions { pub struct CheckedConversions {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl CheckedConversions { impl CheckedConversions {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -51,7 +51,7 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);
impl<'tcx> LateLintPass<'tcx> for CheckedConversions { impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
if !meets_msrv(self.msrv, msrvs::TRY_FROM) { if !self.msrv.meets(msrvs::TRY_FROM) {
return; return;
} }

View file

@ -1,12 +1,13 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap}; use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::sugg::has_enclosing_paren;
use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res}; use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res};
use clippy_utils::{ use clippy_utils::{
fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, meets_msrv, msrvs, path_to_local, fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage,
walk_to_expr_usage,
}; };
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch}; use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch};
@ -28,7 +29,6 @@ use rustc_middle::ty::{
self, Binder, BoundVariableKind, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind, self, Binder, BoundVariableKind, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind,
ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults, ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults,
}; };
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::infer::InferCtxtExt as _;
@ -181,12 +181,12 @@ pub struct Dereferencing<'tcx> {
possible_borrowers: Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, possible_borrowers: Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
// `IntoIterator` for arrays requires Rust 1.53. // `IntoIterator` for arrays requires Rust 1.53.
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl<'tcx> Dereferencing<'tcx> { impl<'tcx> Dereferencing<'tcx> {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { Self {
msrv, msrv,
..Dereferencing::default() ..Dereferencing::default()
@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
match (self.state.take(), kind) { match (self.state.take(), kind) {
(None, kind) => { (None, kind) => {
let expr_ty = typeck.expr_ty(expr); let expr_ty = typeck.expr_ty(expr);
let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, self.msrv); let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, &self.msrv);
match kind { match kind {
RefOp::Deref => { RefOp::Deref => {
if let Position::FieldAccess { if let Position::FieldAccess {
@ -698,7 +698,7 @@ fn walk_parents<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
e: &'tcx Expr<'_>, e: &'tcx Expr<'_>,
msrv: Option<RustcVersion>, msrv: &Msrv,
) -> (Position, &'tcx [Adjustment<'tcx>]) { ) -> (Position, &'tcx [Adjustment<'tcx>]) {
let mut adjustments = [].as_slice(); let mut adjustments = [].as_slice();
let mut precedence = 0i8; let mut precedence = 0i8;
@ -1082,7 +1082,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
param_ty: ParamTy, param_ty: ParamTy,
mut expr: &Expr<'tcx>, mut expr: &Expr<'tcx>,
precedence: i8, precedence: i8,
msrv: Option<RustcVersion>, msrv: &Msrv,
) -> Position { ) -> Position {
let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait(); let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
let sized_trait_def_id = cx.tcx.lang_items().sized_trait(); let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
@ -1182,7 +1182,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
&& let ty::Param(param_ty) = trait_predicate.self_ty().kind() && let ty::Param(param_ty) = trait_predicate.self_ty().kind()
&& let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack() && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack()
&& ty.is_array() && ty.is_array()
&& !meets_msrv(msrv, msrvs::ARRAY_INTO_ITERATOR) && !msrv.meets(msrvs::ARRAY_INTO_ITERATOR)
{ {
return false; return false;
} }

View file

@ -1,11 +1,12 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::is_diag_trait_item;
use clippy_utils::macros::FormatParamKind::{Implicit, Named, Numbered, Starred}; use clippy_utils::macros::FormatParamKind::{Implicit, Named, Numbered, Starred};
use clippy_utils::macros::{ use clippy_utils::macros::{
is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, FormatParamUsage, is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, FormatParamUsage,
}; };
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs};
use if_chain::if_chain; use if_chain::if_chain;
use itertools::Itertools; use itertools::Itertools;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -13,7 +14,6 @@ use rustc_hir::{Expr, ExprKind, HirId, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_span::edition::Edition::Edition2021; use rustc_span::edition::Edition::Edition2021;
@ -158,12 +158,12 @@ impl_lint_pass!(FormatArgs => [
]); ]);
pub struct FormatArgs { pub struct FormatArgs {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl FormatArgs { impl FormatArgs {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -188,7 +188,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs {
check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value); check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value);
check_to_string_in_format_args(cx, name, arg.param.value); check_to_string_in_format_args(cx, name, arg.param.value);
} }
if meets_msrv(self.msrv, msrvs::FORMAT_ARGS_CAPTURE) { if self.msrv.meets(msrvs::FORMAT_ARGS_CAPTURE) {
check_uninlined_args(cx, &format_args, outermost_expn_data.call_site, macro_def_id); check_uninlined_args(cx, &format_args, outermost_expn_data.call_site, macro_def_id);
} }
} }

View file

@ -1,7 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::span_is_local; use clippy_utils::macros::span_is_local;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::path_def_id;
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use clippy_utils::{meets_msrv, msrvs, path_def_id};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_path, Visitor}; use rustc_hir::intravisit::{walk_path, Visitor};
use rustc_hir::{ use rustc_hir::{
@ -10,7 +11,6 @@ use rustc_hir::{
}; };
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::{kw, sym}; use rustc_span::symbol::{kw, sym};
use rustc_span::{Span, Symbol}; use rustc_span::{Span, Symbol};
@ -49,12 +49,12 @@ declare_clippy_lint! {
} }
pub struct FromOverInto { pub struct FromOverInto {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl FromOverInto { impl FromOverInto {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
FromOverInto { msrv } FromOverInto { msrv }
} }
} }
@ -63,7 +63,7 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
impl<'tcx> LateLintPass<'tcx> for FromOverInto { impl<'tcx> LateLintPass<'tcx> for FromOverInto {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if !meets_msrv(self.msrv, msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) { if !self.msrv.meets(msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) {
return; return;
} }

View file

@ -1,14 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::eager_or_lazy::switch_to_eager_eval;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::source::snippet_with_macro_callsite;
use clippy_utils::{ use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks};
contains_return, higher, is_else_clause, is_res_lang_ctor, meets_msrv, msrvs, path_res, peel_blocks,
};
use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_hir::{Expr, ExprKind, Stmt, StmtKind}; use rustc_hir::{Expr, ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! { declare_clippy_lint! {
@ -47,12 +45,12 @@ declare_clippy_lint! {
} }
pub struct IfThenSomeElseNone { pub struct IfThenSomeElseNone {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl IfThenSomeElseNone { impl IfThenSomeElseNone {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -61,7 +59,7 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if !meets_msrv(self.msrv, msrvs::BOOL_THEN) { if !self.msrv.meets(msrvs::BOOL_THEN) {
return; return;
} }
@ -94,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
} else { } else {
format!("{{ /* snippet */ {arg_snip} }}") format!("{{ /* snippet */ {arg_snip} }}")
}; };
let method_name = if switch_to_eager_eval(cx, expr) && meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) { let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(msrvs::BOOL_THEN_SOME) {
"then_some" "then_some"
} else { } else {
method_body.insert_str(0, "|| "); method_body.insert_str(0, "|| ");

View file

@ -1,8 +1,9 @@
use clippy_utils::consts::{constant, Constant}; use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLet; use clippy_utils::higher::IfLet;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::is_copy; use clippy_utils::ty::is_copy;
use clippy_utils::{is_expn_of, is_lint_allowed, meets_msrv, msrvs, path_to_local}; use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -11,7 +12,6 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{symbol::Ident, Span}; use rustc_span::{symbol::Ident, Span};
@ -51,14 +51,13 @@ declare_clippy_lint! {
"avoid indexing on slices which could be destructed" "avoid indexing on slices which could be destructed"
} }
#[derive(Copy, Clone)]
pub struct IndexRefutableSlice { pub struct IndexRefutableSlice {
max_suggested_slice: u64, max_suggested_slice: u64,
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl IndexRefutableSlice { impl IndexRefutableSlice {
pub fn new(max_suggested_slice_pattern_length: u64, msrv: Option<RustcVersion>) -> Self { pub fn new(max_suggested_slice_pattern_length: u64, msrv: Msrv) -> Self {
Self { Self {
max_suggested_slice: max_suggested_slice_pattern_length, max_suggested_slice: max_suggested_slice_pattern_length,
msrv, msrv,
@ -74,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some(); if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some();
if let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr); if let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr);
if !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id); if !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id);
if meets_msrv(self.msrv, msrvs::SLICE_PATTERNS); if self.msrv.meets(msrvs::SLICE_PATTERNS);
let found_slices = find_slice_values(cx, let_pat); let found_slices = find_slice_values(cx, let_pat);
if !found_slices.is_empty(); if !found_slices.is_empty();

View file

@ -1,13 +1,11 @@
use clippy_utils::{ use clippy_utils::diagnostics::{self, span_lint_and_sugg};
diagnostics::{self, span_lint_and_sugg}, use clippy_utils::msrvs::{self, Msrv};
meets_msrv, msrvs, source, use clippy_utils::source;
sugg::Sugg, use clippy_utils::sugg::Sugg;
ty, use clippy_utils::ty;
};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{source_map::Spanned, sym}; use rustc_span::{source_map::Spanned, sym};
@ -68,12 +66,12 @@ declare_clippy_lint! {
} }
pub struct InstantSubtraction { pub struct InstantSubtraction {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl InstantSubtraction { impl InstantSubtraction {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -101,7 +99,7 @@ impl LateLintPass<'_> for InstantSubtraction {
} else { } else {
if_chain! { if_chain! {
if !expr.span.from_expansion(); if !expr.span.from_expansion();
if meets_msrv(self.msrv, msrvs::TRY_FROM); if self.msrv.meets(msrvs::TRY_FROM);
if is_an_instant(cx, lhs); if is_an_instant(cx, lhs);
if is_a_duration(cx, rhs); if is_a_duration(cx, rhs);

View file

@ -52,10 +52,9 @@ extern crate declare_clippy_lint;
use std::io; use std::io;
use std::path::PathBuf; use std::path::PathBuf;
use clippy_utils::parse_msrv; use clippy_utils::msrvs::Msrv;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_lint::{Lint, LintId}; use rustc_lint::{Lint, LintId};
use rustc_semver::RustcVersion;
use rustc_session::Session; use rustc_session::Session;
#[cfg(feature = "internal")] #[cfg(feature = "internal")]
@ -322,48 +321,10 @@ pub use crate::utils::conf::{lookup_conf_file, Conf};
/// Used in `./src/driver.rs`. /// Used in `./src/driver.rs`.
pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) { pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
// NOTE: Do not add any more pre-expansion passes. These should be removed eventually. // NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
let msrv = Msrv::read(&conf.msrv, sess);
let msrv = move || msrv.clone();
let msrv = conf.msrv.as_ref().and_then(|s| { store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv: msrv() }));
parse_msrv(s, None, None).or_else(|| {
sess.err(format!(
"error reading Clippy's configuration file. `{s}` is not a valid Rust version"
));
None
})
});
store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv }));
}
fn read_msrv(conf: &Conf, sess: &Session) -> Option<RustcVersion> {
let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION")
.ok()
.and_then(|v| parse_msrv(&v, None, None));
let clippy_msrv = conf.msrv.as_ref().and_then(|s| {
parse_msrv(s, None, None).or_else(|| {
sess.err(format!(
"error reading Clippy's configuration file. `{s}` is not a valid Rust version"
));
None
})
});
if let Some(cargo_msrv) = cargo_msrv {
if let Some(clippy_msrv) = clippy_msrv {
// if both files have an msrv, let's compare them and emit a warning if they differ
if clippy_msrv != cargo_msrv {
sess.warn(format!(
"the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
));
}
Some(clippy_msrv)
} else {
Some(cargo_msrv)
}
} else {
clippy_msrv
}
} }
#[doc(hidden)] #[doc(hidden)]
@ -595,43 +556,44 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports)); store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
let msrv = read_msrv(conf, sess); let msrv = Msrv::read(&conf.msrv, sess);
let msrv = move || msrv.clone();
let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
let allow_expect_in_tests = conf.allow_expect_in_tests; let allow_expect_in_tests = conf.allow_expect_in_tests;
let allow_unwrap_in_tests = conf.allow_unwrap_in_tests; let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv))); store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv())));
store.register_late_pass(move |_| { store.register_late_pass(move |_| {
Box::new(methods::Methods::new( Box::new(methods::Methods::new(
avoid_breaking_exported_api, avoid_breaking_exported_api,
msrv, msrv(),
allow_expect_in_tests, allow_expect_in_tests,
allow_unwrap_in_tests, allow_unwrap_in_tests,
)) ))
}); });
store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv))); store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv())));
let matches_for_let_else = conf.matches_for_let_else; let matches_for_let_else = conf.matches_for_let_else;
store.register_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv, matches_for_let_else))); store.register_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv(), matches_for_let_else)));
store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv))); store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv())));
store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv))); store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv())));
store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv))); store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv())));
store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv))); store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv())));
store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv))); store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv())));
store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv))); store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv())));
store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv))); store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv())));
store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv))); store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv())));
store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv))); store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv())));
store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv))); store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv())));
store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv))); store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv())));
store.register_late_pass(move |_| Box::new(needless_question_mark::NeedlessQuestionMark)); store.register_late_pass(move |_| Box::new(needless_question_mark::NeedlessQuestionMark));
store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv))); store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv())));
store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv))); store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv())));
store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount)); store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount));
store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod)); store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod));
let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length; let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length;
store.register_late_pass(move |_| { store.register_late_pass(move |_| {
Box::new(index_refutable_slice::IndexRefutableSlice::new( Box::new(index_refutable_slice::IndexRefutableSlice::new(
max_suggested_slice_pattern_length, max_suggested_slice_pattern_length,
msrv, msrv(),
)) ))
}); });
store.register_late_pass(|_| Box::<shadow::Shadow>::default()); store.register_late_pass(|_| Box::<shadow::Shadow>::default());
@ -648,7 +610,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef)); store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef));
store.register_late_pass(|_| Box::new(no_effect::NoEffect)); store.register_late_pass(|_| Box::new(no_effect::NoEffect));
store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment)); store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment));
store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv))); store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv())));
let cognitive_complexity_threshold = conf.cognitive_complexity_threshold; let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
store.register_late_pass(move |_| { store.register_late_pass(move |_| {
Box::new(cognitive_complexity::CognitiveComplexity::new( Box::new(cognitive_complexity::CognitiveComplexity::new(
@ -806,7 +768,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports))); store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
store.register_late_pass(|_| Box::<redundant_pub_crate::RedundantPubCrate>::default()); store.register_late_pass(|_| Box::<redundant_pub_crate::RedundantPubCrate>::default());
store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress)); store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv))); store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv())));
store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse));
store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend)); store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend));
store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex)); store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex));
@ -840,7 +802,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::<vec_init_then_push::VecInitThenPush>::default()); store.register_late_pass(|_| Box::<vec_init_then_push::VecInitThenPush>::default());
store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing)); store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing));
store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10)); store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10));
store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv))); store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv())));
store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison)); store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison));
store.register_early_pass(move || Box::new(module_style::ModStyle)); store.register_early_pass(move || Box::new(module_style::ModStyle));
store.register_late_pass(|_| Box::new(unused_async::UnusedAsync)); store.register_late_pass(|_| Box::new(unused_async::UnusedAsync));
@ -865,14 +827,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
)) ))
}); });
store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks)); store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv))); store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv())));
store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray)); store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes)); store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit)); store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit));
store.register_late_pass(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse)); store.register_late_pass(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
store.register_late_pass(|_| Box::new(init_numbered_fields::NumberedFields)); store.register_late_pass(|_| Box::new(init_numbered_fields::NumberedFields));
store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames)); store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv))); store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv())));
store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation)); store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation));
store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default()); store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default());
let allow_dbg_in_tests = conf.allow_dbg_in_tests; let allow_dbg_in_tests = conf.allow_dbg_in_tests;
@ -896,20 +858,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
store.register_early_pass(|| Box::<duplicate_mod::DuplicateMod>::default()); store.register_early_pass(|| Box::<duplicate_mod::DuplicateMod>::default());
store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding)); store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv))); store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv())));
store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef)); store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef));
store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch)); store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch));
store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec)); store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec));
store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv))); store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv())));
store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv))); store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv())));
let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold))); store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default()); store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv))); store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv())));
store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone)); store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv))); store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv())));
store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew)); store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew));
store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable)); store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable));
store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments)); store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments));
@ -920,7 +882,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods)); store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr)); store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow)); store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv))); store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
// add lints here, do not remove this comment, it's used in `new_lint` // add lints here, do not remove this comment, it's used in `new_lint`
} }

View file

@ -1,12 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::get_parent_expr;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{get_parent_expr, meets_msrv, msrvs};
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath}; use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::sym; use rustc_span::sym;
@ -34,12 +34,12 @@ declare_clippy_lint! {
#[derive(Clone)] #[derive(Clone)]
pub struct ManualBits { pub struct ManualBits {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl ManualBits { impl ManualBits {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -48,7 +48,7 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]);
impl<'tcx> LateLintPass<'tcx> for ManualBits { impl<'tcx> LateLintPass<'tcx> for ManualBits {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv, msrvs::MANUAL_BITS) { if !self.msrv.meets(msrvs::MANUAL_BITS) {
return; return;
} }

View file

@ -1,28 +1,25 @@
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::higher::If;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::implements_trait;
use clippy_utils::visitors::is_const_evaluatable;
use clippy_utils::MaybePath;
use clippy_utils::{
eq_expr_value, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
};
use itertools::Itertools; use itertools::Itertools;
use rustc_errors::Applicability;
use rustc_errors::Diagnostic; use rustc_errors::Diagnostic;
use rustc_hir::{ use rustc_hir::{
def::Res, Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind, def::Res, Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind,
}; };
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{symbol::sym, Span}; use rustc_span::{symbol::sym, Span};
use std::ops::Deref; use std::ops::Deref;
use clippy_utils::{
diagnostics::{span_lint_and_then, span_lint_hir_and_then},
eq_expr_value,
higher::If,
is_diag_trait_item, is_trait_method, meets_msrv, msrvs, path_res, path_to_local_id, peel_blocks,
peel_blocks_with_stmt,
sugg::Sugg,
ty::implements_trait,
visitors::is_const_evaluatable,
MaybePath,
};
use rustc_errors::Applicability;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
/// Identifies good opportunities for a clamp function from std or core, and suggests using it. /// Identifies good opportunities for a clamp function from std or core, and suggests using it.
@ -87,11 +84,11 @@ declare_clippy_lint! {
impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]); impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]);
pub struct ManualClamp { pub struct ManualClamp {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl ManualClamp { impl ManualClamp {
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -114,7 +111,7 @@ struct InputMinMax<'tcx> {
impl<'tcx> LateLintPass<'tcx> for ManualClamp { impl<'tcx> LateLintPass<'tcx> for ManualClamp {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if !meets_msrv(self.msrv, msrvs::CLAMP) { if !self.msrv.meets(msrvs::CLAMP) {
return; return;
} }
if !expr.span.from_expansion() { if !expr.span.from_expansion() {
@ -130,7 +127,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp {
} }
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
if !meets_msrv(self.msrv, msrvs::CLAMP) { if !self.msrv.meets(msrvs::CLAMP) {
return; return;
} }
for suggestion in is_two_if_pattern(cx, block) { for suggestion in is_two_if_pattern(cx, block) {

View file

@ -1,15 +1,12 @@
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::{diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, source::snippet};
use rustc_ast::LitKind::{Byte, Char}; use rustc_ast::LitKind::{Byte, Char};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd}; use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{def_id::DefId, sym}; use rustc_span::{def_id::DefId, sym};
use clippy_utils::{
diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, meets_msrv, msrvs, source::snippet,
};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
/// Suggests to use dedicated built-in methods, /// Suggests to use dedicated built-in methods,
@ -45,12 +42,12 @@ declare_clippy_lint! {
impl_lint_pass!(ManualIsAsciiCheck => [MANUAL_IS_ASCII_CHECK]); impl_lint_pass!(ManualIsAsciiCheck => [MANUAL_IS_ASCII_CHECK]);
pub struct ManualIsAsciiCheck { pub struct ManualIsAsciiCheck {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl ManualIsAsciiCheck { impl ManualIsAsciiCheck {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -70,11 +67,11 @@ enum CharRange {
impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv, msrvs::IS_ASCII_DIGIT) { if !self.msrv.meets(msrvs::IS_ASCII_DIGIT) {
return; return;
} }
if in_constant(cx, expr.hir_id) && !meets_msrv(self.msrv, msrvs::IS_ASCII_DIGIT_CONST) { if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::IS_ASCII_DIGIT_CONST) {
return; return;
} }

View file

@ -1,16 +1,16 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLetOrMatch; use clippy_utils::higher::IfLetOrMatch;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::peel_blocks;
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::visitors::{for_each_expr, Descend};
use clippy_utils::{meets_msrv, msrvs, peel_blocks};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind}; use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::Span; use rustc_span::Span;
@ -50,13 +50,13 @@ declare_clippy_lint! {
} }
pub struct ManualLetElse { pub struct ManualLetElse {
msrv: Option<RustcVersion>, msrv: Msrv,
matches_behaviour: MatchLintBehaviour, matches_behaviour: MatchLintBehaviour,
} }
impl ManualLetElse { impl ManualLetElse {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>, matches_behaviour: MatchLintBehaviour) -> Self { pub fn new(msrv: Msrv, matches_behaviour: MatchLintBehaviour) -> Self {
Self { Self {
msrv, msrv,
matches_behaviour, matches_behaviour,
@ -69,7 +69,7 @@ impl_lint_pass!(ManualLetElse => [MANUAL_LET_ELSE]);
impl<'tcx> LateLintPass<'tcx> for ManualLetElse { impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
let if_let_or_match = if_chain! { let if_let_or_match = if_chain! {
if meets_msrv(self.msrv, msrvs::LET_ELSE); if self.msrv.meets(msrvs::LET_ELSE);
if !in_external_macro(cx.sess(), stmt.span); if !in_external_macro(cx.sess(), stmt.span);
if let StmtKind::Local(local) = stmt.kind; if let StmtKind::Local(local) = stmt.kind;
if let Some(init) = local.init; if let Some(init) = local.init;

View file

@ -1,6 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::is_doc_hidden;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use clippy_utils::{is_doc_hidden, meets_msrv, msrvs};
use rustc_ast::ast::{self, VisibilityKind}; use rustc_ast::ast::{self, VisibilityKind};
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -8,7 +9,6 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::{self as hir, Expr, ExprKind, QPath}; use rustc_hir::{self as hir, Expr, ExprKind, QPath};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_middle::ty::DefIdTree; use rustc_middle::ty::DefIdTree;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
@ -63,12 +63,12 @@ declare_clippy_lint! {
#[expect(clippy::module_name_repetitions)] #[expect(clippy::module_name_repetitions)]
pub struct ManualNonExhaustiveStruct { pub struct ManualNonExhaustiveStruct {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl ManualNonExhaustiveStruct { impl ManualNonExhaustiveStruct {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -77,14 +77,14 @@ impl_lint_pass!(ManualNonExhaustiveStruct => [MANUAL_NON_EXHAUSTIVE]);
#[expect(clippy::module_name_repetitions)] #[expect(clippy::module_name_repetitions)]
pub struct ManualNonExhaustiveEnum { pub struct ManualNonExhaustiveEnum {
msrv: Option<RustcVersion>, msrv: Msrv,
constructed_enum_variants: FxHashSet<(DefId, DefId)>, constructed_enum_variants: FxHashSet<(DefId, DefId)>,
potential_enums: Vec<(LocalDefId, LocalDefId, Span, Span)>, potential_enums: Vec<(LocalDefId, LocalDefId, Span, Span)>,
} }
impl ManualNonExhaustiveEnum { impl ManualNonExhaustiveEnum {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { Self {
msrv, msrv,
constructed_enum_variants: FxHashSet::default(), constructed_enum_variants: FxHashSet::default(),
@ -97,7 +97,7 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]);
impl EarlyLintPass for ManualNonExhaustiveStruct { impl EarlyLintPass for ManualNonExhaustiveStruct {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) { if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) {
return; return;
} }
@ -149,7 +149,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) { if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) {
return; return;
} }

View file

@ -1,12 +1,12 @@
use clippy_utils::consts::{constant_full_int, FullInt}; use clippy_utils::consts::{constant_full_int, FullInt};
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{in_constant, meets_msrv, msrvs, path_to_local}; use clippy_utils::{in_constant, path_to_local};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind}; use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! { declare_clippy_lint! {
@ -34,12 +34,12 @@ declare_clippy_lint! {
} }
pub struct ManualRemEuclid { pub struct ManualRemEuclid {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl ManualRemEuclid { impl ManualRemEuclid {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -48,11 +48,11 @@ impl_lint_pass!(ManualRemEuclid => [MANUAL_REM_EUCLID]);
impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv, msrvs::REM_EUCLID) { if !self.msrv.meets(msrvs::REM_EUCLID) {
return; return;
} }
if in_constant(cx, expr.hir_id) && !meets_msrv(self.msrv, msrvs::REM_EUCLID_CONST) { if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::REM_EUCLID_CONST) {
return; return;
} }

View file

@ -1,8 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq}; use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq};
use clippy_utils::{meets_msrv, msrvs};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
@ -50,12 +50,12 @@ declare_clippy_lint! {
} }
pub struct ManualRetain { pub struct ManualRetain {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl ManualRetain { impl ManualRetain {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -71,9 +71,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain {
&& let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
&& let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id) && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
&& match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) { && match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv); check_into_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
check_iter(cx, parent_expr, left_expr, target_expr, self.msrv); check_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
check_to_owned(cx, parent_expr, left_expr, target_expr, self.msrv); check_to_owned(cx, parent_expr, left_expr, target_expr, &self.msrv);
} }
} }
@ -85,7 +85,7 @@ fn check_into_iter(
parent_expr: &hir::Expr<'_>, parent_expr: &hir::Expr<'_>,
left_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>,
target_expr: &hir::Expr<'_>, target_expr: &hir::Expr<'_>,
msrv: Option<RustcVersion>, msrv: &Msrv,
) { ) {
if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
@ -104,7 +104,7 @@ fn check_iter(
parent_expr: &hir::Expr<'_>, parent_expr: &hir::Expr<'_>,
left_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>,
target_expr: &hir::Expr<'_>, target_expr: &hir::Expr<'_>,
msrv: Option<RustcVersion>, msrv: &Msrv,
) { ) {
if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
&& let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) && let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
@ -127,9 +127,9 @@ fn check_to_owned(
parent_expr: &hir::Expr<'_>, parent_expr: &hir::Expr<'_>,
left_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>,
target_expr: &hir::Expr<'_>, target_expr: &hir::Expr<'_>,
msrv: Option<RustcVersion>, msrv: &Msrv,
) { ) {
if meets_msrv(msrv, msrvs::STRING_RETAIN) if msrv.meets(msrvs::STRING_RETAIN)
&& let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
&& let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) && let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD) && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD)
@ -215,10 +215,10 @@ fn match_acceptable_def_path(cx: &LateContext<'_>, collect_def_id: DefId) -> boo
.any(|&method| match_def_path(cx, collect_def_id, method)) .any(|&method| match_def_path(cx, collect_def_id, method))
} }
fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Option<RustcVersion>) -> bool { fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv) -> bool {
let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs();
ACCEPTABLE_TYPES.iter().any(|(ty, acceptable_msrv)| { ACCEPTABLE_TYPES.iter().any(|(ty, acceptable_msrv)| {
is_type_diagnostic_item(cx, expr_ty, *ty) is_type_diagnostic_item(cx, expr_ty, *ty)
&& acceptable_msrv.map_or(true, |acceptable_msrv| meets_msrv(msrv, acceptable_msrv)) && acceptable_msrv.map_or(true, |acceptable_msrv| msrv.meets(acceptable_msrv))
}) })
} }

View file

@ -1,8 +1,9 @@
use clippy_utils::consts::{constant, Constant}; use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::usage::mutated_variables; use clippy_utils::usage::mutated_variables;
use clippy_utils::{eq_expr_value, higher, match_def_path, meets_msrv, msrvs, paths}; use clippy_utils::{eq_expr_value, higher, match_def_path, paths};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_hir::def::Res; use rustc_hir::def::Res;
@ -11,7 +12,6 @@ use rustc_hir::BinOpKind;
use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_hir::{BorrowKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
use rustc_span::Span; use rustc_span::Span;
@ -48,12 +48,12 @@ declare_clippy_lint! {
} }
pub struct ManualStrip { pub struct ManualStrip {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl ManualStrip { impl ManualStrip {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -68,7 +68,7 @@ enum StripKind {
impl<'tcx> LateLintPass<'tcx> for ManualStrip { impl<'tcx> LateLintPass<'tcx> for ManualStrip {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) { if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) {
return; return;
} }

View file

@ -23,13 +23,13 @@ mod single_match;
mod try_err; mod try_err;
mod wild_in_or_pats; mod wild_in_or_pats;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{snippet_opt, walk_span_to_context}; use clippy_utils::source::{snippet_opt, walk_span_to_context};
use clippy_utils::{higher, in_constant, is_span_match, meets_msrv, msrvs}; use clippy_utils::{higher, in_constant, is_span_match};
use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
use rustc_lexer::{tokenize, TokenKind}; use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{Span, SpanData, SyntaxContext}; use rustc_span::{Span, SpanData, SyntaxContext};
@ -930,13 +930,13 @@ declare_clippy_lint! {
#[derive(Default)] #[derive(Default)]
pub struct Matches { pub struct Matches {
msrv: Option<RustcVersion>, msrv: Msrv,
infallible_destructuring_match_linted: bool, infallible_destructuring_match_linted: bool,
} }
impl Matches { impl Matches {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { Self {
msrv, msrv,
..Matches::default() ..Matches::default()
@ -1000,9 +1000,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
if !from_expansion && !contains_cfg_arm(cx, expr, ex, arms) { if !from_expansion && !contains_cfg_arm(cx, expr, ex, arms) {
if source == MatchSource::Normal { if source == MatchSource::Normal {
if !(meets_msrv(self.msrv, msrvs::MATCHES_MACRO) if !(self.msrv.meets(msrvs::MATCHES_MACRO) && match_like_matches::check_match(cx, expr, ex, arms)) {
&& match_like_matches::check_match(cx, expr, ex, arms))
{
match_same_arms::check(cx, arms); match_same_arms::check(cx, arms);
} }
@ -1034,7 +1032,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else); collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else);
if !from_expansion { if !from_expansion {
if let Some(else_expr) = if_let.if_else { if let Some(else_expr) = if_let.if_else {
if meets_msrv(self.msrv, msrvs::MATCHES_MACRO) { if self.msrv.meets(msrvs::MATCHES_MACRO) {
match_like_matches::check_if_let( match_like_matches::check_if_let(
cx, cx,
expr, expr,

View file

@ -1,14 +1,14 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::ty::is_non_aggregate_primitive_type; use clippy_utils::ty::is_non_aggregate_primitive_type;
use clippy_utils::{is_default_equivalent, is_res_lang_ctor, meets_msrv, msrvs, path_res}; use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone; use rustc_hir::LangItem::OptionNone;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath}; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
@ -227,12 +227,12 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<
} }
pub struct MemReplace { pub struct MemReplace {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl MemReplace { impl MemReplace {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -248,7 +248,7 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
then { then {
check_replace_option_with_none(cx, src, dest, expr.span); check_replace_option_with_none(cx, src, dest, expr.span);
check_replace_with_uninit(cx, src, dest, expr.span); check_replace_with_uninit(cx, src, dest, expr.span);
if meets_msrv(self.msrv, msrvs::MEM_TAKE) { if self.msrv.meets(msrvs::MEM_TAKE) {
check_replace_with_default(cx, src, dest, expr.span); check_replace_with_default(cx, src, dest, expr.span);
} }
} }

View file

@ -1,25 +1,25 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::{get_iterator_item_ty, is_copy}; use clippy_utils::ty::{get_iterator_item_ty, is_copy};
use clippy_utils::{is_trait_method, meets_msrv, msrvs};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::Expr; use rustc_hir::Expr;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_semver::RustcVersion;
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
use super::CLONED_INSTEAD_OF_COPIED; use super::CLONED_INSTEAD_OF_COPIED;
pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<RustcVersion>) { pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: &Msrv) {
let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); let recv_ty = cx.typeck_results().expr_ty_adjusted(recv);
let inner_ty = match recv_ty.kind() { let inner_ty = match recv_ty.kind() {
// `Option<T>` -> `T` // `Option<T>` -> `T`
ty::Adt(adt, subst) ty::Adt(adt, subst)
if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, msrvs::OPTION_COPIED) => if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && msrv.meets(msrvs::OPTION_COPIED) =>
{ {
subst.type_at(0) subst.type_at(0)
}, },
_ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) => { _ if is_trait_method(cx, expr, sym::Iterator) && msrv.meets(msrvs::ITERATOR_COPIED) => {
match get_iterator_item_ty(cx, recv_ty) { match get_iterator_item_ty(cx, recv_ty) {
// <T as Iterator>::Item // <T as Iterator>::Item
Some(ty) => ty, Some(ty) => ty,

View file

@ -1,27 +1,27 @@
use super::ERR_EXPECT; use super::ERR_EXPECT;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::has_debug_impl; use clippy_utils::ty::has_debug_impl;
use clippy_utils::{meets_msrv, msrvs, ty::is_type_diagnostic_item}; use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
use rustc_semver::RustcVersion;
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
pub(super) fn check( pub(super) fn check(
cx: &LateContext<'_>, cx: &LateContext<'_>,
_expr: &rustc_hir::Expr<'_>, _expr: &rustc_hir::Expr<'_>,
recv: &rustc_hir::Expr<'_>, recv: &rustc_hir::Expr<'_>,
msrv: Option<RustcVersion>,
expect_span: Span, expect_span: Span,
err_span: Span, err_span: Span,
msrv: &Msrv,
) { ) {
if_chain! { if_chain! {
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
// Test the version to make sure the lint can be showed (expect_err has been // Test the version to make sure the lint can be showed (expect_err has been
// introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982) // introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982)
if meets_msrv(msrv, msrvs::EXPECT_ERR); if msrv.meets(msrvs::EXPECT_ERR);
// Grabs the `Result<T, E>` type // Grabs the `Result<T, E>` type
let result_type = cx.typeck_results().expr_ty(recv); let result_type = cx.typeck_results().expr_ty(recv);

View file

@ -1,10 +1,10 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::is_trait_method;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::{is_trait_method, meets_msrv, msrvs};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_semver::RustcVersion;
use rustc_span::sym; use rustc_span::sym;
use super::FILTER_MAP_NEXT; use super::FILTER_MAP_NEXT;
@ -14,10 +14,10 @@ pub(super) fn check<'tcx>(
expr: &'tcx hir::Expr<'_>, expr: &'tcx hir::Expr<'_>,
recv: &'tcx hir::Expr<'_>, recv: &'tcx hir::Expr<'_>,
arg: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>,
msrv: Option<RustcVersion>, msrv: &Msrv,
) { ) {
if is_trait_method(cx, expr, sym::Iterator) { if is_trait_method(cx, expr, sym::Iterator) {
if !meets_msrv(msrv, msrvs::ITERATOR_FIND_MAP) { if !msrv.meets(msrvs::ITERATOR_FIND_MAP) {
return; return;
} }

View file

@ -1,23 +1,22 @@
//! Lint for `c.is_digit(10)` //! Lint for `c.is_digit(10)`
use super::IS_DIGIT_ASCII_RADIX; use super::IS_DIGIT_ASCII_RADIX;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::{ use clippy_utils::{
consts::constant_full_int, consts::FullInt, diagnostics::span_lint_and_sugg, meets_msrv, msrvs, consts::constant_full_int, consts::FullInt, diagnostics::span_lint_and_sugg, source::snippet_with_applicability,
source::snippet_with_applicability,
}; };
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::Expr; use rustc_hir::Expr;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_semver::RustcVersion;
pub(super) fn check<'tcx>( pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>,
self_arg: &'tcx Expr<'_>, self_arg: &'tcx Expr<'_>,
radix: &'tcx Expr<'_>, radix: &'tcx Expr<'_>,
msrv: Option<RustcVersion>, msrv: &Msrv,
) { ) {
if !meets_msrv(msrv, msrvs::IS_ASCII_DIGIT) { if !msrv.meets(msrvs::IS_ASCII_DIGIT) {
return; return;
} }

View file

@ -1,7 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs, peel_blocks}; use clippy_utils::{is_diag_trait_item, peel_blocks};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
@ -9,19 +10,12 @@ use rustc_lint::LateContext;
use rustc_middle::mir::Mutability; use rustc_middle::mir::Mutability;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::adjustment::Adjust;
use rustc_semver::RustcVersion;
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
use super::MAP_CLONE; use super::MAP_CLONE;
pub(super) fn check( pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, msrv: &Msrv) {
cx: &LateContext<'_>,
e: &hir::Expr<'_>,
recv: &hir::Expr<'_>,
arg: &hir::Expr<'_>,
msrv: Option<RustcVersion>,
) {
if_chain! { if_chain! {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id); if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id);
if cx.tcx.impl_of_method(method_id) if cx.tcx.impl_of_method(method_id)
@ -97,10 +91,10 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
); );
} }
fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: Option<RustcVersion>) { fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: &Msrv) {
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
let (message, sugg_method) = if is_copy && meets_msrv(msrv, msrvs::ITERATOR_COPIED) { let (message, sugg_method) = if is_copy && msrv.meets(msrvs::ITERATOR_COPIED) {
("you are using an explicit closure for copying elements", "copied") ("you are using an explicit closure for copying elements", "copied")
} else { } else {
("you are using an explicit closure for cloning elements", "cloned") ("you are using an explicit closure for cloning elements", "cloned")

View file

@ -1,12 +1,11 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::usage::mutated_variables; use clippy_utils::usage::mutated_variables;
use clippy_utils::{meets_msrv, msrvs};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_semver::RustcVersion;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use super::MAP_UNWRAP_OR; use super::MAP_UNWRAP_OR;
@ -19,13 +18,13 @@ pub(super) fn check<'tcx>(
recv: &'tcx hir::Expr<'_>, recv: &'tcx hir::Expr<'_>,
map_arg: &'tcx hir::Expr<'_>, map_arg: &'tcx hir::Expr<'_>,
unwrap_arg: &'tcx hir::Expr<'_>, unwrap_arg: &'tcx hir::Expr<'_>,
msrv: Option<RustcVersion>, msrv: &Msrv,
) -> bool { ) -> bool {
// lint if the caller of `map()` is an `Option` // 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); let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option);
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
if is_result && !meets_msrv(msrv, msrvs::RESULT_MAP_OR_ELSE) { if is_result && !msrv.meets(msrvs::RESULT_MAP_OR_ELSE) {
return false; return false;
} }

View file

@ -104,8 +104,9 @@ mod zst_offset;
use bind_instead_of_map::BindInsteadOfMap; use bind_instead_of_map::BindInsteadOfMap;
use clippy_utils::consts::{constant, Constant}; use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, meets_msrv, msrvs, return_ty}; use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, return_ty};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::{Expr, ExprKind, TraitItem, TraitItemKind}; use rustc_hir::{Expr, ExprKind, TraitItem, TraitItemKind};
@ -113,7 +114,6 @@ use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_middle::ty::{self, TraitRef, Ty};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
@ -3163,7 +3163,7 @@ declare_clippy_lint! {
pub struct Methods { pub struct Methods {
avoid_breaking_exported_api: bool, avoid_breaking_exported_api: bool,
msrv: Option<RustcVersion>, msrv: Msrv,
allow_expect_in_tests: bool, allow_expect_in_tests: bool,
allow_unwrap_in_tests: bool, allow_unwrap_in_tests: bool,
} }
@ -3172,7 +3172,7 @@ impl Methods {
#[must_use] #[must_use]
pub fn new( pub fn new(
avoid_breaking_exported_api: bool, avoid_breaking_exported_api: bool,
msrv: Option<RustcVersion>, msrv: Msrv,
allow_expect_in_tests: bool, allow_expect_in_tests: bool,
allow_unwrap_in_tests: bool, allow_unwrap_in_tests: bool,
) -> Self { ) -> Self {
@ -3325,7 +3325,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
single_char_add_str::check(cx, expr, receiver, args); single_char_add_str::check(cx, expr, receiver, args);
into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver); into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args); single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args);
unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv); unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, &self.msrv);
}, },
hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
let mut info = BinaryExprInfo { let mut info = BinaryExprInfo {
@ -3501,7 +3501,7 @@ impl Methods {
("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv), ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv), ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv), ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv), ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, &self.msrv),
("collect", []) if is_trait_method(cx, expr, sym::Iterator) => { ("collect", []) if is_trait_method(cx, expr, sym::Iterator) => {
needless_collect::check(cx, span, expr, recv, call_span); needless_collect::check(cx, span, expr, recv, call_span);
match method_call(recv) { match method_call(recv) {
@ -3512,7 +3512,7 @@ impl Methods {
map_collect_result_unit::check(cx, expr, m_recv, m_arg); map_collect_result_unit::check(cx, expr, m_recv, m_arg);
}, },
Some(("take", take_self_arg, [take_arg], _, _)) => { Some(("take", take_self_arg, [take_arg], _, _)) => {
if meets_msrv(self.msrv, msrvs::STR_REPEAT) { if self.msrv.meets(msrvs::STR_REPEAT) {
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
} }
}, },
@ -3539,7 +3539,7 @@ impl Methods {
}, },
("expect", [_]) => match method_call(recv) { ("expect", [_]) => match method_call(recv) {
Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv), Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span), Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests), _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
}, },
("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests), ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
@ -3578,7 +3578,7 @@ impl Methods {
unit_hash::check(cx, expr, recv, arg); unit_hash::check(cx, expr, recv, arg);
}, },
("is_file", []) => filetype_is_file::check(cx, expr, recv), ("is_file", []) => filetype_is_file::check(cx, expr, recv),
("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, &self.msrv),
("is_none", []) => check_is_some_is_none(cx, expr, recv, false), ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
("is_some", []) => check_is_some_is_none(cx, expr, recv, true), ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
("iter" | "iter_mut" | "into_iter", []) => { ("iter" | "iter_mut" | "into_iter", []) => {
@ -3601,7 +3601,7 @@ impl Methods {
}, },
(name @ ("map" | "map_err"), [m_arg]) => { (name @ ("map" | "map_err"), [m_arg]) => {
if name == "map" { if name == "map" {
map_clone::check(cx, expr, recv, m_arg, self.msrv); map_clone::check(cx, expr, recv, m_arg, &self.msrv);
if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) = method_call(recv) { if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) = method_call(recv) {
iter_kv_map::check(cx, map_name, expr, recv2, m_arg); iter_kv_map::check(cx, map_name, expr, recv2, m_arg);
} }
@ -3610,8 +3610,8 @@ impl Methods {
} }
if let Some((name, recv2, args, span2,_)) = method_call(recv) { if let Some((name, recv2, args, span2,_)) = method_call(recv) {
match (name, args) { match (name, args) {
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, &self.msrv),
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv), ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, &self.msrv),
("filter", [f_arg]) => { ("filter", [f_arg]) => {
filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false); filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
}, },
@ -3632,7 +3632,7 @@ impl Methods {
match (name2, args2) { match (name2, args2) {
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false), ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv), ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, &self.msrv),
("iter", []) => iter_next_slice::check(cx, expr, recv2), ("iter", []) => iter_next_slice::check(cx, expr, recv2),
("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg), ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
("skip_while", [_]) => skip_while_next::check(cx, expr), ("skip_while", [_]) => skip_while_next::check(cx, expr),
@ -3680,10 +3680,10 @@ impl Methods {
vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span); vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
}, },
("seek", [arg]) => { ("seek", [arg]) => {
if meets_msrv(self.msrv, msrvs::SEEK_FROM_CURRENT) { if self.msrv.meets(msrvs::SEEK_FROM_CURRENT) {
seek_from_current::check(cx, expr, recv, arg); seek_from_current::check(cx, expr, recv, arg);
} }
if meets_msrv(self.msrv, msrvs::SEEK_REWIND) { if self.msrv.meets(msrvs::SEEK_REWIND) {
seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span); seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
} }
}, },
@ -3699,7 +3699,7 @@ impl Methods {
("splitn" | "rsplitn", [count_arg, pat_arg]) => { ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count); suspicious_splitn::check(cx, name, expr, recv, count);
str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv); str_splitn::check(cx, name, expr, recv, pat_arg, count, &self.msrv);
} }
}, },
("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
@ -3717,7 +3717,7 @@ impl Methods {
}, },
("take", []) => needless_option_take::check(cx, expr, recv), ("take", []) => needless_option_take::check(cx, expr, recv),
("then", [arg]) => { ("then", [arg]) => {
if !meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) { if !self.msrv.meets(msrvs::BOOL_THEN_SOME) {
return; return;
} }
unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"); unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
@ -3760,7 +3760,7 @@ impl Methods {
}, },
("unwrap_or_else", [u_arg]) => match method_call(recv) { ("unwrap_or_else", [u_arg]) => match method_call(recv) {
Some(("map", recv, [map_arg], _, _)) Some(("map", recv, [map_arg], _, _))
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {}, if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {},
_ => { _ => {
unwrap_or_else_default::check(cx, expr, recv, u_arg); unwrap_or_else_default::check(cx, expr, recv, u_arg);
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");

View file

@ -1,13 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, peel_blocks}; use clippy_utils::{match_def_path, path_to_local_id, paths, peel_blocks};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_semver::RustcVersion;
use rustc_span::sym; use rustc_span::sym;
use super::OPTION_AS_REF_DEREF; use super::OPTION_AS_REF_DEREF;
@ -19,9 +19,9 @@ pub(super) fn check(
as_ref_recv: &hir::Expr<'_>, as_ref_recv: &hir::Expr<'_>,
map_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>,
is_mut: bool, is_mut: bool,
msrv: Option<RustcVersion>, msrv: &Msrv,
) { ) {
if !meets_msrv(msrv, msrvs::OPTION_AS_DEREF) { if !msrv.meets(msrvs::OPTION_AS_DEREF) {
return; return;
} }

View file

@ -1,9 +1,10 @@
use clippy_utils::consts::{constant, Constant}; use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context; use clippy_utils::source::snippet_with_context;
use clippy_utils::usage::local_used_after_expr; use clippy_utils::usage::local_used_after_expr;
use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, path_to_local_id, paths}; use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths};
use core::ops::ControlFlow; use core::ops::ControlFlow;
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -12,7 +13,6 @@ use rustc_hir::{
}; };
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_semver::RustcVersion;
use rustc_span::{sym, Span, Symbol, SyntaxContext}; use rustc_span::{sym, Span, Symbol, SyntaxContext};
use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN}; use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN};
@ -24,7 +24,7 @@ pub(super) fn check(
self_arg: &Expr<'_>, self_arg: &Expr<'_>,
pat_arg: &Expr<'_>, pat_arg: &Expr<'_>,
count: u128, count: u128,
msrv: Option<RustcVersion>, msrv: &Msrv,
) { ) {
if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() {
return; return;
@ -34,7 +34,7 @@ pub(super) fn check(
IterUsageKind::Nth(n) => count > n + 1, IterUsageKind::Nth(n) => count > n + 1,
IterUsageKind::NextTuple => count > 2, IterUsageKind::NextTuple => count > 2,
}; };
let manual = count == 2 && meets_msrv(msrv, msrvs::STR_SPLIT_ONCE); let manual = count == 2 && msrv.meets(msrvs::STR_SPLIT_ONCE);
match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) { match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) {
Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg), Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg),

View file

@ -1,11 +1,11 @@
use super::implicit_clone::is_clone_like; use super::implicit_clone::is_clone_like;
use super::unnecessary_iter_cloned::{self, is_into_iter}; use super::unnecessary_iter_cloned::{self, is_into_iter};
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::visitors::find_all_ret_expressions;
use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
use clippy_utils::{meets_msrv, msrvs};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node}; use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node};
use rustc_hir_analysis::check::{FnCtxt, Inherited}; use rustc_hir_analysis::check::{FnCtxt, Inherited};
@ -16,7 +16,6 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::EarlyBinder; use rustc_middle::ty::EarlyBinder;
use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
use rustc_semver::RustcVersion;
use rustc_span::{sym, Symbol}; use rustc_span::{sym, Symbol};
use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
use std::cmp::max; use std::cmp::max;
@ -29,7 +28,7 @@ pub fn check<'tcx>(
method_name: Symbol, method_name: Symbol,
receiver: &'tcx Expr<'_>, receiver: &'tcx Expr<'_>,
args: &'tcx [Expr<'_>], args: &'tcx [Expr<'_>],
msrv: Option<RustcVersion>, msrv: &Msrv,
) { ) {
if_chain! { if_chain! {
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
@ -200,7 +199,7 @@ fn check_into_iter_call_arg(
expr: &Expr<'_>, expr: &Expr<'_>,
method_name: Symbol, method_name: Symbol,
receiver: &Expr<'_>, receiver: &Expr<'_>,
msrv: Option<RustcVersion>, msrv: &Msrv,
) -> bool { ) -> bool {
if_chain! { if_chain! {
if let Some(parent) = get_parent_expr(cx, expr); if let Some(parent) = get_parent_expr(cx, expr);
@ -215,7 +214,7 @@ fn check_into_iter_call_arg(
if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) { if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) {
return true; return true;
} }
let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) { let cloned_or_copied = if is_copy(cx, item_ty) && msrv.meets(msrvs::ITERATOR_COPIED) {
"copied" "copied"
} else { } else {
"cloned" "cloned"

View file

@ -1,9 +1,8 @@
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::qualify_min_const_fn::is_min_const_fn;
use clippy_utils::ty::has_drop; use clippy_utils::ty::has_drop;
use clippy_utils::{ use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method};
fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, meets_msrv, msrvs, trait_ref_of_method,
};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_hir::intravisit::FnKind; use rustc_hir::intravisit::FnKind;
@ -11,7 +10,6 @@ use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
use rustc_hir_analysis::hir_ty_to_ty; use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span; use rustc_span::Span;
@ -75,12 +73,12 @@ declare_clippy_lint! {
impl_lint_pass!(MissingConstForFn => [MISSING_CONST_FOR_FN]); impl_lint_pass!(MissingConstForFn => [MISSING_CONST_FOR_FN]);
pub struct MissingConstForFn { pub struct MissingConstForFn {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl MissingConstForFn { impl MissingConstForFn {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -95,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
span: Span, span: Span,
hir_id: HirId, hir_id: HirId,
) { ) {
if !meets_msrv(self.msrv, msrvs::CONST_IF_MATCH) { if !self.msrv.meets(msrvs::CONST_IF_MATCH) {
return; return;
} }
@ -152,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
let mir = cx.tcx.optimized_mir(def_id); let mir = cx.tcx.optimized_mir(def_id);
if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) { if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, &self.msrv) {
if cx.tcx.is_const_fn_raw(def_id.to_def_id()) { if cx.tcx.is_const_fn_raw(def_id.to_def_id()) {
cx.tcx.sess.span_err(span, err.as_ref()); cx.tcx.sess.span_err(span, err.as_ref());
} }

View file

@ -1,16 +1,16 @@
use clippy_utils::consts::{constant, Constant}; use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::higher; use clippy_utils::higher;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, path_to_local}; use clippy_utils::{get_parent_expr, in_constant, is_integer_const, path_to_local};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::RangeLimits; use rustc_ast::ast::RangeLimits;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; use rustc_hir::{BinOpKind, Expr, ExprKind, HirId};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::{Span, Spanned}; use rustc_span::source_map::{Span, Spanned};
use std::cmp::Ordering; use std::cmp::Ordering;
@ -161,12 +161,12 @@ declare_clippy_lint! {
} }
pub struct Ranges { pub struct Ranges {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl Ranges { impl Ranges {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -181,7 +181,7 @@ impl_lint_pass!(Ranges => [
impl<'tcx> LateLintPass<'tcx> for Ranges { impl<'tcx> LateLintPass<'tcx> for Ranges {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Binary(ref op, l, r) = expr.kind { if let ExprKind::Binary(ref op, l, r) = expr.kind {
if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) { if self.msrv.meets(msrvs::RANGE_CONTAINS) {
check_possible_range_contains(cx, op.node, l, r, expr, expr.span); check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
} }
} }

View file

@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::{meets_msrv, msrvs}; use clippy_utils::msrvs::{self, Msrv};
use rustc_ast::ast::{Expr, ExprKind}; use rustc_ast::ast::{Expr, ExprKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! { declare_clippy_lint! {
@ -37,12 +36,12 @@ declare_clippy_lint! {
} }
pub struct RedundantFieldNames { pub struct RedundantFieldNames {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl RedundantFieldNames { impl RedundantFieldNames {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -51,7 +50,7 @@ impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]);
impl EarlyLintPass for RedundantFieldNames { impl EarlyLintPass for RedundantFieldNames {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
if !meets_msrv(self.msrv, msrvs::FIELD_INIT_SHORTHAND) { if !self.msrv.meets(msrvs::FIELD_INIT_SHORTHAND) {
return; return;
} }

View file

@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::{meets_msrv, msrvs};
use rustc_ast::ast::{Item, ItemKind, Ty, TyKind}; use rustc_ast::ast::{Item, ItemKind, Ty, TyKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! { declare_clippy_lint! {
@ -34,12 +33,12 @@ declare_clippy_lint! {
} }
pub struct RedundantStaticLifetimes { pub struct RedundantStaticLifetimes {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl RedundantStaticLifetimes { impl RedundantStaticLifetimes {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -96,7 +95,7 @@ impl RedundantStaticLifetimes {
impl EarlyLintPass for RedundantStaticLifetimes { impl EarlyLintPass for RedundantStaticLifetimes {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
if !meets_msrv(self.msrv, msrvs::STATIC_IN_CONST) { if !self.msrv.meets(msrvs::STATIC_IN_CONST) {
return; return;
} }

View file

@ -16,10 +16,10 @@ mod utils;
mod wrong_transmute; mod wrong_transmute;
use clippy_utils::in_constant; use clippy_utils::in_constant;
use clippy_utils::msrvs::Msrv;
use if_chain::if_chain; use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind, QPath}; use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
@ -410,7 +410,7 @@ declare_clippy_lint! {
} }
pub struct Transmute { pub struct Transmute {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl_lint_pass!(Transmute => [ impl_lint_pass!(Transmute => [
CROSSPOINTER_TRANSMUTE, CROSSPOINTER_TRANSMUTE,
@ -431,7 +431,7 @@ impl_lint_pass!(Transmute => [
]); ]);
impl Transmute { impl Transmute {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -461,7 +461,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
let linted = wrong_transmute::check(cx, e, from_ty, to_ty) let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
| crosspointer_transmute::check(cx, e, from_ty, to_ty) | crosspointer_transmute::check(cx, e, from_ty, to_ty)
| transmuting_null::check(cx, e, arg, to_ty) | transmuting_null::check(cx, e, arg, to_ty)
| transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv) | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv)
| transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
| transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
| transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg) | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)

View file

@ -1,12 +1,12 @@
use super::TRANSMUTE_PTR_TO_REF; use super::TRANSMUTE_PTR_TO_REF;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{meets_msrv, msrvs, sugg}; use clippy_utils::sugg;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{self as hir, Expr, GenericArg, Mutability, Path, TyKind}; use rustc_hir::{self as hir, Expr, GenericArg, Mutability, Path, TyKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty, TypeVisitable}; use rustc_middle::ty::{self, Ty, TypeVisitable};
use rustc_semver::RustcVersion;
/// Checks for `transmute_ptr_to_ref` lint. /// Checks for `transmute_ptr_to_ref` lint.
/// Returns `true` if it's triggered, otherwise returns `false`. /// Returns `true` if it's triggered, otherwise returns `false`.
@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(
to_ty: Ty<'tcx>, to_ty: Ty<'tcx>,
arg: &'tcx Expr<'_>, arg: &'tcx Expr<'_>,
path: &'tcx Path<'_>, path: &'tcx Path<'_>,
msrv: Option<RustcVersion>, msrv: &Msrv,
) -> bool { ) -> bool {
match (&from_ty.kind(), &to_ty.kind()) { match (&from_ty.kind(), &to_ty.kind()) {
(ty::RawPtr(from_ptr_ty), ty::Ref(_, to_ref_ty, mutbl)) => { (ty::RawPtr(from_ptr_ty), ty::Ref(_, to_ref_ty, mutbl)) => {
@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(
let sugg = if let Some(ty) = get_explicit_type(path) { let sugg = if let Some(ty) = get_explicit_type(path) {
let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app); let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app);
if meets_msrv(msrv, msrvs::POINTER_CAST) { if msrv.meets(msrvs::POINTER_CAST) {
format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_par()) format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_par())
} else if from_ptr_ty.has_erased_regions() { } else if from_ptr_ty.has_erased_regions() {
sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string() sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string()
@ -46,7 +46,7 @@ pub(super) fn check<'tcx>(
} }
} else if from_ptr_ty.ty == *to_ref_ty { } else if from_ptr_ty.ty == *to_ref_ty {
if from_ptr_ty.has_erased_regions() { if from_ptr_ty.has_erased_regions() {
if meets_msrv(msrv, msrvs::POINTER_CAST) { if msrv.meets(msrvs::POINTER_CAST) {
format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_par()) format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_par())
} else { } else {
sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}"))) sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}")))

View file

@ -2,14 +2,14 @@
use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path}; use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path};
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{meets_msrv, msrvs, over}; use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::over;
use rustc_ast::mut_visit::*; use rustc_ast::mut_visit::*;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::{self as ast, Mutability, Pat, PatKind, PatKind::*, DUMMY_NODE_ID}; use rustc_ast::{self as ast, Mutability, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
@ -45,14 +45,13 @@ declare_clippy_lint! {
"unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`" "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`"
} }
#[derive(Clone, Copy)]
pub struct UnnestedOrPatterns { pub struct UnnestedOrPatterns {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl UnnestedOrPatterns { impl UnnestedOrPatterns {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { msrv } Self { msrv }
} }
} }
@ -61,13 +60,13 @@ impl_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]);
impl EarlyLintPass for UnnestedOrPatterns { impl EarlyLintPass for UnnestedOrPatterns {
fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) { fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) {
if meets_msrv(self.msrv, msrvs::OR_PATTERNS) { if self.msrv.meets(msrvs::OR_PATTERNS) {
lint_unnested_or_patterns(cx, &a.pat); lint_unnested_or_patterns(cx, &a.pat);
} }
} }
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
if meets_msrv(self.msrv, msrvs::OR_PATTERNS) { if self.msrv.meets(msrvs::OR_PATTERNS) {
if let ast::ExprKind::Let(pat, _, _) = &e.kind { if let ast::ExprKind::Let(pat, _, _) = &e.kind {
lint_unnested_or_patterns(cx, pat); lint_unnested_or_patterns(cx, pat);
} }
@ -75,13 +74,13 @@ impl EarlyLintPass for UnnestedOrPatterns {
} }
fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) { fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) {
if meets_msrv(self.msrv, msrvs::OR_PATTERNS) { if self.msrv.meets(msrvs::OR_PATTERNS) {
lint_unnested_or_patterns(cx, &p.pat); lint_unnested_or_patterns(cx, &p.pat);
} }
} }
fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) { fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) {
if meets_msrv(self.msrv, msrvs::OR_PATTERNS) { if self.msrv.meets(msrvs::OR_PATTERNS) {
lint_unnested_or_patterns(cx, &l.pat); lint_unnested_or_patterns(cx, &l.pat);
} }
} }

View file

@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_from_proc_macro;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::same_type_and_consts; use clippy_utils::ty::same_type_and_consts;
use clippy_utils::{is_from_proc_macro, meets_msrv, msrvs};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -14,7 +15,6 @@ use rustc_hir::{
}; };
use rustc_hir_analysis::hir_ty_to_ty; use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span; use rustc_span::Span;
@ -57,13 +57,13 @@ declare_clippy_lint! {
#[derive(Default)] #[derive(Default)]
pub struct UseSelf { pub struct UseSelf {
msrv: Option<RustcVersion>, msrv: Msrv,
stack: Vec<StackItem>, stack: Vec<StackItem>,
} }
impl UseSelf { impl UseSelf {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Msrv) -> Self {
Self { Self {
msrv, msrv,
..Self::default() ..Self::default()
@ -199,7 +199,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) { fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
if_chain! { if_chain! {
if !hir_ty.span.from_expansion(); if !hir_ty.span.from_expansion();
if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS); if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS);
if let Some(&StackItem::Check { if let Some(&StackItem::Check {
impl_id, impl_id,
in_body, in_body,
@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! { if_chain! {
if !expr.span.from_expansion(); if !expr.span.from_expansion();
if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS); if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS);
if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id); if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id);
then {} else { return; } then {} else { return; }
@ -248,7 +248,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) { fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
if_chain! { if_chain! {
if !pat.span.from_expansion(); if !pat.span.from_expansion();
if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS); if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS);
if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
// get the path from the pattern // get the path from the pattern
if let PatKind::Path(QPath::Resolved(_, path)) if let PatKind::Path(QPath::Resolved(_, path))

View file

@ -41,7 +41,7 @@ impl LateLintPass<'_> for MsrvAttrImpl {
.type_of(f.did) .type_of(f.did)
.walk() .walk()
.filter(|t| matches!(t.unpack(), GenericArgKind::Type(_))) .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
.any(|t| match_type(cx, t.expect_ty(), &paths::RUSTC_VERSION)) .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV))
}); });
if !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs)); if !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs));
then { then {

View file

@ -105,8 +105,6 @@ use rustc_middle::ty::{
layout::IntegerExt, BorrowKind, ClosureKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeVisitable, UpvarCapture, layout::IntegerExt, BorrowKind, ClosureKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeVisitable, UpvarCapture,
}; };
use rustc_middle::ty::{FloatTy, IntTy, UintTy}; use rustc_middle::ty::{FloatTy, IntTy, UintTy};
use rustc_semver::RustcVersion;
use rustc_session::Session;
use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::source_map::SourceMap; use rustc_span::source_map::SourceMap;
use rustc_span::sym; use rustc_span::sym;
@ -118,36 +116,17 @@ use crate::consts::{constant, Constant};
use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param}; use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param};
use crate::visitors::for_each_expr; use crate::visitors::for_each_expr;
pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
if let Ok(version) = RustcVersion::parse(msrv) {
return Some(version);
} else if let Some(sess) = sess {
if let Some(span) = span {
sess.span_err(span, format!("`{msrv}` is not a valid Rust version"));
}
}
None
}
pub fn meets_msrv(msrv: Option<RustcVersion>, lint_msrv: RustcVersion) -> bool {
msrv.map_or(true, |msrv| msrv.meets(lint_msrv))
}
#[macro_export] #[macro_export]
macro_rules! extract_msrv_attr { macro_rules! extract_msrv_attr {
($context:ident) => { ($context:ident) => {
fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) { fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
let sess = rustc_lint::LintContext::sess(cx); let sess = rustc_lint::LintContext::sess(cx);
match $crate::get_unique_inner_attr(sess, attrs, "msrv") { self.msrv.enter_lint_attrs(sess, attrs);
Some(msrv_attr) => { }
if let Some(msrv) = msrv_attr.value_str() {
self.msrv = $crate::parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span)); fn exit_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
} else { let sess = rustc_lint::LintContext::sess(cx);
sess.span_err(msrv_attr.span, "bad clippy attribute"); self.msrv.exit_lint_attrs(sess, attrs);
}
},
_ => (),
}
} }
}; };
} }

View file

@ -1,4 +1,11 @@
use std::sync::OnceLock;
use rustc_ast::Attribute;
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::Session;
use rustc_span::Span;
use crate::attrs::get_unique_inner_attr;
macro_rules! msrv_aliases { macro_rules! msrv_aliases {
($($major:literal,$minor:literal,$patch:literal { ($($major:literal,$minor:literal,$patch:literal {
@ -40,3 +47,97 @@ msrv_aliases! {
1,16,0 { STR_REPEAT } 1,16,0 { STR_REPEAT }
1,55,0 { SEEK_REWIND } 1,55,0 { SEEK_REWIND }
} }
fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
if let Ok(version) = RustcVersion::parse(msrv) {
return Some(version);
} else if let Some(sess) = sess {
if let Some(span) = span {
sess.span_err(span, format!("`{msrv}` is not a valid Rust version"));
}
}
None
}
/// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]`
#[derive(Debug, Clone, Default)]
pub struct Msrv {
stack: Vec<RustcVersion>,
}
impl Msrv {
fn new(initial: Option<RustcVersion>) -> Self {
Self {
stack: Vec::from_iter(initial),
}
}
fn read_inner(conf_msrv: &Option<String>, sess: &Session) -> Self {
let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION")
.ok()
.and_then(|v| parse_msrv(&v, None, None));
let clippy_msrv = conf_msrv.as_ref().and_then(|s| {
parse_msrv(s, None, None).or_else(|| {
sess.err(format!(
"error reading Clippy's configuration file. `{s}` is not a valid Rust version"
));
None
})
});
// if both files have an msrv, let's compare them and emit a warning if they differ
if let Some(cargo_msrv) = cargo_msrv
&& let Some(clippy_msrv) = clippy_msrv
&& clippy_msrv != cargo_msrv
{
sess.warn(format!(
"the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
));
}
Self::new(clippy_msrv.or(cargo_msrv))
}
/// Set the initial MSRV from the Clippy config file or from Cargo due to the `rust-version`
/// field in `Cargo.toml`
///
/// Returns a `&'static Msrv` as `Copy` types are more easily passed to the
/// `register_{late,early}_pass` callbacks
pub fn read(conf_msrv: &Option<String>, sess: &Session) -> &'static Self {
static PARSED: OnceLock<Msrv> = OnceLock::new();
PARSED.get_or_init(|| Self::read_inner(conf_msrv, sess))
}
pub fn current(&self) -> Option<RustcVersion> {
self.stack.last().copied()
}
pub fn meets(&self, required: RustcVersion) -> bool {
self.current().map_or(true, |version| version.meets(required))
}
fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option<RustcVersion> {
if let Some(msrv_attr) = get_unique_inner_attr(sess, attrs, "msrv") {
if let Some(msrv) = msrv_attr.value_str() {
return parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span));
}
sess.span_err(msrv_attr.span, "bad clippy attribute");
}
None
}
pub fn enter_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) {
if let Some(version) = Self::parse_attr(sess, attrs) {
self.stack.push(version);
}
}
pub fn exit_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) {
if Self::parse_attr(sess, attrs).is_some() {
self.stack.pop();
}
}
}

View file

@ -60,6 +60,8 @@ pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"];
#[cfg(feature = "internal")] #[cfg(feature = "internal")]
pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"]; pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"];
#[cfg(feature = "internal")]
pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"];
pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"]; pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
@ -101,8 +103,6 @@ pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"]; pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"]; pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"]; pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
#[cfg(feature = "internal")]
pub const RUSTC_VERSION: [&str; 2] = ["rustc_semver", "RustcVersion"];
pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"]; pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];

View file

@ -3,6 +3,7 @@
// of terminologies might not be relevant in the context of Clippy. Note that its behavior might // of terminologies might not be relevant in the context of Clippy. Note that its behavior might
// differ from the time of `rustc` even if the name stays the same. // differ from the time of `rustc` even if the name stays the same.
use crate::msrvs::Msrv;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::mir::{ use rustc_middle::mir::{
@ -18,7 +19,7 @@ use std::borrow::Cow;
type McfResult = Result<(), (Span, Cow<'static, str>)>; type McfResult = Result<(), (Span, Cow<'static, str>)>;
pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: Option<RustcVersion>) -> McfResult { pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) -> McfResult {
let def_id = body.source.def_id(); let def_id = body.source.def_id();
let mut current = def_id; let mut current = def_id;
loop { loop {
@ -280,7 +281,7 @@ fn check_terminator<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
body: &Body<'tcx>, body: &Body<'tcx>,
terminator: &Terminator<'tcx>, terminator: &Terminator<'tcx>,
msrv: Option<RustcVersion>, msrv: &Msrv,
) -> McfResult { ) -> McfResult {
let span = terminator.source_info.span; let span = terminator.source_info.span;
match &terminator.kind { match &terminator.kind {
@ -364,7 +365,7 @@ fn check_terminator<'tcx>(
} }
} }
fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bool { fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
tcx.is_const_fn(def_id) tcx.is_const_fn(def_id)
&& tcx.lookup_const_stability(def_id).map_or(true, |const_stab| { && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level { if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level {
@ -383,15 +384,12 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bo
let since = rustc_span::Symbol::intern(short_version); let since = rustc_span::Symbol::intern(short_version);
crate::meets_msrv( msrv.meets(RustcVersion::parse(since.as_str()).unwrap_or_else(|err| {
msrv, panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}")
RustcVersion::parse(since.as_str()).unwrap_or_else(|err| { }))
panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}")
}),
)
} else { } else {
// Unstable const fn with the feature enabled. // Unstable const fn with the feature enabled.
msrv.is_none() msrv.current().is_none()
} }
}) })
} }

View file

@ -11,9 +11,9 @@ extern crate rustc_middle;
#[macro_use] #[macro_use]
extern crate rustc_session; extern crate rustc_session;
use clippy_utils::extract_msrv_attr; use clippy_utils::extract_msrv_attr;
use clippy_utils::msrvs::Msrv;
use rustc_hir::Expr; use rustc_hir::Expr;
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
use rustc_semver::RustcVersion;
declare_lint! { declare_lint! {
pub TEST_LINT, pub TEST_LINT,
@ -22,7 +22,7 @@ declare_lint! {
} }
struct Pass { struct Pass {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl_lint_pass!(Pass => [TEST_LINT]); impl_lint_pass!(Pass => [TEST_LINT]);

View file

@ -11,9 +11,9 @@ extern crate rustc_middle;
#[macro_use] #[macro_use]
extern crate rustc_session; extern crate rustc_session;
use clippy_utils::extract_msrv_attr; use clippy_utils::extract_msrv_attr;
use clippy_utils::msrvs::Msrv;
use rustc_hir::Expr; use rustc_hir::Expr;
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
use rustc_semver::RustcVersion;
declare_lint! { declare_lint! {
pub TEST_LINT, pub TEST_LINT,
@ -22,7 +22,7 @@ declare_lint! {
} }
struct Pass { struct Pass {
msrv: Option<RustcVersion>, msrv: Msrv,
} }
impl_lint_pass!(Pass => [TEST_LINT]); impl_lint_pass!(Pass => [TEST_LINT]);

View file

@ -27,3 +27,26 @@ fn no_patch_meets() {
#![clippy::msrv = "1.43"] #![clippy::msrv = "1.43"]
let log2_10 = 3.321928094887362; let log2_10 = 3.321928094887362;
} }
// https://github.com/rust-lang/rust-clippy/issues/6920
fn scoping() {
mod m {
#![clippy::msrv = "1.42.0"]
}
// Should warn
let log2_10 = 3.321928094887362;
mod a {
#![clippy::msrv = "1.42.0"]
fn should_warn() {
#![clippy::msrv = "1.43.0"]
let log2_10 = 3.321928094887362;
}
fn should_not_warn() {
let log2_10 = 3.321928094887362;
}
}
}

View file

@ -23,5 +23,21 @@ LL | let log2_10 = 3.321928094887362;
| |
= help: consider using the constant directly = help: consider using the constant directly
error: aborting due to 3 previous errors error: approximate value of `f{32, 64}::consts::LOG2_10` found
--> $DIR/min_rust_version_attr.rs:38:19
|
LL | let log2_10 = 3.321928094887362;
| ^^^^^^^^^^^^^^^^^
|
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::LOG2_10` found
--> $DIR/min_rust_version_attr.rs:45:27
|
LL | let log2_10 = 3.321928094887362;
| ^^^^^^^^^^^^^^^^^
|
= help: consider using the constant directly
error: aborting due to 5 previous errors