Skip to content

Commit

Permalink
[WIP] add support for minimum supported rust version. fixes #6097
Browse files Browse the repository at this point in the history
add configuration option for minimum supported rust version
add msrv attribute to  lints listed in #6097
generify `LimitStack` for use in other lints
update the `cognitive_complexity` lint to use a `LimitStack<u64>`
update existing tests with the msrv attribute
  • Loading branch information
suyashb95 committed Nov 2, 2020
1 parent e298c83 commit 6d22f60
Show file tree
Hide file tree
Showing 26 changed files with 279 additions and 159 deletions.
4 changes: 2 additions & 2 deletions clippy_lints/src/cognitive_complexity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ declare_clippy_lint! {
}

pub struct CognitiveComplexity {
limit: LimitStack,
limit: LimitStack<u64>,
}

impl CognitiveComplexity {
Expand Down Expand Up @@ -74,7 +74,7 @@ impl CognitiveComplexity {
rust_cc -= ret_adjust;
}

if rust_cc > self.limit.limit() {
if rust_cc > *self.limit.limit() {
let fn_span = match kind {
FnKind::ItemFn(ident, _, _, _, _) | FnKind::Method(ident, _, _, _) => ident.span,
FnKind::Closure(_) => {
Expand Down
13 changes: 8 additions & 5 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,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 @@ -956,7 +955,8 @@ 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 msrv = conf.msrv.clone();
store.register_late_pass(move || box methods::Methods::new(String::from(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 @@ -970,7 +970,8 @@ 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());
let msrv = conf.msrv.clone();
store.register_late_pass(move || box matches::Matches::new(String::from(msrv.clone())));
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 @@ -1129,7 +1130,8 @@ 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);
let msrv = conf.msrv.clone();
store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(String::from(msrv.clone())));
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 @@ -1150,7 +1152,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
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);
let msrv = conf.msrv.clone();
store.register_late_pass(move || box manual_strip::ManualStrip::new(String::from(msrv.clone())));
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
35 changes: 32 additions & 3 deletions clippy_lints/src/manual_non_exhaustive.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use crate::utils::{snippet_opt, span_lint_and_then};
use crate::utils::{snippet_opt, span_lint_and_then, LimitStack};
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::Span;
use semver::Version;

const MANUAL_NON_EXHAUSTIVE_MSRV: &str = "1.40.0";

declare_clippy_lint! {
/// **What it does:** Checks for manual implementations of the non-exhaustive pattern.
Expand Down Expand Up @@ -55,10 +58,28 @@ 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_stack: LimitStack<String>,
}

impl ManualNonExhaustive {
#[must_use]
pub fn new(msrv: String) -> Self {
Self {
msrv_stack: LimitStack::new(msrv),
}
}
}

impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]);

impl EarlyLintPass for ManualNonExhaustive {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
if Version::parse(&self.msrv_stack.limit()) < Version::parse(MANUAL_NON_EXHAUSTIVE_MSRV) {
return;
}

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

fn enter_lint_attrs(&mut self, cx: &EarlyContext<'tcx>, attrs: &'tcx [Attribute]) {
self.msrv_stack.push_attrs(cx.sess, attrs, "msrv");
}

fn exit_lint_attrs(&mut self, cx: &EarlyContext<'tcx>, attrs: &'tcx [Attribute]) {
self.msrv_stack.pop_attrs(cx.sess, attrs, "msrv");
}
}

fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants: &[Variant]) {
Expand Down
38 changes: 33 additions & 5 deletions clippy_lints/src/manual_strip.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
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, higher, match_def_path, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then, LimitStack,
};

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;

const MANUAL_STRIP_MSRV: &str = "1.45.0";

declare_clippy_lint! {
/// **What it does:**
Expand Down Expand Up @@ -51,7 +54,20 @@ 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_stack: LimitStack<String>,
}

impl ManualStrip {
#[must_use]
pub fn new(msrv: String) -> Self {
Self {
msrv_stack: LimitStack::new(msrv),
}
}
}

impl_lint_pass!(ManualStrip => [MANUAL_STRIP]);

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

impl<'tcx> LateLintPass<'tcx> for ManualStrip {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if Version::parse(&self.msrv_stack.limit()) < Version::parse(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 +134,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
}
}
}

fn enter_lint_attrs(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
self.msrv_stack.push_attrs(cx.sess(), attrs, "msrv");
}

fn exit_lint_attrs(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
self.msrv_stack.pop_attrs(cx.sess(), attrs, "msrv");
}
}

// Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.
Expand Down
33 changes: 29 additions & 4 deletions clippy_lints/src/matches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ 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,
span_lint_and_then, LimitStack,
};
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::Symbol;
use semver::Version;
use std::cmp::Ordering;
use std::collections::hash_map::Entry;
use std::collections::Bound;
Expand Down Expand Up @@ -521,9 +522,20 @@ declare_clippy_lint! {

#[derive(Default)]
pub struct Matches {
msrv_stack: LimitStack<String>,
infallible_destructuring_match_linted: bool,
}

impl Matches {
#[must_use]
pub fn new(msrv: String) -> Self {
Self {
msrv_stack: LimitStack::new(msrv),
..Default::default()
}
}
}

impl_lint_pass!(Matches => [
SINGLE_MATCH,
MATCH_REF_PATS,
Expand All @@ -543,15 +555,20 @@ impl_lint_pass!(Matches => [
MATCH_SAME_ARMS,
]);

const MATCH_LIKE_MATCHES_MACRO_MSRV: &str = "1.42.0";

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

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

if Version::parse(&self.msrv_stack.limit()) >= Version::parse(MATCH_LIKE_MATCHES_MACRO_MSRV) {
if !check_match_like_matches(cx, expr) {
lint_match_arms(cx, expr);
}
}

if let ExprKind::Match(ref ex, ref arms, MatchSource::Normal) = expr.kind {
Expand Down Expand Up @@ -634,6 +651,14 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
}
}
}

fn enter_lint_attrs(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
self.msrv_stack.push_attrs(cx.sess(), attrs, "msrv");
}

fn exit_lint_attrs(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
self.msrv_stack.pop_attrs(cx.sess(), attrs, "msrv");
}
}

#[rustfmt::skip]
Expand Down
43 changes: 38 additions & 5 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,9 +21,10 @@ 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 semver::Version;

use crate::consts::{constant, Constant};
use crate::utils::eager_or_lazy::is_lazyness_candidate;
Expand All @@ -32,7 +34,8 @@ use crate::utils::{
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,
span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth,
LimitStack, SpanlessEq,
};

declare_clippy_lint! {
Expand Down Expand Up @@ -1369,7 +1372,20 @@ declare_clippy_lint! {
"using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`"
}

declare_lint_pass!(Methods => [
pub struct Methods {
msrv_stack: LimitStack<String>,
}

impl Methods {
#[must_use]
pub fn new(msrv: String) -> Self {
Self {
msrv_stack: LimitStack::new(msrv.clone()),
}
}
}

impl_lint_pass!(Methods => [
UNWRAP_USED,
EXPECT_USED,
SHOULD_IMPLEMENT_TRAIT,
Expand Down Expand Up @@ -1495,8 +1511,10 @@ 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_stack)
},
["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true, &self.msrv_stack),
["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 @@ -1693,6 +1711,14 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
}
}
}

fn enter_lint_attrs(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
self.msrv_stack.push_attrs(cx.sess(), attrs, "msrv");
}

fn exit_lint_attrs(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
self.msrv_stack.pop_attrs(cx.sess(), attrs, "msrv");
}
}

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

const OPTION_AS_REF_DEREF_MSRV: &str = "1.40.0";

/// 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_stack: &LimitStack<String>,
) {
if Version::parse(&msrv_stack.limit()) < Version::parse(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 6d22f60

Please sign in to comment.