Draft skeleton for new lint

This commit is contained in:
nahuakang 2021-01-27 09:34:59 +01:00
parent 949b125891
commit 5753614152
3 changed files with 68 additions and 0 deletions

View file

@ -1969,6 +1969,7 @@ Released 2018-09-13
[`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
[`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map
[`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
[`for_loops_over_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_options
[`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect

View file

@ -685,6 +685,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&loops::EXPLICIT_ITER_LOOP,
&loops::FOR_KV_MAP,
&loops::FOR_LOOPS_OVER_FALLIBLES,
&loops::FOR_LOOPS_OVER_OPTIONS,
&loops::ITER_NEXT_LOOP,
&loops::MANUAL_MEMCPY,
&loops::MUT_RANGE_BOUND,
@ -1488,6 +1489,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&loops::EXPLICIT_COUNTER_LOOP),
LintId::of(&loops::FOR_KV_MAP),
LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES),
LintId::of(&loops::FOR_LOOPS_OVER_OPTIONS),
LintId::of(&loops::ITER_NEXT_LOOP),
LintId::of(&loops::MANUAL_MEMCPY),
LintId::of(&loops::MUT_RANGE_BOUND),
@ -1820,6 +1822,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES),
LintId::of(&lifetimes::NEEDLESS_LIFETIMES),
LintId::of(&loops::EXPLICIT_COUNTER_LOOP),
LintId::of(&loops::FOR_LOOPS_OVER_OPTIONS),
LintId::of(&loops::MUT_RANGE_BOUND),
LintId::of(&loops::SINGLE_ELEMENT_LOOP),
LintId::of(&loops::WHILE_LET_LOOP),

View file

@ -494,6 +494,37 @@ declare_clippy_lint! {
"there is no reason to have a single element loop"
}
declare_clippy_lint! {
/// **What it does:** Checks for iteration of `Option`s with
/// a single `if let Some()` expression inside.
///
/// **Why is this bad?** It is verbose and can be simplified
/// by first calling the `flatten` method on the `Iterator`.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// let x = vec![Some(1), Some(2), Some(3)];
/// for n in x {
/// if let Some(n) = n {
/// println!("{}", n);
/// }
/// }
/// ```
/// Use instead:
/// ```rust
/// let x = vec![Some(1), Some(2), Some(3)];
/// for n in x.iter().flatten() {
/// println!("{}", n);
/// }
/// ```
pub FOR_LOOPS_OVER_OPTIONS,
complexity,
"for loops over `Option`s or `Result`s with a single expression can be simplified"
}
declare_lint_pass!(Loops => [
MANUAL_MEMCPY,
NEEDLESS_RANGE_LOOP,
@ -501,6 +532,7 @@ declare_lint_pass!(Loops => [
EXPLICIT_INTO_ITER_LOOP,
ITER_NEXT_LOOP,
FOR_LOOPS_OVER_FALLIBLES,
FOR_LOOPS_OVER_OPTIONS,
WHILE_LET_LOOP,
NEEDLESS_COLLECT,
EXPLICIT_COUNTER_LOOP,
@ -830,6 +862,7 @@ fn check_for_loop<'tcx>(
check_for_mut_range_bound(cx, arg, body);
check_for_single_element_loop(cx, pat, arg, body, expr);
detect_same_item_push(cx, pat, arg, body, expr);
check_for_loop_over_options_or_results(cx, pat, arg, body, expr);
}
// this function assumes the given expression is a `for` loop.
@ -1953,6 +1986,37 @@ fn check_for_single_element_loop<'tcx>(
}
}
/// Check if a for loop loops over `Option`s or `Result`s and contains only
/// a `if let Some` or `if let Ok` expression.
fn check_for_loop_over_options_or_results<'tcx>(
cx: &LateContext<'tcx>,
pat: &'tcx Pat<'_>,
arg: &'tcx Expr<'_>,
body: &'tcx Expr<'_>,
expr: &'tcx Expr<'_>,
) {
if_chain! {
if let ExprKind::Block(ref block, _) = body.kind;
if block.stmts.is_empty();
if let Some(inner_expr) = block.expr;
if let ExprKind::Match(ref _match_expr, ref _match_arms, MatchSource::IfLetDesugar{ contains_else_clause }) = inner_expr.kind;
if !contains_else_clause;
then {
// println!("if_let_expr:\n{:?}", snippet(cx, if_let_expr.span, ".."));
// println!("pat is:\n {:?}", snippet(cx, pat.span, ".."));
// println!("arg is:\n {:?}", snippet(cx, arg.span, ".."));
// println!("body is:\n {:?}", snippet(cx, body.span, ".."));
// println!("arg kind is: {:?}", arg.kind);
// println!("expr is:\n {:?}", snippet(cx, expr.span, ".."));
// todo!();
let arg_snippet = snippet(cx, arg.span, "..");
let msg = "looping over `Option`s or `Result`s with an `if let` expression.";
let hint = format!("try turn {} into an `Iterator` and use `flatten`: `{}.iter().flatten()`", arg_snippet, arg_snippet);
span_lint_and_help(cx, FOR_LOOPS_OVER_OPTIONS, expr.span, msg, None, &hint);
}
}
}
struct MutatePairDelegate<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
hir_id_low: Option<HirId>,