Skip to content

Commit

Permalink
add support for minimum supported rust version.
Browse files Browse the repository at this point in the history
add configuration option for minimum supported rust version
add msrv attribute to some lints listed in #6097
add tests
  • Loading branch information
suyashb95 authored and flip1995 committed Nov 25, 2020
1 parent f897d27 commit aaa4325
Show file tree
Hide file tree
Showing 20 changed files with 390 additions and 29 deletions.
23 changes: 18 additions & 5 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ extern crate rustc_target;
extern crate rustc_trait_selection;
extern crate rustc_typeck;

use crate::utils::parse_msrv;
use rustc_data_structures::fx::FxHashSet;
use rustc_lint::LintId;
use rustc_session::Session;
Expand Down Expand Up @@ -933,7 +934,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&zero_div_zero::ZERO_DIVIDED_BY_ZERO,
]);
// end register lints, do not remove this comment, it’s used in `update_lints`

store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
store.register_late_pass(|| box serde_api::SerdeAPI);
store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
Expand Down Expand Up @@ -969,7 +969,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box strings::StringAdd);
store.register_late_pass(|| box implicit_return::ImplicitReturn);
store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
store.register_late_pass(|| box methods::Methods);

let parsed_msrv = conf.msrv.as_ref().and_then(|s| {
parse_msrv(s, None, None).or_else(|| {
sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
None
})
});

let msrv = parsed_msrv.clone();
store.register_late_pass(move || box methods::Methods::new(msrv.clone()));
let msrv = parsed_msrv.clone();
store.register_late_pass(move || box matches::Matches::new(msrv.clone()));
let msrv = parsed_msrv.clone();
store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv.clone()));
let msrv = parsed_msrv;
store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv.clone()));

store.register_late_pass(|| box map_clone::MapClone);
store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
store.register_late_pass(|| box shadow::Shadow);
Expand All @@ -983,7 +999,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box types::Casts);
let type_complexity_threshold = conf.type_complexity_threshold;
store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold));
store.register_late_pass(|| box matches::Matches::default());
store.register_late_pass(|| box minmax::MinMaxPass);
store.register_late_pass(|| box open_options::OpenOptions);
store.register_late_pass(|| box zero_div_zero::ZeroDiv);
Expand Down Expand Up @@ -1144,7 +1159,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box if_let_mutex::IfLetMutex);
store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive);
store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
store.register_early_pass(|| box redundant_field_names::RedundantFieldNames);
store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
Expand All @@ -1166,7 +1180,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box manual_ok_or::ManualOkOr);
store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
store.register_late_pass(|| box manual_strip::ManualStrip);
store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
Expand Down
33 changes: 30 additions & 3 deletions clippy_lints/src/manual_non_exhaustive.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
use crate::utils::{snippet_opt, span_lint_and_then};
use crate::utils::{get_inner_attr, meets_msrv, snippet_opt, span_lint_and_then};
use if_chain::if_chain;
use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantData, VisibilityKind};
use rustc_attr as attr;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
use semver::{Version, VersionReq};

const MANUAL_NON_EXHAUSTIVE_MSRV: Version = Version {
major: 1,
minor: 40,
patch: 0,
pre: Vec::new(),
build: Vec::new(),
};

declare_clippy_lint! {
/// **What it does:** Checks for manual implementations of the non-exhaustive pattern.
Expand Down Expand Up @@ -55,10 +64,26 @@ declare_clippy_lint! {
"manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]"
}

declare_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]);
#[derive(Clone)]
pub struct ManualNonExhaustive {
msrv: Option<VersionReq>,
}

impl ManualNonExhaustive {
#[must_use]
pub fn new(msrv: Option<VersionReq>) -> Self {
Self { msrv }
}
}

impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]);

impl EarlyLintPass for ManualNonExhaustive {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
if !meets_msrv(self.msrv.as_ref(), &MANUAL_NON_EXHAUSTIVE_MSRV) {
return;
}

match &item.kind {
ItemKind::Enum(def, _) => {
check_manual_non_exhaustive_enum(cx, item, &def.variants);
Expand All @@ -73,6 +98,8 @@ impl EarlyLintPass for ManualNonExhaustive {
_ => {},
}
}

extract_msrv_attr!(EarlyContext);
}

fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants: &[Variant]) {
Expand Down
37 changes: 32 additions & 5 deletions clippy_lints/src/manual_strip.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
use crate::consts::{constant, Constant};
use crate::utils::usage::mutated_variables;
use crate::utils::{
eq_expr_value, higher, match_def_path, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then,
eq_expr_value, get_inner_attr, higher, match_def_path, meets_msrv, multispan_sugg, paths, qpath_res, snippet,
span_lint_and_then,
};

use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_ast::ast::{Attribute, LitKind};
use rustc_hir::def::Res;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::BinOpKind;
use rustc_hir::{BorrowKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Spanned;
use rustc_span::Span;
use semver::{Version, VersionReq};

const MANUAL_STRIP_MSRV: Version = Version {
major: 1,
minor: 45,
patch: 0,
pre: Vec::new(),
build: Vec::new(),
};

declare_clippy_lint! {
/// **What it does:**
Expand Down Expand Up @@ -51,7 +61,18 @@ declare_clippy_lint! {
"suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing"
}

declare_lint_pass!(ManualStrip => [MANUAL_STRIP]);
pub struct ManualStrip {
msrv: Option<VersionReq>,
}

impl ManualStrip {
#[must_use]
pub fn new(msrv: Option<VersionReq>) -> Self {
Self { msrv }
}
}

impl_lint_pass!(ManualStrip => [MANUAL_STRIP]);

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum StripKind {
Expand All @@ -61,6 +82,10 @@ enum StripKind {

impl<'tcx> LateLintPass<'tcx> for ManualStrip {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) {
return;
}

if_chain! {
if let Some((cond, then, _)) = higher::if_block(&expr);
if let ExprKind::MethodCall(_, _, [target_arg, pattern], _) = cond.kind;
Expand Down Expand Up @@ -114,6 +139,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
}
}
}

extract_msrv_attr!(LateContext);
}

// Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.
Expand Down
39 changes: 33 additions & 6 deletions clippy_lints/src/matches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ use crate::consts::{constant, miri_to_const, Constant};
use crate::utils::sugg::Sugg;
use crate::utils::usage::is_unused;
use crate::utils::{
expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable,
is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, multispan_sugg, remove_blocks, snippet,
snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
span_lint_and_then,
expr_block, get_arg_name, get_inner_attr, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of,
is_refutable, is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg,
remove_blocks, snippet, snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note,
span_lint_and_sugg, span_lint_and_then,
};
use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_ast::ast::{Attribute, LitKind};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_hir::def::CtorKind;
Expand All @@ -23,6 +23,7 @@ use rustc_middle::ty::{self, Ty, TyS};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::{Span, Spanned};
use rustc_span::{sym, Symbol};
use semver::{Version, VersionReq};
use std::cmp::Ordering;
use std::collections::hash_map::Entry;
use std::collections::Bound;
Expand Down Expand Up @@ -527,9 +528,20 @@ declare_clippy_lint! {

#[derive(Default)]
pub struct Matches {
msrv: Option<VersionReq>,
infallible_destructuring_match_linted: bool,
}

impl Matches {
#[must_use]
pub fn new(msrv: Option<VersionReq>) -> Self {
Self {
msrv,
..Matches::default()
}
}
}

impl_lint_pass!(Matches => [
SINGLE_MATCH,
MATCH_REF_PATS,
Expand All @@ -549,14 +561,27 @@ impl_lint_pass!(Matches => [
MATCH_SAME_ARMS,
]);

const MATCH_LIKE_MATCHES_MACRO_MSRV: Version = Version {
major: 1,
minor: 42,
patch: 0,
pre: Vec::new(),
build: Vec::new(),
};

impl<'tcx> LateLintPass<'tcx> for Matches {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) {
return;
}

redundant_pattern_match::check(cx, expr);
if !check_match_like_matches(cx, expr) {

if meets_msrv(self.msrv.as_ref(), &MATCH_LIKE_MATCHES_MACRO_MSRV) {
if !check_match_like_matches(cx, expr) {
lint_match_arms(cx, expr);
}
} else {
lint_match_arms(cx, expr);
}

Expand Down Expand Up @@ -640,6 +665,8 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
}
}
}

extract_msrv_attr!(LateContext);
}

#[rustfmt::skip]
Expand Down
51 changes: 42 additions & 9 deletions clippy_lints/src/methods/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::iter;
use bind_instead_of_map::BindInsteadOfMap;
use if_chain::if_chain;
use rustc_ast::ast;
use rustc_ast::ast::Attribute;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
Expand All @@ -20,20 +21,22 @@ use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, TraitRef, Ty, TyS};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::symbol::{sym, SymbolStr};

use crate::consts::{constant, Constant};
use crate::utils::eager_or_lazy::is_lazyness_candidate;
use crate::utils::usage::mutated_variables;
use crate::utils::{
contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro,
is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath,
match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty,
single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq,
contains_ty, get_arg_name, get_inner_attr, get_parent_expr, get_trait_def_id, has_iter_method, higher,
implements_trait, in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment,
match_def_path, match_qpath, match_trait_method, match_type, match_var, meets_msrv, method_calls,
method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability,
snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg,
walk_ptrs_ty_depth, SpanlessEq,
};
use semver::{Version, VersionReq};

declare_clippy_lint! {
/// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s.
Expand Down Expand Up @@ -1404,7 +1407,18 @@ declare_clippy_lint! {
"use `.collect()` instead of `::from_iter()`"
}

declare_lint_pass!(Methods => [
pub struct Methods {
msrv: Option<VersionReq>,
}

impl Methods {
#[must_use]
pub fn new(msrv: Option<VersionReq>) -> Self {
Self { msrv }
}
}

impl_lint_pass!(Methods => [
UNWRAP_USED,
EXPECT_USED,
SHOULD_IMPLEMENT_TRAIT,
Expand Down Expand Up @@ -1531,8 +1545,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
check_pointer_offset(cx, expr, arg_lists[0])
},
["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]),
["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false),
["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true),
["map", "as_ref"] => {
lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref())
},
["map", "as_mut"] => {
lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref())
},
["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"),
["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"),
["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"),
Expand Down Expand Up @@ -1738,6 +1756,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
}
}
}

extract_msrv_attr!(LateContext);
}

/// Checks for the `OR_FUN_CALL` lint.
Expand Down Expand Up @@ -3453,14 +3473,27 @@ fn lint_suspicious_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
);
}

const OPTION_AS_REF_DEREF_MSRV: Version = Version {
major: 1,
minor: 40,
patch: 0,
pre: Vec::new(),
build: Vec::new(),
};

/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
fn lint_option_as_ref_deref<'tcx>(
cx: &LateContext<'tcx>,
expr: &hir::Expr<'_>,
as_ref_args: &[hir::Expr<'_>],
map_args: &[hir::Expr<'_>],
is_mut: bool,
msrv: Option<&VersionReq>,
) {
if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) {
return;
}

let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);

let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]);
Expand Down
Loading

0 comments on commit aaa4325

Please sign in to comment.