From 949b12589112cecad9566305444527ec0738d521 Mon Sep 17 00:00:00 2001 From: nahuakang Date: Wed, 27 Jan 2021 09:34:36 +0100 Subject: [PATCH 01/72] Add unit tests for new lint --- tests/ui/for_loops_over_options.rs | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/ui/for_loops_over_options.rs diff --git a/tests/ui/for_loops_over_options.rs b/tests/ui/for_loops_over_options.rs new file mode 100644 index 0000000000000..d8144864a219d --- /dev/null +++ b/tests/ui/for_loops_over_options.rs @@ -0,0 +1,31 @@ +#![warn(clippy::for_loops_over_options)] + +fn main() { + let x = vec![Some(1), Some(2), Some(3)]; + for n in x { + if let Some(n) = n { + println!("{}", n); + } + } + + let y: Vec> = vec![]; + for n in y.clone() { + if let Ok(n) = n { + println!("{}", n); + } + } + + // This should not trigger the lint + for n in y.clone() { + if let Ok(n) = n { + println!("{}", n); + } else { + println!("Oops!"); + } + } + + // This should not trigger the lint + for n in vec![Some(1), Some(2), Some(3)].iter().flatten() { + println!("{}", n); + } +} From 5753614152b4c6d9c0d20bc311a335c4746c3ed0 Mon Sep 17 00:00:00 2001 From: nahuakang Date: Wed, 27 Jan 2021 09:34:59 +0100 Subject: [PATCH 02/72] Draft skeleton for new lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 ++ clippy_lints/src/loops.rs | 64 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dadb6832d1fd7..e8e738313d450 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 54007c29c6c5e..3793208735540 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -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), diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 5211ca7da323a..c1a59650cb04c 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -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, From 3da25ed955baffe8c14cee4950762d268f1b48e7 Mon Sep 17 00:00:00 2001 From: nahuakang Date: Wed, 27 Jan 2021 09:49:53 +0100 Subject: [PATCH 03/72] Rename lint --- CHANGELOG.md | 3 ++- clippy_lints/src/lib.rs | 6 +++--- clippy_lints/src/loops.rs | 6 +++--- ...over_options.rs => for_loops_over_options_or_results.rs} | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) rename tests/ui/{for_loops_over_options.rs => for_loops_over_options_or_results.rs} (92%) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8e738313d450..4bd04ffbd99c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1969,7 +1969,8 @@ 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 +[`for_loops_over_options_or_results`]: +https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_options_or_results [`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 diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3793208735540..dae6c93c7cb9b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -685,7 +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::FOR_LOOPS_OVER_OPTIONS_OR_RESULTS, &loops::ITER_NEXT_LOOP, &loops::MANUAL_MEMCPY, &loops::MUT_RANGE_BOUND, @@ -1489,7 +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::FOR_LOOPS_OVER_OPTIONS_OR_RESULTS), LintId::of(&loops::ITER_NEXT_LOOP), LintId::of(&loops::MANUAL_MEMCPY), LintId::of(&loops::MUT_RANGE_BOUND), @@ -1822,7 +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::FOR_LOOPS_OVER_OPTIONS_OR_RESULTS), LintId::of(&loops::MUT_RANGE_BOUND), LintId::of(&loops::SINGLE_ELEMENT_LOOP), LintId::of(&loops::WHILE_LET_LOOP), diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index c1a59650cb04c..e9047cce15f9a 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -520,7 +520,7 @@ declare_clippy_lint! { /// println!("{}", n); /// } /// ``` - pub FOR_LOOPS_OVER_OPTIONS, + pub FOR_LOOPS_OVER_OPTIONS_OR_RESULTS, complexity, "for loops over `Option`s or `Result`s with a single expression can be simplified" } @@ -532,7 +532,7 @@ declare_lint_pass!(Loops => [ EXPLICIT_INTO_ITER_LOOP, ITER_NEXT_LOOP, FOR_LOOPS_OVER_FALLIBLES, - FOR_LOOPS_OVER_OPTIONS, + FOR_LOOPS_OVER_OPTIONS_OR_RESULTS, WHILE_LET_LOOP, NEEDLESS_COLLECT, EXPLICIT_COUNTER_LOOP, @@ -2012,7 +2012,7 @@ fn check_for_loop_over_options_or_results<'tcx>( 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); + span_lint_and_help(cx, FOR_LOOPS_OVER_OPTIONS_OR_RESULTS, expr.span, msg, None, &hint); } } } diff --git a/tests/ui/for_loops_over_options.rs b/tests/ui/for_loops_over_options_or_results.rs similarity index 92% rename from tests/ui/for_loops_over_options.rs rename to tests/ui/for_loops_over_options_or_results.rs index d8144864a219d..02e24b250f796 100644 --- a/tests/ui/for_loops_over_options.rs +++ b/tests/ui/for_loops_over_options_or_results.rs @@ -1,4 +1,4 @@ -#![warn(clippy::for_loops_over_options)] +#![warn(clippy::for_loops_over_options_or_results)] fn main() { let x = vec![Some(1), Some(2), Some(3)]; From 8973f2c03a87802ba266f1e3e08e6b4cf7f96b8c Mon Sep 17 00:00:00 2001 From: nahuakang Date: Wed, 27 Jan 2021 09:56:56 +0100 Subject: [PATCH 04/72] Run cargo dev update_lints --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bd04ffbd99c9..e40cd8174fc2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1969,8 +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_or_results`]: -https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_options_or_results +[`for_loops_over_options_or_results`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_options_or_results [`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 From b87e189694eebb5b83d758528032cf4d4db81472 Mon Sep 17 00:00:00 2001 From: nahuakang Date: Fri, 29 Jan 2021 01:38:34 +0100 Subject: [PATCH 05/72] Implement manual flatten lint --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 6 +- clippy_lints/src/loops.rs | 85 +++++++++++++------ clippy_lints/src/mut_mut.rs | 2 +- clippy_lints/src/needless_question_mark.rs | 26 +----- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/utils/higher.rs | 9 +- clippy_lints/src/utils/internal_lints.rs | 16 ++-- clippy_lints/src/utils/mod.rs | 28 +++++- clippy_lints/src/vec.rs | 2 +- tests/ui/for_loops_over_options_or_results.rs | 31 ------- tests/ui/manual_flatten.rs | 54 ++++++++++++ tests/ui/manual_flatten.stderr | 51 +++++++++++ 13 files changed, 208 insertions(+), 106 deletions(-) delete mode 100644 tests/ui/for_loops_over_options_or_results.rs create mode 100644 tests/ui/manual_flatten.rs create mode 100644 tests/ui/manual_flatten.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index e40cd8174fc2d..aceabcbbdfc8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1969,7 +1969,6 @@ 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_or_results`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_options_or_results [`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 @@ -2040,6 +2039,7 @@ Released 2018-09-13 [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map +[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dae6c93c7cb9b..cd0a95a45857a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -685,8 +685,8 @@ 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_OR_RESULTS, &loops::ITER_NEXT_LOOP, + &loops::MANUAL_FLATTEN, &loops::MANUAL_MEMCPY, &loops::MUT_RANGE_BOUND, &loops::NEEDLESS_COLLECT, @@ -1489,8 +1489,8 @@ 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_OR_RESULTS), LintId::of(&loops::ITER_NEXT_LOOP), + LintId::of(&loops::MANUAL_FLATTEN), LintId::of(&loops::MANUAL_MEMCPY), LintId::of(&loops::MUT_RANGE_BOUND), LintId::of(&loops::NEEDLESS_COLLECT), @@ -1822,7 +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_OR_RESULTS), + LintId::of(&loops::MANUAL_FLATTEN), LintId::of(&loops::MUT_RANGE_BOUND), LintId::of(&loops::SINGLE_ELEMENT_LOOP), LintId::of(&loops::WHILE_LET_LOOP), diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index e9047cce15f9a..db5aec82e90c2 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -5,10 +5,10 @@ use crate::utils::usage::{is_unused, mutated_variables}; use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, - indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, - last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, 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, SpanlessEq, + indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_ok_ctor, is_refutable, is_some_ctor, + is_type_diagnostic_item, last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, + 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, SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast; @@ -495,8 +495,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for iteration of `Option`s with - /// a single `if let Some()` expression inside. + /// **What it does:** Check for unnecessary `if let` usage in a for loop + /// where only the `Some` or `Ok` variant of the iterator element is used. /// /// **Why is this bad?** It is verbose and can be simplified /// by first calling the `flatten` method on the `Iterator`. @@ -516,23 +516,23 @@ declare_clippy_lint! { /// Use instead: /// ```rust /// let x = vec![Some(1), Some(2), Some(3)]; - /// for n in x.iter().flatten() { + /// for n in x.into_iter().flatten() { /// println!("{}", n); /// } /// ``` - pub FOR_LOOPS_OVER_OPTIONS_OR_RESULTS, + pub MANUAL_FLATTEN, complexity, "for loops over `Option`s or `Result`s with a single expression can be simplified" } declare_lint_pass!(Loops => [ MANUAL_MEMCPY, + MANUAL_FLATTEN, NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, EXPLICIT_INTO_ITER_LOOP, ITER_NEXT_LOOP, FOR_LOOPS_OVER_FALLIBLES, - FOR_LOOPS_OVER_OPTIONS_OR_RESULTS, WHILE_LET_LOOP, NEEDLESS_COLLECT, EXPLICIT_COUNTER_LOOP, @@ -549,14 +549,14 @@ declare_lint_pass!(Loops => [ impl<'tcx> LateLintPass<'tcx> for Loops { #[allow(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some((pat, arg, body)) = higher::for_loop(expr) { + if let Some((pat, arg, body, span)) = higher::for_loop(expr) { // we don't want to check expanded macros // this check is not at the top of the function // since higher::for_loop expressions are marked as expansions if body.span.from_expansion() { return; } - check_for_loop(cx, pat, arg, body, expr); + check_for_loop(cx, pat, arg, body, expr, span); } // we don't want to check expanded macros @@ -851,6 +851,7 @@ fn check_for_loop<'tcx>( arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>, expr: &'tcx Expr<'_>, + span: Span, ) { let is_manual_memcpy_triggered = detect_manual_memcpy(cx, pat, arg, body, expr); if !is_manual_memcpy_triggered { @@ -862,7 +863,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); + check_manual_flatten(cx, pat, arg, body, span); } // this function assumes the given expression is a `for` loop. @@ -1986,33 +1987,61 @@ 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>( +/// Check for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the +/// iterator element is used. +fn check_manual_flatten<'tcx>( cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>, - expr: &'tcx Expr<'_>, + span: Span, ) { if_chain! { + // Ensure the `if let` statement is the only expression in the for-loop 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; + if let ExprKind::Match( + ref match_expr, ref match_arms, MatchSource::IfLetDesugar{ contains_else_clause: false } + ) = inner_expr.kind; + // Ensure match_expr in `if let` statement is the same as the pat from the for-loop + if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind; + if let ExprKind::Path(QPath::Resolved(None, match_expr_path)) = match_expr.kind; + if let Res::Local(match_expr_path_id) = match_expr_path.res; + if pat_hir_id == match_expr_path_id; + // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result` + if let PatKind::TupleStruct(QPath::Resolved(None, path), _, _) = match_arms[0].pat.kind; + if is_some_ctor(cx, path.res) || is_ok_ctor(cx, path.res); + let if_let_type = if is_some_ctor(cx, path.res) { + "Some" + } else { + "Ok" + }; + // Determine if `arg` is `Iterator` or implicitly calls `into_iter` + let arg_ty = cx.typeck_results().expr_ty(arg); + if let Some(id) = get_trait_def_id(cx, &paths::ITERATOR); + if let is_iterator = implements_trait(cx, arg_ty, id, &[]); + 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!(); + // Prepare the error message + let msg = format!("Unnecessary `if let` since only the `{}` variant of the iterator element is used.", if_let_type); + + // Prepare the help message 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_OR_RESULTS, expr.span, msg, None, &hint); + let hint = if is_iterator { + format!("try: `{}.flatten()`", arg_snippet) + } else { + format!("try: `{}.into_iter().flatten()`", arg_snippet) + }; + + span_lint_and_help( + cx, + MANUAL_FLATTEN, + span, + &msg, + Some(arg.span), + &hint, + ); } } } diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 2f3cdb894f01c..d7239b328bbcd 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -52,7 +52,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { return; } - if let Some((_, arg, body)) = higher::for_loop(expr) { + if let Some((_, arg, body, _)) = higher::for_loop(expr) { // A `for` loop lowers to: // ```rust // match ::std::iter::Iterator::next(&mut iter) { diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 9e9b79ee1cf08..fe8d4d07abc15 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -1,8 +1,6 @@ use rustc_errors::Applicability; -use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::DefIdTree; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; @@ -160,7 +158,7 @@ fn is_some_or_ok_call<'a>( // Check outer expression matches CALL_IDENT(ARGUMENT) format if let ExprKind::Call(path, args) = &expr.kind; if let ExprKind::Path(QPath::Resolved(None, path)) = &path.kind; - if is_some_ctor(cx, path.res) || is_ok_ctor(cx, path.res); + if utils::is_some_ctor(cx, path.res) || utils::is_ok_ctor(cx, path.res); // Extract inner expression from ARGUMENT if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &args[0].kind; @@ -208,25 +206,3 @@ fn is_some_or_ok_call<'a>( fn has_implicit_error_from(cx: &LateContext<'_>, entire_expr: &Expr<'_>, inner_result_expr: &Expr<'_>) -> bool { return cx.typeck_results().expr_ty(entire_expr) != cx.typeck_results().expr_ty(inner_result_expr); } - -fn is_ok_ctor(cx: &LateContext<'_>, res: Res) -> bool { - if let Some(ok_id) = cx.tcx.lang_items().result_ok_variant() { - if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res { - if let Some(variant_id) = cx.tcx.parent(id) { - return variant_id == ok_id; - } - } - } - false -} - -fn is_some_ctor(cx: &LateContext<'_>, res: Res) -> bool { - if let Some(some_id) = cx.tcx.lang_items().option_some_variant() { - if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res { - if let Some(variant_id) = cx.tcx.parent(id) { - return variant_id == some_id; - } - } - } - false -} diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 3e454eecd970e..59503817c0fcc 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -442,7 +442,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { let mut cur_expr = expr; while let Some(parent_expr) = get_parent_expr(cx, cur_expr) { match higher::for_loop(parent_expr) { - Some((_, args, _)) if args.hir_id == expr.hir_id => return true, + Some((_, args, _, _)) if args.hir_id == expr.hir_id => return true, _ => cur_expr = parent_expr, } } diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 340d340d6d340..df7f0f9578218 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -9,6 +9,7 @@ use rustc_ast::ast; use rustc_hir as hir; use rustc_hir::{BorrowKind, Expr, ExprKind, StmtKind, UnOp}; use rustc_lint::LateContext; +use rustc_span::source_map::Span; /// Converts a hir binary operator to the corresponding `ast` type. #[must_use] @@ -133,11 +134,11 @@ pub fn is_from_for_desugar(local: &hir::Local<'_>) -> bool { false } -/// Recover the essential nodes of a desugared for loop: -/// `for pat in arg { body }` becomes `(pat, arg, body)`. +/// Recover the essential nodes of a desugared for loop as well as the entire span: +/// `for pat in arg { body }` becomes `(pat, arg, body)`. Return `(pat, arg, body, span)`. pub fn for_loop<'tcx>( expr: &'tcx hir::Expr<'tcx>, -) -> Option<(&hir::Pat<'_>, &'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>)> { +) -> Option<(&hir::Pat<'_>, &'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>, Span)> { if_chain! { if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind; if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind; @@ -148,7 +149,7 @@ pub fn for_loop<'tcx>( if let hir::StmtKind::Local(ref local) = let_stmt.kind; if let hir::StmtKind::Expr(ref expr) = body.kind; then { - return Some((&*local.pat, &iterargs[0], expr)); + return Some((&*local.pat, &iterargs[0], expr, arms[0].span)); } } None diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 822863ca3e279..b3eae93306211 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -841,15 +841,13 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { // implementations of native types. Check lang items. let path_syms: Vec<_> = path.iter().map(|p| Symbol::intern(p)).collect(); let lang_items = cx.tcx.lang_items(); - for lang_item in lang_items.items() { - if let Some(def_id) = lang_item { - let lang_item_path = cx.get_def_path(*def_id); - if path_syms.starts_with(&lang_item_path) { - if let [item] = &path_syms[lang_item_path.len()..] { - for child in cx.tcx.item_children(*def_id) { - if child.ident.name == *item { - return true; - } + for item_def_id in lang_items.items().iter().flatten() { + let lang_item_path = cx.get_def_path(*item_def_id); + if path_syms.starts_with(&lang_item_path) { + if let [item] = &path_syms[lang_item_path.len()..] { + for child in cx.tcx.item_children(*item_def_id) { + if child.ident.name == *item { + return true; } } } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index d0db3a67533bc..3390c71dd8ecb 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -37,7 +37,7 @@ use rustc_ast::ast::{self, Attribute, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::Node; @@ -50,7 +50,7 @@ use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::exports::Export; use rustc_middle::hir::map::Map; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, layout::IntegerExt, DefIdTree, Ty, TyCtxt, TypeFoldable}; use rustc_semver::RustcVersion; use rustc_session::Session; use rustc_span::hygiene::{ExpnKind, MacroKind}; @@ -1700,6 +1700,30 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { } } +/// Check if the resolution of a given path is an `Ok` variant of `Result`. +pub fn is_ok_ctor(cx: &LateContext<'_>, res: Res) -> bool { + if let Some(ok_id) = cx.tcx.lang_items().result_ok_variant() { + if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res { + if let Some(variant_id) = cx.tcx.parent(id) { + return variant_id == ok_id; + } + } + } + false +} + +/// Check if the resolution of a given path is a `Some` variant of `Option`. +pub fn is_some_ctor(cx: &LateContext<'_>, res: Res) -> bool { + if let Some(some_id) = cx.tcx.lang_items().option_some_variant() { + if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res { + if let Some(variant_id) = cx.tcx.parent(id) { + return variant_id == some_id; + } + } + } + false +} + #[cfg(test)] mod test { use super::{reindent_multiline, without_block_comments}; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 149cceb39dd99..c132e4de4f67b 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { // search for `for _ in vec![…]` if_chain! { - if let Some((_, arg, _)) = higher::for_loop(expr); + if let Some((_, arg, _, _)) = higher::for_loop(expr); if let Some(vec_args) = higher::vec_macro(cx, arg); if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg))); then { diff --git a/tests/ui/for_loops_over_options_or_results.rs b/tests/ui/for_loops_over_options_or_results.rs deleted file mode 100644 index 02e24b250f796..0000000000000 --- a/tests/ui/for_loops_over_options_or_results.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![warn(clippy::for_loops_over_options_or_results)] - -fn main() { - let x = vec![Some(1), Some(2), Some(3)]; - for n in x { - if let Some(n) = n { - println!("{}", n); - } - } - - let y: Vec> = vec![]; - for n in y.clone() { - if let Ok(n) = n { - println!("{}", n); - } - } - - // This should not trigger the lint - for n in y.clone() { - if let Ok(n) = n { - println!("{}", n); - } else { - println!("Oops!"); - } - } - - // This should not trigger the lint - for n in vec![Some(1), Some(2), Some(3)].iter().flatten() { - println!("{}", n); - } -} diff --git a/tests/ui/manual_flatten.rs b/tests/ui/manual_flatten.rs new file mode 100644 index 0000000000000..f183ceecdd897 --- /dev/null +++ b/tests/ui/manual_flatten.rs @@ -0,0 +1,54 @@ +#![warn(clippy::manual_flatten)] + +fn main() { + let x = vec![Some(1), Some(2), Some(3)]; + for n in x { + if let Some(n) = n { + println!("{}", n); + } + } + + let y: Vec> = vec![]; + for n in y.clone() { + if let Ok(n) = n { + println!("{}", n); + } + } + + let z = vec![Some(1), Some(2), Some(3)]; + let z = z.iter(); + for n in z { + if let Some(n) = n { + println!("{}", n); + } + } + + // Using the `None` variant should not trigger the lint + let z = vec![Some(1), Some(2), Some(3)]; + for n in z { + if n.is_none() { + println!("Nada."); + } + } + + // Using the `Err` variant should not trigger the lint + for n in y.clone() { + if let Err(e) = n { + println!("Oops: {}!", e); + } + } + + // Having an else clause should not trigger the lint + for n in y.clone() { + if let Ok(n) = n { + println!("{}", n); + } else { + println!("Oops!"); + } + } + + // Using manual flatten should not trigger the lint + for n in vec![Some(1), Some(2), Some(3)].iter().flatten() { + println!("{}", n); + } +} diff --git a/tests/ui/manual_flatten.stderr b/tests/ui/manual_flatten.stderr new file mode 100644 index 0000000000000..cf99a2d9ab1f8 --- /dev/null +++ b/tests/ui/manual_flatten.stderr @@ -0,0 +1,51 @@ +error: Unnecessary `if let` since only the `Some` variant of the iterator element is used. + --> $DIR/manual_flatten.rs:5:5 + | +LL | / for n in x { +LL | | if let Some(n) = n { +LL | | println!("{}", n); +LL | | } +LL | | } + | |_____^ + | + = note: `-D clippy::manual-flatten` implied by `-D warnings` +help: try: `x.into_iter().flatten()` + --> $DIR/manual_flatten.rs:5:14 + | +LL | for n in x { + | ^ + +error: Unnecessary `if let` since only the `Ok` variant of the iterator element is used. + --> $DIR/manual_flatten.rs:12:5 + | +LL | / for n in y.clone() { +LL | | if let Ok(n) = n { +LL | | println!("{}", n); +LL | | } +LL | | } + | |_____^ + | +help: try: `y.clone().into_iter().flatten()` + --> $DIR/manual_flatten.rs:12:14 + | +LL | for n in y.clone() { + | ^^^^^^^^^ + +error: Unnecessary `if let` since only the `Some` variant of the iterator element is used. + --> $DIR/manual_flatten.rs:20:5 + | +LL | / for n in z { +LL | | if let Some(n) = n { +LL | | println!("{}", n); +LL | | } +LL | | } + | |_____^ + | +help: try: `z.flatten()` + --> $DIR/manual_flatten.rs:20:14 + | +LL | for n in z { + | ^ + +error: aborting due to 3 previous errors + From 7825bf36d8dfee0099a23eb74451783da3ce261f Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 31 Jan 2021 21:43:35 +0100 Subject: [PATCH 06/72] Fix suggestions that need parens --- clippy_lints/src/methods/mod.rs | 9 +++++++-- tests/ui/from_iter_instead_of_collect.rs | 8 +++++++- tests/ui/from_iter_instead_of_collect.stderr | 14 +++++++++++++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7a459a440cae4..f53b2f67d1db8 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4094,14 +4094,19 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); then { // `expr` implements `FromIterator` trait - let iter_expr = snippet(cx, args[0].span, ".."); + let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); + let sugg = if higher::range(&args[0]).is_some() { + format!("{}.collect::<{}>()", iter_expr, ty) + } else { + format!("{}.collect()", iter_expr) + }; span_lint_and_sugg( cx, FROM_ITER_INSTEAD_OF_COLLECT, expr.span, "usage of `FromIterator::from_iter`", "use `.collect()` instead of `::from_iter()`", - format!("{}.collect()", iter_expr), + sugg, Applicability::MaybeIncorrect, ); } diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index 045eb3133d3c4..6c81366c4df7f 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -1,6 +1,6 @@ #![warn(clippy::from_iter_instead_of_collect)] -use std::collections::HashMap; +use std::collections::{HashMap, VecDeque}; use std::iter::FromIterator; fn main() { @@ -10,4 +10,10 @@ fn main() { HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); Vec::from_iter(vec![42u32]); + + let a = vec![0, 1, 2]; + assert_eq!(a, Vec::from_iter(0..3)); + + let mut b = VecDeque::from_iter(0..3); + b.push_back(4); } diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index 46bdc2f4e199b..e2161dd3b5778 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -12,5 +12,17 @@ error: usage of `FromIterator::from_iter` LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect()` -error: aborting due to 2 previous errors +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:15:19 + | +LL | assert_eq!(a, Vec::from_iter(0..3)); + | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:17:17 + | +LL | let mut b = VecDeque::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: aborting due to 4 previous errors From e07cd5b6fe47b1e26f19a1bede7c2e4967cb46d7 Mon Sep 17 00:00:00 2001 From: nahuakang Date: Tue, 2 Feb 2021 19:04:20 +0100 Subject: [PATCH 07/72] Enhance manual flatten --- clippy_lints/src/loops.rs | 112 +++++++++++++++++++++------------ tests/ui/manual_flatten.rs | 10 +++ tests/ui/manual_flatten.stderr | 47 ++++++-------- 3 files changed, 101 insertions(+), 68 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index db5aec82e90c2..23dce283f28ce 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1996,52 +1996,82 @@ fn check_manual_flatten<'tcx>( body: &'tcx Expr<'_>, span: Span, ) { - if_chain! { - // Ensure the `if let` statement is the only expression in the for-loop - 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: false } - ) = inner_expr.kind; - // Ensure match_expr in `if let` statement is the same as the pat from the for-loop - if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind; - if let ExprKind::Path(QPath::Resolved(None, match_expr_path)) = match_expr.kind; - if let Res::Local(match_expr_path_id) = match_expr_path.res; - if pat_hir_id == match_expr_path_id; - // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result` - if let PatKind::TupleStruct(QPath::Resolved(None, path), _, _) = match_arms[0].pat.kind; - if is_some_ctor(cx, path.res) || is_ok_ctor(cx, path.res); - let if_let_type = if is_some_ctor(cx, path.res) { - "Some" + if let ExprKind::Block(ref block, _) = body.kind { + // Ensure the `if let` statement is the only expression or statement in the for-loop + let inner_expr = if block.stmts.len() == 1 && block.expr.is_none() { + let match_stmt = &block.stmts[0]; + if let StmtKind::Semi(inner_expr) = match_stmt.kind { + Some(inner_expr) + } else { + None + } + } else if block.stmts.is_empty() { + block.expr } else { - "Ok" + None }; - // Determine if `arg` is `Iterator` or implicitly calls `into_iter` - let arg_ty = cx.typeck_results().expr_ty(arg); - if let Some(id) = get_trait_def_id(cx, &paths::ITERATOR); - if let is_iterator = implements_trait(cx, arg_ty, id, &[]); - then { - // Prepare the error message - let msg = format!("Unnecessary `if let` since only the `{}` variant of the iterator element is used.", if_let_type); + if_chain! { + if let Some(inner_expr) = inner_expr; + if let ExprKind::Match( + ref match_expr, ref match_arms, MatchSource::IfLetDesugar{ contains_else_clause: false } + ) = inner_expr.kind; + // Ensure match_expr in `if let` statement is the same as the pat from the for-loop + if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind; + if let ExprKind::Path(QPath::Resolved(None, match_expr_path)) = match_expr.kind; + if let Res::Local(match_expr_path_id) = match_expr_path.res; + if pat_hir_id == match_expr_path_id; + // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result` + if let PatKind::TupleStruct(QPath::Resolved(None, path), _, _) = match_arms[0].pat.kind; + let some_ctor = is_some_ctor(cx, path.res); + let ok_ctor = is_ok_ctor(cx, path.res); + if some_ctor || ok_ctor; + let if_let_type = if some_ctor { "Some" } else { "Ok" }; - // Prepare the help message - let arg_snippet = snippet(cx, arg.span, ".."); - let hint = if is_iterator { - format!("try: `{}.flatten()`", arg_snippet) - } else { - format!("try: `{}.into_iter().flatten()`", arg_snippet) - }; + then { + // Prepare the error message + let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type); - span_lint_and_help( - cx, - MANUAL_FLATTEN, - span, - &msg, - Some(arg.span), - &hint, - ); + // Prepare the help message + let mut applicability = Applicability::MaybeIncorrect; + let arg_snippet = snippet_with_applicability( + cx, + arg.span, + "..", + &mut applicability, + ); + // Determine if `arg` is by reference, an `Iterator`, or implicitly adjusted with `into_iter` + let hint = match arg.kind { + ExprKind::AddrOf(_, _, arg_expr) => { + format!("{}.iter().flatten()", snippet(cx, arg_expr.span, "..")) + }, + ExprKind::MethodCall(_, _, _, _) | ExprKind::Path(QPath::Resolved(None, _)) => { + // Determine if `arg` is `Iterator` or implicitly calls `into_iter` + let arg_ty = cx.typeck_results().expr_ty(arg); + if let Some(id) = get_trait_def_id(cx, &paths::ITERATOR) { + let is_iterator = implements_trait(cx, arg_ty, id, &[]); + if is_iterator { + format!("{}.flatten()", arg_snippet) + } else { + format!("{}.into_iter().flatten()", arg_snippet) + } + } else { + return + } + }, + _ => return, + }; + + span_lint_and_sugg( + cx, + MANUAL_FLATTEN, + span, + &msg, + "try", + hint, + applicability, + ) + } } } } diff --git a/tests/ui/manual_flatten.rs b/tests/ui/manual_flatten.rs index f183ceecdd897..b97cceb66f8e6 100644 --- a/tests/ui/manual_flatten.rs +++ b/tests/ui/manual_flatten.rs @@ -1,6 +1,7 @@ #![warn(clippy::manual_flatten)] fn main() { + // Test for loop over implicitly adjusted `Iterator` with `if let` expression let x = vec![Some(1), Some(2), Some(3)]; for n in x { if let Some(n) = n { @@ -8,13 +9,22 @@ fn main() { } } + // Test for loop over implicitly implicitly adjusted `Iterator` with `if let` statement let y: Vec> = vec![]; for n in y.clone() { + if let Ok(n) = n { + println!("{}", n); + }; + } + + // Test for loop over by reference + for n in &y { if let Ok(n) = n { println!("{}", n); } } + // Test for loop over `Iterator` with `if let` expression let z = vec![Some(1), Some(2), Some(3)]; let z = z.iter(); for n in z { diff --git a/tests/ui/manual_flatten.stderr b/tests/ui/manual_flatten.stderr index cf99a2d9ab1f8..754921eb73927 100644 --- a/tests/ui/manual_flatten.stderr +++ b/tests/ui/manual_flatten.stderr @@ -1,51 +1,44 @@ -error: Unnecessary `if let` since only the `Some` variant of the iterator element is used. - --> $DIR/manual_flatten.rs:5:5 +error: unnecessary `if let` since only the `Some` variant of the iterator element is used + --> $DIR/manual_flatten.rs:6:5 | LL | / for n in x { LL | | if let Some(n) = n { LL | | println!("{}", n); LL | | } LL | | } - | |_____^ + | |_____^ help: try: `x.into_iter().flatten()` | = note: `-D clippy::manual-flatten` implied by `-D warnings` -help: try: `x.into_iter().flatten()` - --> $DIR/manual_flatten.rs:5:14 - | -LL | for n in x { - | ^ -error: Unnecessary `if let` since only the `Ok` variant of the iterator element is used. - --> $DIR/manual_flatten.rs:12:5 +error: unnecessary `if let` since only the `Ok` variant of the iterator element is used + --> $DIR/manual_flatten.rs:14:5 | LL | / for n in y.clone() { LL | | if let Ok(n) = n { LL | | println!("{}", n); -LL | | } +LL | | }; LL | | } - | |_____^ - | -help: try: `y.clone().into_iter().flatten()` - --> $DIR/manual_flatten.rs:12:14 + | |_____^ help: try: `y.clone().into_iter().flatten()` + +error: unnecessary `if let` since only the `Ok` variant of the iterator element is used + --> $DIR/manual_flatten.rs:21:5 | -LL | for n in y.clone() { - | ^^^^^^^^^ +LL | / for n in &y { +LL | | if let Ok(n) = n { +LL | | println!("{}", n); +LL | | } +LL | | } + | |_____^ help: try: `y.iter().flatten()` -error: Unnecessary `if let` since only the `Some` variant of the iterator element is used. - --> $DIR/manual_flatten.rs:20:5 +error: unnecessary `if let` since only the `Some` variant of the iterator element is used + --> $DIR/manual_flatten.rs:30:5 | LL | / for n in z { LL | | if let Some(n) = n { LL | | println!("{}", n); LL | | } LL | | } - | |_____^ - | -help: try: `z.flatten()` - --> $DIR/manual_flatten.rs:20:14 - | -LL | for n in z { - | ^ + | |_____^ help: try: `z.flatten()` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors From c8cb90abbdff45cd936272903f14990bdcefc1cf Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 2 Feb 2021 20:43:30 -0800 Subject: [PATCH 08/72] Merge commit '3e4179766bcecd712824da04356621b8df012ea4' into sync-from-clippy --- CHANGELOG.md | 1 + CONTRIBUTING.md | 9 +- clippy_dev/src/bless.rs | 3 + clippy_dev/src/fmt.rs | 23 ++-- clippy_dev/src/lib.rs | 13 ++ clippy_dev/src/ra_setup.rs | 3 + clippy_dev/src/serve.rs | 3 + clippy_lints/src/doc.rs | 125 +++++++++++++++++- clippy_lints/src/excessive_bools.rs | 8 +- clippy_lints/src/exhaustive_items.rs | 10 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/matches.rs | 12 +- clippy_lints/src/utils/ast_utils.rs | 15 +-- clippy_lints/src/utils/diagnostics.rs | 2 +- clippy_lints/src/utils/internal_lints.rs | 6 +- clippy_lints/src/utils/mod.rs | 31 +++-- clippy_lints/src/write.rs | 6 +- doc/adding_lints.md | 10 +- doc/basics.md | 2 +- mini-macro/src/lib.rs | 3 + rust-toolchain | 2 +- tests/ui/doc_panics.rs | 95 +++++++++++++ tests/ui/doc_panics.stderr | 67 ++++++++++ tests/ui/exhaustive_items.fixed | 23 +++- tests/ui/exhaustive_items.rs | 23 +++- tests/ui/exhaustive_items.stderr | 4 +- tests/ui/let_and_return.rs | 12 +- tests/ui/let_and_return.stderr | 2 +- tests/ui/match_overlapping_arm.rs | 30 +++++ tests/ui/match_overlapping_arm.stderr | 32 ++--- tests/ui/should_impl_trait/corner_cases.rs | 3 +- tests/ui/should_impl_trait/method_list_1.rs | 3 +- .../ui/should_impl_trait/method_list_1.stderr | 28 ++-- tests/ui/should_impl_trait/method_list_2.rs | 3 +- .../ui/should_impl_trait/method_list_2.stderr | 30 ++--- 35 files changed, 518 insertions(+), 126 deletions(-) create mode 100644 tests/ui/doc_panics.rs create mode 100644 tests/ui/doc_panics.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index dadb6832d1fd7..c1032204a22cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2079,6 +2079,7 @@ Released 2018-09-13 [`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items [`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc [`missing_inline_in_public_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_inline_in_public_items +[`missing_panics_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc [`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc [`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes [`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f2641a23f563b..5954ab25d1942 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -46,11 +46,12 @@ first read the [Basics docs](doc/basics.md).** ### Finding something to fix/improve -All issues on Clippy are mentored, if you want help with a bug just ask -@Manishearth, @flip1995, @phansch or @yaahc. +All issues on Clippy are mentored, if you want help simply ask @Manishearth, @flip1995, @phansch +or @llogiq directly by mentioning them in the issue or over on [Zulip]. This list may be out of date. +All currently active mentors can be found [here](https://github.com/rust-lang/highfive/blob/master/highfive/configs/rust-lang/rust-clippy.json#L3) -Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy issues. -If you want to work on an issue, please leave a comment so that we can assign it to you! +Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy +issues. You can use `@rustbot claim` to assign the issue to yourself. There are also some abandoned PRs, marked with [`S-inactive-closed`]. Pretty often these PRs are nearly completed and just need some extra steps diff --git a/clippy_dev/src/bless.rs b/clippy_dev/src/bless.rs index b877806946cfe..2a869e9d4491b 100644 --- a/clippy_dev/src/bless.rs +++ b/clippy_dev/src/bless.rs @@ -24,6 +24,9 @@ static CLIPPY_BUILD_TIME: SyncLazy> = SyncLazy::ne fs::metadata(path).ok()?.modified().ok() }); +/// # Panics +/// +/// Panics if the path to a test file is broken pub fn bless(ignore_timestamp: bool) { let test_suite_dirs = [ clippy_project_root().join("tests").join("ui"), diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 6b528d219df27..4d0fdadbd85d1 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -8,7 +8,7 @@ use walkdir::WalkDir; #[derive(Debug)] pub enum CliError { - CommandFailed(String), + CommandFailed(String, String), IoError(io::Error), RustfmtNotInstalled, WalkDirError(walkdir::Error), @@ -75,8 +75,8 @@ pub fn run(check: bool, verbose: bool) { fn output_err(err: CliError) { match err { - CliError::CommandFailed(command) => { - eprintln!("error: A command failed! `{}`", command); + CliError::CommandFailed(command, stderr) => { + eprintln!("error: A command failed! `{}`\nstderr: {}", command, stderr); }, CliError::IoError(err) => { eprintln!("error: {}", err); @@ -136,12 +136,16 @@ fn exec( println!("{}", format_command(&program, &dir, args)); } - let mut child = Command::new(&program).current_dir(&dir).args(args.iter()).spawn()?; - let code = child.wait()?; - let success = code.success(); + let child = Command::new(&program).current_dir(&dir).args(args.iter()).spawn()?; + let output = child.wait_with_output()?; + let success = output.status.success(); if !context.check && !success { - return Err(CliError::CommandFailed(format_command(&program, &dir, args))); + let stderr = std::str::from_utf8(&output.stderr).unwrap_or(""); + return Err(CliError::CommandFailed( + format_command(&program, &dir, args), + String::from(stderr), + )); } Ok(success) @@ -177,7 +181,10 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> { { Err(CliError::RustfmtNotInstalled) } else { - Err(CliError::CommandFailed(format_command(&program, &dir, args))) + Err(CliError::CommandFailed( + format_command(&program, &dir, args), + std::str::from_utf8(&output.stderr).unwrap_or("").to_string(), + )) } } diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 24d70d433f367..01d1fc9211a94 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -236,6 +236,10 @@ pub struct FileChange { /// `path` is the relative path to the file on which you want to perform the replacement. /// /// See `replace_region_in_text` for documentation of the other options. +/// +/// # Panics +/// +/// Panics if the path could not read or then written pub fn replace_region_in_file( path: &Path, start: &str, @@ -283,6 +287,10 @@ where /// .new_lines; /// assert_eq!("replace_start\na different\ntext\nreplace_end", result); /// ``` +/// +/// # Panics +/// +/// Panics if start or end is not valid regex pub fn replace_region_in_text(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> FileChange where F: FnOnce() -> Vec, @@ -329,6 +337,11 @@ where } /// Returns the path to the Clippy project directory +/// +/// # Panics +/// +/// Panics if the current directory could not be retrieved, there was an error reading any of the +/// Cargo.toml files or ancestor directory is the clippy root directory #[must_use] pub fn clippy_project_root() -> PathBuf { let current_dir = std::env::current_dir().unwrap(); diff --git a/clippy_dev/src/ra_setup.rs b/clippy_dev/src/ra_setup.rs index a8a6a2cb1bd6f..a3c329b578b20 100644 --- a/clippy_dev/src/ra_setup.rs +++ b/clippy_dev/src/ra_setup.rs @@ -8,6 +8,9 @@ use std::path::{Path, PathBuf}; // This allows rust analyzer to analyze rustc internals and show proper information inside clippy // code. See https://github.com/rust-analyzer/rust-analyzer/issues/3517 and https://github.com/rust-lang/rust-clippy/issues/5514 for details +/// # Panics +/// +/// Panics if `rustc_path` does not lead to a rustc repo or the files could not be read pub fn run(rustc_path: Option<&str>) { // we can unwrap here because the arg is required by clap let rustc_path = PathBuf::from(rustc_path.unwrap()); diff --git a/clippy_dev/src/serve.rs b/clippy_dev/src/serve.rs index a46c0e4d3f0a1..faa94859601e3 100644 --- a/clippy_dev/src/serve.rs +++ b/clippy_dev/src/serve.rs @@ -4,6 +4,9 @@ use std::process::Command; use std::thread; use std::time::{Duration, SystemTime}; +/// # Panics +/// +/// Panics if the python commands could not be spawned pub fn run(port: u16, lint: Option<&str>) -> ! { let mut url = Some(match lint { None => format!("http://localhost:{}", port), diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index fa0289c977c72..75e71eb1e4ce2 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,4 +1,7 @@ -use crate::utils::{implements_trait, is_entrypoint_fn, is_type_diagnostic_item, return_ty, span_lint}; +use crate::utils::{ + implements_trait, is_entrypoint_fn, is_type_diagnostic_item, match_panic_def_id, method_chain_args, return_ty, + span_lint, span_lint_and_note, +}; use if_chain::if_chain; use itertools::Itertools; use rustc_ast::ast::{Async, AttrKind, Attribute, FnKind, FnRetTy, ItemKind}; @@ -8,7 +11,10 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::EmitterWriter; use rustc_errors::Handler; use rustc_hir as hir; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_parse::maybe_new_parser_from_source_str; @@ -122,6 +128,37 @@ declare_clippy_lint! { "`pub fn` returns `Result` without `# Errors` in doc comment" } +declare_clippy_lint! { + /// **What it does:** Checks the doc comments of publicly visible functions that + /// may panic and warns if there is no `# Panics` section. + /// + /// **Why is this bad?** Documenting the scenarios in which panicking occurs + /// can help callers who do not want to panic to avoid those situations. + /// + /// **Known problems:** None. + /// + /// **Examples:** + /// + /// Since the following function may panic it has a `# Panics` section in + /// its doc comment: + /// + /// ```rust + /// /// # Panics + /// /// + /// /// Will panic if y is 0 + /// pub fn divide_by(x: i32, y: i32) -> i32 { + /// if y == 0 { + /// panic!("Cannot divide by 0") + /// } else { + /// x / y + /// } + /// } + /// ``` + pub MISSING_PANICS_DOC, + pedantic, + "`pub fn` may panic without `# Panics` in doc comment" +} + declare_clippy_lint! { /// **What it does:** Checks for `fn main() { .. }` in doctests /// @@ -166,7 +203,9 @@ impl DocMarkdown { } } -impl_lint_pass!(DocMarkdown => [DOC_MARKDOWN, MISSING_SAFETY_DOC, MISSING_ERRORS_DOC, NEEDLESS_DOCTEST_MAIN]); +impl_lint_pass!(DocMarkdown => + [DOC_MARKDOWN, MISSING_SAFETY_DOC, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, NEEDLESS_DOCTEST_MAIN] +); impl<'tcx> LateLintPass<'tcx> for DocMarkdown { fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) { @@ -180,7 +219,15 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { if !(is_entrypoint_fn(cx, cx.tcx.hir().local_def_id(item.hir_id).to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) { - lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id)); + let body = cx.tcx.hir().body(body_id); + let impl_item_def_id = cx.tcx.hir().local_def_id(item.hir_id); + let mut fpu = FindPanicUnwrap { + cx, + typeck_results: cx.tcx.typeck(impl_item_def_id), + panic_span: None, + }; + fpu.visit_expr(&body.value); + lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id), fpu.panic_span); } }, hir::ItemKind::Impl(ref impl_) => { @@ -200,7 +247,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { let headers = check_attrs(cx, &self.valid_idents, &item.attrs); if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind { if !in_external_macro(cx.tcx.sess, item.span) { - lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, None); + lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, None, None); } } } @@ -211,7 +258,15 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { return; } if let hir::ImplItemKind::Fn(ref sig, body_id) = item.kind { - lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id)); + let body = cx.tcx.hir().body(body_id); + let impl_item_def_id = cx.tcx.hir().local_def_id(item.hir_id); + let mut fpu = FindPanicUnwrap { + cx, + typeck_results: cx.tcx.typeck(impl_item_def_id), + panic_span: None, + }; + fpu.visit_expr(&body.value); + lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id), fpu.panic_span); } } } @@ -223,6 +278,7 @@ fn lint_for_missing_headers<'tcx>( sig: &hir::FnSig<'_>, headers: DocHeaders, body_id: Option, + panic_span: Option, ) { if !cx.access_levels.is_exported(hir_id) { return; // Private functions do not require doc comments @@ -235,6 +291,16 @@ fn lint_for_missing_headers<'tcx>( "unsafe function's docs miss `# Safety` section", ); } + if !headers.panics && panic_span.is_some() { + span_lint_and_note( + cx, + MISSING_PANICS_DOC, + span, + "docs for function which may panic missing `# Panics` section", + panic_span, + "first possible panic found here", + ); + } if !headers.errors { if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) { span_lint( @@ -321,6 +387,7 @@ pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: struct DocHeaders { safety: bool, errors: bool, + panics: bool, } fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &'a [Attribute]) -> DocHeaders { @@ -338,6 +405,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs return DocHeaders { safety: true, errors: true, + panics: true, }; } } @@ -353,6 +421,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs return DocHeaders { safety: false, errors: false, + panics: false, }; } @@ -394,6 +463,7 @@ fn check_doc<'a, Events: Iterator, Range, Range o, Err(e) => e - 1, @@ -609,3 +680,47 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { ); } } + +struct FindPanicUnwrap<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + panic_span: Option, + typeck_results: &'tcx ty::TypeckResults<'tcx>, +} + +impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + if self.panic_span.is_some() { + return; + } + + // check for `begin_panic` + if_chain! { + if let ExprKind::Call(ref func_expr, _) = expr.kind; + if let ExprKind::Path(QPath::Resolved(_, ref path)) = func_expr.kind; + if let Some(path_def_id) = path.res.opt_def_id(); + if match_panic_def_id(self.cx, path_def_id); + then { + self.panic_span = Some(expr.span); + } + } + + // check for `unwrap` + if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { + let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); + if is_type_diagnostic_item(self.cx, reciever_ty, sym::option_type) + || is_type_diagnostic_item(self.cx, reciever_ty, sym::result_type) + { + self.panic_span = Some(expr.span); + } + } + + // and check sub-expressions + intravisit::walk_expr(self, expr); + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) + } +} diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index fecde8e274348..6f22f65deac80 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -160,15 +160,17 @@ impl EarlyLintPass for ExcessiveBools { "consider using a state machine or refactoring bools into two-variant enums", ); } - } - ItemKind::Impl(box ImplKind { of_trait: None, items, .. }) + }, + ItemKind::Impl(box ImplKind { + of_trait: None, items, .. + }) | ItemKind::Trait(box TraitKind(.., items)) => { for item in items { if let AssocItemKind::Fn(box FnKind(_, fn_sig, _, _)) = &item.kind { self.check_fn_sig(cx, fn_sig, item.span); } } - } + }, ItemKind::Fn(box FnKind(_, fn_sig, _, _)) => self.check_fn_sig(cx, fn_sig, item.span), _ => (), } diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 32b1299efce91..e3988d0038c23 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -75,10 +75,14 @@ impl LateLintPass<'_> for ExhaustiveItems { if cx.access_levels.is_exported(item.hir_id); if !item.attrs.iter().any(|a| a.has_name(sym::non_exhaustive)); then { - let (lint, msg) = if let ItemKind::Enum(..) = item.kind { - (EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive") - } else { + let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind { + if v.fields().iter().any(|f| !f.vis.node.is_pub()) { + // skip structs with private fields + return; + } (EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive") + } else { + (EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive") }; let suggestion_span = item.span.shrink_to_lo(); let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0)); diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 54007c29c6c5e..5a40c00bd673a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -592,6 +592,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &disallowed_method::DISALLOWED_METHOD, &doc::DOC_MARKDOWN, &doc::MISSING_ERRORS_DOC, + &doc::MISSING_PANICS_DOC, &doc::MISSING_SAFETY_DOC, &doc::NEEDLESS_DOCTEST_MAIN, &double_comparison::DOUBLE_COMPARISONS, @@ -1317,6 +1318,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE), LintId::of(&doc::DOC_MARKDOWN), LintId::of(&doc::MISSING_ERRORS_DOC), + LintId::of(&doc::MISSING_PANICS_DOC), LintId::of(&empty_enum::EMPTY_ENUM), LintId::of(&enum_variants::MODULE_NAME_REPETITIONS), LintId::of(&enum_variants::PUB_ENUM_VARIANT_NAMES), diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 5f62d2d13165c..ba7b9bd04248d 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1592,7 +1592,17 @@ where } }, (&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (), - _ => return Some((a.range(), b.range())), + _ => { + // skip if the range `a` is completely included into the range `b` + if let Ordering::Equal | Ordering::Less = a.cmp(&b) { + let kind_a = Kind::End(a.range().node.1, a.range()); + let kind_b = Kind::End(b.range().node.1, b.range()); + if let Ordering::Equal | Ordering::Greater = kind_a.cmp(&kind_b) { + return None; + } + } + return Some((a.range(), b.range())); + }, } } diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index 69492e84e4ac5..642326469725f 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -247,7 +247,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { (ForeignMod(l), ForeignMod(r)) => { both(&l.abi, &r.abi, |l, r| eq_str_lit(l, r)) && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind)) - } + }, (TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => { eq_defaultness(*ld, *rd) && eq_generics(lg, rg) @@ -259,7 +259,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { }, (Struct(lv, lg), Struct(rv, rg)) | (Union(lv, lg), Union(rv, rg)) => { eq_variant_data(lv, rv) && eq_generics(lg, rg) - } + }, (Trait(box TraitKind(la, lu, lg, lb, li)), Trait(box TraitKind(ra, ru, rg, rb, ri))) => { la == ra && matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No) @@ -331,15 +331,10 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { use AssocItemKind::*; match (l, r) { - (Const(ld, lt, le), Const(rd, rt, re)) => { - eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re) - } + (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), (Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => { - eq_defaultness(*ld, *rd) - && eq_fn_sig(lf, rf) - && eq_generics(lg, rg) - && both(lb, rb, |l, r| eq_block(l, r)) - } + eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r)) + }, (TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => { eq_defaultness(*ld, *rd) && eq_generics(lg, rg) diff --git a/clippy_lints/src/utils/diagnostics.rs b/clippy_lints/src/utils/diagnostics.rs index 6caa04f651fae..269be217c2d87 100644 --- a/clippy_lints/src/utils/diagnostics.rs +++ b/clippy_lints/src/utils/diagnostics.rs @@ -110,7 +110,7 @@ pub fn span_lint_and_help<'a, T: LintContext>( pub fn span_lint_and_note<'a, T: LintContext>( cx: &'a T, lint: &'static Lint, - span: Span, + span: impl Into, msg: &str, note_span: Option, note: &str, diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 822863ca3e279..cccad243e1b59 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -760,7 +760,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { // Extract the path to the matched type if let Some(segments) = path_to_matched_type(cx, ty_path); let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect(); - if let Some(ty_did) = path_to_res(cx, &segments[..]).and_then(|res| res.opt_def_id()); + if let Some(ty_did) = path_to_res(cx, &segments[..]).opt_def_id(); // Check if the matched type is a diagnostic item let diag_items = cx.tcx.diagnostic_items(ty_did.krate); if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None }); @@ -833,7 +833,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option, path: &[&str]) -> bool { - if path_to_res(cx, path).is_some() { + if path_to_res(cx, path) != Res::Err { return true; } @@ -906,7 +906,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { } for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] { - if let Some(Res::Def(_, def_id)) = path_to_res(cx, module) { + if let Some(def_id) = path_to_res(cx, module).opt_def_id() { for item in cx.tcx.item_children(def_id).iter() { if_chain! { if let Res::Def(DefKind::Const, item_def_id) = item.res; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index d0db3a67533bc..ef45f9fdcd5d4 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -309,7 +309,15 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { /// Gets the definition associated to a path. #[allow(clippy::shadow_unrelated)] // false positive #6563 -pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option { +pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res { + macro_rules! try_res { + ($e:expr) => { + match $e { + Some(e) => e, + None => return Res::Err, + } + }; + } fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export> { tcx.item_children(def_id) .iter() @@ -318,12 +326,12 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option { let (krate, first, path) = match *path { [krate, first, ref path @ ..] => (krate, first, path), - _ => return None, + _ => return Res::Err, }; let tcx = cx.tcx; let crates = tcx.crates(); - let krate = crates.iter().find(|&&num| tcx.crate_name(num).as_str() == krate)?; - let first = item_child_by_name(tcx, krate.as_def_id(), first)?; + let krate = try_res!(crates.iter().find(|&&num| tcx.crate_name(num).as_str() == krate)); + let first = try_res!(item_child_by_name(tcx, krate.as_def_id(), first)); let last = path .iter() .copied() @@ -343,21 +351,15 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option { } else { None } - })?; - Some(last.res) + }); + try_res!(last).res } /// Convenience function to get the `DefId` of a trait by path. /// It could be a trait or trait alias. pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option { - let res = match path_to_res(cx, path) { - Some(res) => res, - None => return None, - }; - - match res { + match path_to_res(cx, path) { Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id), - Res::Err => unreachable!("this trait resolution is impossible: {:?}", &path), _ => None, } } @@ -1532,10 +1534,11 @@ pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { ExprKind::Call( Expr { kind: ExprKind::Path(qpath), + hir_id: path_hir_id, .. }, .., - ) => cx.typeck_results().qpath_res(qpath, expr.hir_id).opt_def_id(), + ) => cx.typeck_results().qpath_res(qpath, *path_hir_id).opt_def_id(), _ => None, } } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index b9e97077c540f..978a232bcfb3a 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -233,7 +233,11 @@ impl_lint_pass!(Write => [ impl EarlyLintPass for Write { fn check_item(&mut self, _: &EarlyContext<'_>, item: &Item) { - if let ItemKind::Impl(box ImplKind { of_trait: Some(trait_ref), .. }) = &item.kind { + if let ItemKind::Impl(box ImplKind { + of_trait: Some(trait_ref), + .. + }) = &item.kind + { let trait_name = trait_ref .path .segments diff --git a/doc/adding_lints.md b/doc/adding_lints.md index fd2a7d171d020..8fd1dea9aeef9 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -581,15 +581,15 @@ in the following steps: 3. Passing the configuration value to the lint impl struct: First find the struct construction in the [clippy_lints lib file](/clippy_lints/src/lib.rs). - Make sure that `clippy dev update_lints` added it beforehand. The configuration value is now - cloned or copied into a local value that is then passed to the impl struct like this: + The configuration value is now cloned or copied into a local value that is then passed to the + impl struct like this: ```rust // Default generated registration: - store.register_late_pass(|| box module::StructName); + store.register_*_pass(|| box module::StructName); // New registration with configuration value let configuration_ident = conf.configuration_ident.clone(); - store.register_late_pass(move || box module::StructName::new(configuration_ident)); + store.register_*_pass(move || box module::StructName::new(configuration_ident)); ``` Congratulations the work is almost done. The configuration value can now be accessed @@ -599,7 +599,7 @@ in the following steps: 1. The default configured value can be tested like any normal lint in [`tests/ui`](/tests/ui). 2. The configuration itself will be tested separately in [`tests/ui-toml`](/tests/ui-toml). Simply add a new subfolder with a fitting name. This folder contains a `clippy.toml` file - with the configuration value and a rust file that should be linted by clippy. The test can + with the configuration value and a rust file that should be linted by Clippy. The test can otherwise be written as usual. ## Cheatsheet diff --git a/doc/basics.md b/doc/basics.md index 57f83bdf32bc2..a9416f3b20b7a 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -109,7 +109,7 @@ See . | HIR | High-Level Intermediate Representation | | TCX | Type context | -This is a concise list of abbreviations that can come up during clippy development. An extensive +This is a concise list of abbreviations that can come up during Clippy development. An extensive general list can be found in the [rustc-dev-guide glossary][glossary]. Always feel free to ask if an abbreviation or meaning is unclear to you. diff --git a/mini-macro/src/lib.rs b/mini-macro/src/lib.rs index ba946563ec595..2b793589049ba 100644 --- a/mini-macro/src/lib.rs +++ b/mini-macro/src/lib.rs @@ -7,6 +7,9 @@ extern crate proc_macro; use proc_macro::{quote, TokenStream}; #[proc_macro_derive(ClippyMiniMacroTest)] +/// # Panics +/// +/// Panics if the macro derivation fails pub fn mini_macro(_: TokenStream) -> TokenStream { quote!( #[allow(unused)] diff --git a/rust-toolchain b/rust-toolchain index f55d55d706587..b617203bef6d8 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-01-30" +channel = "nightly-2021-02-03" components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"] diff --git a/tests/ui/doc_panics.rs b/tests/ui/doc_panics.rs new file mode 100644 index 0000000000000..7ef932f367b10 --- /dev/null +++ b/tests/ui/doc_panics.rs @@ -0,0 +1,95 @@ +#![warn(clippy::missing_panics_doc)] +#![allow(clippy::option_map_unit_fn)] + +fn main() {} + +/// This needs to be documented +pub fn unwrap() { + let result = Err("Hi"); + result.unwrap() +} + +/// This needs to be documented +pub fn panic() { + panic!("This function panics") +} + +/// This needs to be documented +pub fn todo() { + todo!() +} + +/// This needs to be documented +pub fn inner_body(opt: Option) { + opt.map(|x| { + if x == 10 { + panic!() + } + }); +} + +/// This is documented +/// +/// # Panics +/// +/// Panics if `result` if an error +pub fn unwrap_documented() { + let result = Err("Hi"); + result.unwrap() +} + +/// This is documented +/// +/// # Panics +/// +/// Panics just because +pub fn panic_documented() { + panic!("This function panics") +} + +/// This is documented +/// +/// # Panics +/// +/// Panics if `opt` is Just(10) +pub fn inner_body_documented(opt: Option) { + opt.map(|x| { + if x == 10 { + panic!() + } + }); +} + +/// This is documented +/// +/// # Panics +/// +/// We still need to do this part +pub fn todo_documented() { + todo!() +} + +/// This is okay because it is private +fn unwrap_private() { + let result = Err("Hi"); + result.unwrap() +} + +/// This is okay because it is private +fn panic_private() { + panic!("This function panics") +} + +/// This is okay because it is private +fn todo_private() { + todo!() +} + +/// This is okay because it is private +fn inner_body_private(opt: Option) { + opt.map(|x| { + if x == 10 { + panic!() + } + }); +} diff --git a/tests/ui/doc_panics.stderr b/tests/ui/doc_panics.stderr new file mode 100644 index 0000000000000..c0c4e9e4fa7ee --- /dev/null +++ b/tests/ui/doc_panics.stderr @@ -0,0 +1,67 @@ +error: docs for function which may panic missing `# Panics` section + --> $DIR/doc_panics.rs:7:1 + | +LL | / pub fn unwrap() { +LL | | let result = Err("Hi"); +LL | | result.unwrap() +LL | | } + | |_^ + | + = note: `-D clippy::missing-panics-doc` implied by `-D warnings` +note: first possible panic found here + --> $DIR/doc_panics.rs:9:5 + | +LL | result.unwrap() + | ^^^^^^^^^^^^^^^ + +error: docs for function which may panic missing `# Panics` section + --> $DIR/doc_panics.rs:13:1 + | +LL | / pub fn panic() { +LL | | panic!("This function panics") +LL | | } + | |_^ + | +note: first possible panic found here + --> $DIR/doc_panics.rs:14:5 + | +LL | panic!("This function panics") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: docs for function which may panic missing `# Panics` section + --> $DIR/doc_panics.rs:18:1 + | +LL | / pub fn todo() { +LL | | todo!() +LL | | } + | |_^ + | +note: first possible panic found here + --> $DIR/doc_panics.rs:19:5 + | +LL | todo!() + | ^^^^^^^ + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: docs for function which may panic missing `# Panics` section + --> $DIR/doc_panics.rs:23:1 + | +LL | / pub fn inner_body(opt: Option) { +LL | | opt.map(|x| { +LL | | if x == 10 { +LL | | panic!() +LL | | } +LL | | }); +LL | | } + | |_^ + | +note: first possible panic found here + --> $DIR/doc_panics.rs:26:13 + | +LL | panic!() + | ^^^^^^^^ + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + diff --git a/tests/ui/exhaustive_items.fixed b/tests/ui/exhaustive_items.fixed index 8174a0175ab32..c209f5b4b7278 100644 --- a/tests/ui/exhaustive_items.fixed +++ b/tests/ui/exhaustive_items.fixed @@ -56,27 +56,36 @@ pub mod enums { pub mod structs { #[non_exhaustive] pub struct Exhaustive { - foo: u8, - bar: String, + pub foo: u8, + pub bar: String, } // no warning, already non_exhaustive #[non_exhaustive] pub struct NonExhaustive { - foo: u8, + pub foo: u8, + pub bar: String, + } + + // no warning, private fields + pub struct ExhaustivePrivateFieldTuple(u8); + + // no warning, private fields + pub struct ExhaustivePrivateField { + pub foo: u8, bar: String, } // no warning, private struct ExhaustivePrivate { - foo: u8, - bar: String, + pub foo: u8, + pub bar: String, } // no warning, private #[non_exhaustive] struct NonExhaustivePrivate { - foo: u8, - bar: String, + pub foo: u8, + pub bar: String, } } diff --git a/tests/ui/exhaustive_items.rs b/tests/ui/exhaustive_items.rs index b476f09f8a087..6f59dbf2da59b 100644 --- a/tests/ui/exhaustive_items.rs +++ b/tests/ui/exhaustive_items.rs @@ -53,27 +53,36 @@ pub mod enums { pub mod structs { pub struct Exhaustive { - foo: u8, - bar: String, + pub foo: u8, + pub bar: String, } // no warning, already non_exhaustive #[non_exhaustive] pub struct NonExhaustive { - foo: u8, + pub foo: u8, + pub bar: String, + } + + // no warning, private fields + pub struct ExhaustivePrivateFieldTuple(u8); + + // no warning, private fields + pub struct ExhaustivePrivateField { + pub foo: u8, bar: String, } // no warning, private struct ExhaustivePrivate { - foo: u8, - bar: String, + pub foo: u8, + pub bar: String, } // no warning, private #[non_exhaustive] struct NonExhaustivePrivate { - foo: u8, - bar: String, + pub foo: u8, + pub bar: String, } } diff --git a/tests/ui/exhaustive_items.stderr b/tests/ui/exhaustive_items.stderr index 7369fe75a4f74..8fbab535a9b25 100644 --- a/tests/ui/exhaustive_items.stderr +++ b/tests/ui/exhaustive_items.stderr @@ -41,8 +41,8 @@ error: exported structs should not be exhaustive --> $DIR/exhaustive_items.rs:55:5 | LL | / pub struct Exhaustive { -LL | | foo: u8, -LL | | bar: String, +LL | | pub foo: u8, +LL | | pub bar: String, LL | | } | |_____^ | diff --git a/tests/ui/let_and_return.rs b/tests/ui/let_and_return.rs index 73e550b3df891..e3561863c1e1f 100644 --- a/tests/ui/let_and_return.rs +++ b/tests/ui/let_and_return.rs @@ -117,7 +117,11 @@ mod no_lint_if_stmt_borrows { fn drop(&mut self) {} } - impl Foo<'_> { + impl<'a> Foo<'a> { + fn new(inner: &'a Inner) -> Self { + Self { inner } + } + fn value(&self) -> i32 { 42 } @@ -132,6 +136,12 @@ mod no_lint_if_stmt_borrows { let value = some_foo(&x).value(); value } + + fn test2() -> i32 { + let x = Inner {}; + let value = Foo::new(&x).value(); + value + } } } diff --git a/tests/ui/let_and_return.stderr b/tests/ui/let_and_return.stderr index fe878e5f20601..a6941dabeb88d 100644 --- a/tests/ui/let_and_return.stderr +++ b/tests/ui/let_and_return.stderr @@ -28,7 +28,7 @@ LL | 5 | error: returning the result of a `let` binding from a block - --> $DIR/let_and_return.rs:154:13 + --> $DIR/let_and_return.rs:164:13 | LL | let clone = Arc::clone(&self.foo); | ---------------------------------- unnecessary `let` binding diff --git a/tests/ui/match_overlapping_arm.rs b/tests/ui/match_overlapping_arm.rs index 97789bb766f89..44c51e8112a7d 100644 --- a/tests/ui/match_overlapping_arm.rs +++ b/tests/ui/match_overlapping_arm.rs @@ -57,6 +57,36 @@ fn overlapping() { _ => (), } + match 42 { + 5..7 => println!("5 .. 7"), + 0..10 => println!("0 .. 10"), + _ => (), + } + + match 42 { + 5..10 => println!("5 .. 10"), + 0..=10 => println!("0 ... 10"), + _ => (), + } + + match 42 { + 0..14 => println!("0 .. 14"), + 5..10 => println!("5 .. 10"), + _ => (), + } + + match 42 { + 5..14 => println!("5 .. 14"), + 0..=10 => println!("0 ... 10"), + _ => (), + } + + match 42 { + 0..7 => println!("0 .. 7"), + 0..=10 => println!("0 ... 10"), + _ => (), + } + /* // FIXME(JohnTitor): uncomment this once rustfmt knows half-open patterns match 42 { diff --git a/tests/ui/match_overlapping_arm.stderr b/tests/ui/match_overlapping_arm.stderr index eb20d5405a95e..f25a66d634e88 100644 --- a/tests/ui/match_overlapping_arm.stderr +++ b/tests/ui/match_overlapping_arm.stderr @@ -24,39 +24,39 @@ LL | FOO..=11 => println!("0 ... 11"), | ^^^^^^^^ error: some ranges overlap - --> $DIR/match_overlapping_arm.rs:26:9 + --> $DIR/match_overlapping_arm.rs:55:9 | -LL | 0..=5 => println!("0 ... 5"), +LL | 0..11 => println!("0 .. 11"), | ^^^^^ | note: overlaps with this - --> $DIR/match_overlapping_arm.rs:25:9 + --> $DIR/match_overlapping_arm.rs:56:9 | -LL | 2 => println!("2"), - | ^ +LL | 0..=11 => println!("0 ... 11"), + | ^^^^^^ error: some ranges overlap - --> $DIR/match_overlapping_arm.rs:32:9 + --> $DIR/match_overlapping_arm.rs:80:9 | -LL | 0..=2 => println!("0 ... 2"), - | ^^^^^ +LL | 0..=10 => println!("0 ... 10"), + | ^^^^^^ | note: overlaps with this - --> $DIR/match_overlapping_arm.rs:31:9 + --> $DIR/match_overlapping_arm.rs:79:9 | -LL | 2 => println!("2"), - | ^ +LL | 5..14 => println!("5 .. 14"), + | ^^^^^ error: some ranges overlap - --> $DIR/match_overlapping_arm.rs:55:9 + --> $DIR/match_overlapping_arm.rs:85:9 | -LL | 0..11 => println!("0 .. 11"), - | ^^^^^ +LL | 0..7 => println!("0 .. 7"), + | ^^^^ | note: overlaps with this - --> $DIR/match_overlapping_arm.rs:56:9 + --> $DIR/match_overlapping_arm.rs:86:9 | -LL | 0..=11 => println!("0 ... 11"), +LL | 0..=10 => println!("0 ... 10"), | ^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/should_impl_trait/corner_cases.rs b/tests/ui/should_impl_trait/corner_cases.rs index 6c5ffe6aba8b7..a7f8f54f2be04 100644 --- a/tests/ui/should_impl_trait/corner_cases.rs +++ b/tests/ui/should_impl_trait/corner_cases.rs @@ -8,7 +8,8 @@ clippy::unused_self, clippy::needless_lifetimes, clippy::missing_safety_doc, - clippy::wrong_self_convention + clippy::wrong_self_convention, + clippy::missing_panics_doc )] use std::ops::Mul; diff --git a/tests/ui/should_impl_trait/method_list_1.rs b/tests/ui/should_impl_trait/method_list_1.rs index f8d248fc98d82..69a3390b03b0b 100644 --- a/tests/ui/should_impl_trait/method_list_1.rs +++ b/tests/ui/should_impl_trait/method_list_1.rs @@ -8,7 +8,8 @@ clippy::unused_self, clippy::needless_lifetimes, clippy::missing_safety_doc, - clippy::wrong_self_convention + clippy::wrong_self_convention, + clippy::missing_panics_doc )] use std::ops::Mul; diff --git a/tests/ui/should_impl_trait/method_list_1.stderr b/tests/ui/should_impl_trait/method_list_1.stderr index 2b7d4628c3fa0..86c63946516ce 100644 --- a/tests/ui/should_impl_trait/method_list_1.stderr +++ b/tests/ui/should_impl_trait/method_list_1.stderr @@ -1,5 +1,5 @@ error: method `add` can be confused for the standard trait method `std::ops::Add::add` - --> $DIR/method_list_1.rs:25:5 + --> $DIR/method_list_1.rs:26:5 | LL | / pub fn add(self, other: T) -> T { LL | | unimplemented!() @@ -10,7 +10,7 @@ LL | | } = help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut` - --> $DIR/method_list_1.rs:29:5 + --> $DIR/method_list_1.rs:30:5 | LL | / pub fn as_mut(&mut self) -> &mut T { LL | | unimplemented!() @@ -20,7 +20,7 @@ LL | | } = help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref` - --> $DIR/method_list_1.rs:33:5 + --> $DIR/method_list_1.rs:34:5 | LL | / pub fn as_ref(&self) -> &T { LL | | unimplemented!() @@ -30,7 +30,7 @@ LL | | } = help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand` - --> $DIR/method_list_1.rs:37:5 + --> $DIR/method_list_1.rs:38:5 | LL | / pub fn bitand(self, rhs: T) -> T { LL | | unimplemented!() @@ -40,7 +40,7 @@ LL | | } = help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor` - --> $DIR/method_list_1.rs:41:5 + --> $DIR/method_list_1.rs:42:5 | LL | / pub fn bitor(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -50,7 +50,7 @@ LL | | } = help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor` - --> $DIR/method_list_1.rs:45:5 + --> $DIR/method_list_1.rs:46:5 | LL | / pub fn bitxor(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -60,7 +60,7 @@ LL | | } = help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow` - --> $DIR/method_list_1.rs:49:5 + --> $DIR/method_list_1.rs:50:5 | LL | / pub fn borrow(&self) -> &str { LL | | unimplemented!() @@ -70,7 +70,7 @@ LL | | } = help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut` - --> $DIR/method_list_1.rs:53:5 + --> $DIR/method_list_1.rs:54:5 | LL | / pub fn borrow_mut(&mut self) -> &mut str { LL | | unimplemented!() @@ -80,7 +80,7 @@ LL | | } = help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone` - --> $DIR/method_list_1.rs:57:5 + --> $DIR/method_list_1.rs:58:5 | LL | / pub fn clone(&self) -> Self { LL | | unimplemented!() @@ -90,7 +90,7 @@ LL | | } = help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp` - --> $DIR/method_list_1.rs:61:5 + --> $DIR/method_list_1.rs:62:5 | LL | / pub fn cmp(&self, other: &Self) -> Self { LL | | unimplemented!() @@ -100,7 +100,7 @@ LL | | } = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref` - --> $DIR/method_list_1.rs:69:5 + --> $DIR/method_list_1.rs:70:5 | LL | / pub fn deref(&self) -> &Self { LL | | unimplemented!() @@ -110,7 +110,7 @@ LL | | } = help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut` - --> $DIR/method_list_1.rs:73:5 + --> $DIR/method_list_1.rs:74:5 | LL | / pub fn deref_mut(&mut self) -> &mut Self { LL | | unimplemented!() @@ -120,7 +120,7 @@ LL | | } = help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name error: method `div` can be confused for the standard trait method `std::ops::Div::div` - --> $DIR/method_list_1.rs:77:5 + --> $DIR/method_list_1.rs:78:5 | LL | / pub fn div(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -130,7 +130,7 @@ LL | | } = help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop` - --> $DIR/method_list_1.rs:81:5 + --> $DIR/method_list_1.rs:82:5 | LL | / pub fn drop(&mut self) { LL | | unimplemented!() diff --git a/tests/ui/should_impl_trait/method_list_2.rs b/tests/ui/should_impl_trait/method_list_2.rs index ed5e0d384bf50..2cdc1a06fe689 100644 --- a/tests/ui/should_impl_trait/method_list_2.rs +++ b/tests/ui/should_impl_trait/method_list_2.rs @@ -8,7 +8,8 @@ clippy::unused_self, clippy::needless_lifetimes, clippy::missing_safety_doc, - clippy::wrong_self_convention + clippy::wrong_self_convention, + clippy::missing_panics_doc )] use std::ops::Mul; diff --git a/tests/ui/should_impl_trait/method_list_2.stderr b/tests/ui/should_impl_trait/method_list_2.stderr index b6fd435695698..0142e2991081c 100644 --- a/tests/ui/should_impl_trait/method_list_2.stderr +++ b/tests/ui/should_impl_trait/method_list_2.stderr @@ -1,5 +1,5 @@ error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq` - --> $DIR/method_list_2.rs:26:5 + --> $DIR/method_list_2.rs:27:5 | LL | / pub fn eq(&self, other: &Self) -> bool { LL | | unimplemented!() @@ -10,7 +10,7 @@ LL | | } = help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter` - --> $DIR/method_list_2.rs:30:5 + --> $DIR/method_list_2.rs:31:5 | LL | / pub fn from_iter(iter: T) -> Self { LL | | unimplemented!() @@ -20,7 +20,7 @@ LL | | } = help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str` - --> $DIR/method_list_2.rs:34:5 + --> $DIR/method_list_2.rs:35:5 | LL | / pub fn from_str(s: &str) -> Result { LL | | unimplemented!() @@ -30,7 +30,7 @@ LL | | } = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash` - --> $DIR/method_list_2.rs:38:5 + --> $DIR/method_list_2.rs:39:5 | LL | / pub fn hash(&self, state: &mut T) { LL | | unimplemented!() @@ -40,7 +40,7 @@ LL | | } = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name error: method `index` can be confused for the standard trait method `std::ops::Index::index` - --> $DIR/method_list_2.rs:42:5 + --> $DIR/method_list_2.rs:43:5 | LL | / pub fn index(&self, index: usize) -> &Self { LL | | unimplemented!() @@ -50,7 +50,7 @@ LL | | } = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut` - --> $DIR/method_list_2.rs:46:5 + --> $DIR/method_list_2.rs:47:5 | LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self { LL | | unimplemented!() @@ -60,7 +60,7 @@ LL | | } = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter` - --> $DIR/method_list_2.rs:50:5 + --> $DIR/method_list_2.rs:51:5 | LL | / pub fn into_iter(self) -> Self { LL | | unimplemented!() @@ -70,7 +70,7 @@ LL | | } = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul` - --> $DIR/method_list_2.rs:54:5 + --> $DIR/method_list_2.rs:55:5 | LL | / pub fn mul(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -80,7 +80,7 @@ LL | | } = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg` - --> $DIR/method_list_2.rs:58:5 + --> $DIR/method_list_2.rs:59:5 | LL | / pub fn neg(self) -> Self { LL | | unimplemented!() @@ -90,7 +90,7 @@ LL | | } = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name error: method `next` can be confused for the standard trait method `std::iter::Iterator::next` - --> $DIR/method_list_2.rs:62:5 + --> $DIR/method_list_2.rs:63:5 | LL | / pub fn next(&mut self) -> Option { LL | | unimplemented!() @@ -100,7 +100,7 @@ LL | | } = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name error: method `not` can be confused for the standard trait method `std::ops::Not::not` - --> $DIR/method_list_2.rs:66:5 + --> $DIR/method_list_2.rs:67:5 | LL | / pub fn not(self) -> Self { LL | | unimplemented!() @@ -110,7 +110,7 @@ LL | | } = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem` - --> $DIR/method_list_2.rs:70:5 + --> $DIR/method_list_2.rs:71:5 | LL | / pub fn rem(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -120,7 +120,7 @@ LL | | } = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl` - --> $DIR/method_list_2.rs:74:5 + --> $DIR/method_list_2.rs:75:5 | LL | / pub fn shl(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -130,7 +130,7 @@ LL | | } = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr` - --> $DIR/method_list_2.rs:78:5 + --> $DIR/method_list_2.rs:79:5 | LL | / pub fn shr(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -140,7 +140,7 @@ LL | | } = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub` - --> $DIR/method_list_2.rs:82:5 + --> $DIR/method_list_2.rs:83:5 | LL | / pub fn sub(self, rhs: Self) -> Self { LL | | unimplemented!() From 0f5e71f8f2d42e3eac3e855a83d53899d4da6eb3 Mon Sep 17 00:00:00 2001 From: nahuakang Date: Wed, 3 Feb 2021 09:39:35 +0100 Subject: [PATCH 09/72] Add additional check on if arg type has iter method --- clippy_lints/src/loops.rs | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 23dce283f28ce..5bfdc98bc6a50 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2041,25 +2041,24 @@ fn check_manual_flatten<'tcx>( &mut applicability, ); // Determine if `arg` is by reference, an `Iterator`, or implicitly adjusted with `into_iter` - let hint = match arg.kind { - ExprKind::AddrOf(_, _, arg_expr) => { + let arg_ty = cx.typeck_results().expr_ty(arg); + let hint = if arg_ty.is_ref() { + if has_iter_method(cx, arg_ty).is_none() { + return; + } else if let ExprKind::AddrOf(_, _, arg_expr) = arg.kind { format!("{}.iter().flatten()", snippet(cx, arg_expr.span, "..")) - }, - ExprKind::MethodCall(_, _, _, _) | ExprKind::Path(QPath::Resolved(None, _)) => { - // Determine if `arg` is `Iterator` or implicitly calls `into_iter` - let arg_ty = cx.typeck_results().expr_ty(arg); - if let Some(id) = get_trait_def_id(cx, &paths::ITERATOR) { - let is_iterator = implements_trait(cx, arg_ty, id, &[]); - if is_iterator { - format!("{}.flatten()", arg_snippet) - } else { - format!("{}.into_iter().flatten()", arg_snippet) - } - } else { - return - } - }, - _ => return, + } else { + return; + } + } else if let Some(id) = get_trait_def_id(cx, &paths::ITERATOR) { + let is_iterator = implements_trait(cx, arg_ty, id, &[]); + if is_iterator { + format!("{}.flatten()", arg_snippet) + } else { + format!("{}.into_iter().flatten()", arg_snippet) + } + } else { + return }; span_lint_and_sugg( From f2e82af3f278f8fbd51657a66c5b6d769d6ad9e9 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 2 Feb 2021 12:28:58 -0600 Subject: [PATCH 10/72] Use PrimTy in builtin type shadow lint --- clippy_lints/src/misc_early.rs | 8 ++++---- clippy_lints/src/utils/constants.rs | 13 ------------- clippy_lints/src/utils/mod.rs | 1 - 3 files changed, 4 insertions(+), 18 deletions(-) delete mode 100644 clippy_lints/src/utils/constants.rs diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 5bc45c87874b4..84a0df92f5b43 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -1,4 +1,4 @@ -use crate::utils::{constants, snippet_opt, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{snippet_opt, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use rustc_ast::ast::{ BindingMode, Expr, ExprKind, GenericParamKind, Generics, Lit, LitFloatType, LitIntType, LitKind, Mutability, NodeId, Pat, PatKind, UnOp, @@ -6,6 +6,7 @@ use rustc_ast::ast::{ use rustc_ast::visit::FnKind; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; +use rustc_hir::PrimTy; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -264,13 +265,12 @@ impl EarlyLintPass for MiscEarlyLints { fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) { for param in &gen.params { if let GenericParamKind::Type { .. } = param.kind { - let name = param.ident.as_str(); - if constants::BUILTIN_TYPES.contains(&&*name) { + if let Some(prim_ty) = PrimTy::from_name(param.ident.name) { span_lint( cx, BUILTIN_TYPE_SHADOW, param.ident.span, - &format!("this generic shadows the built-in type `{}`", name), + &format!("this generic shadows the built-in type `{}`", prim_ty.name()), ); } } diff --git a/clippy_lints/src/utils/constants.rs b/clippy_lints/src/utils/constants.rs deleted file mode 100644 index 522932f054d89..0000000000000 --- a/clippy_lints/src/utils/constants.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! This module contains some useful constants. - -#![deny(clippy::missing_docs_in_private_items)] - -/// List of the built-in types names. -/// -/// See also [the reference][reference-types] for a list of such types. -/// -/// [reference-types]: https://doc.rust-lang.org/reference/types.html -pub const BUILTIN_TYPES: &[&str] = &[ - "i8", "u8", "i16", "u16", "i32", "u32", "i64", "u64", "i128", "u128", "isize", "usize", "f32", "f64", "bool", - "str", "char", -]; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index d0db3a67533bc..e639d33ed4715 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -8,7 +8,6 @@ pub mod author; pub mod camel_case; pub mod comparisons; pub mod conf; -pub mod constants; mod diagnostics; pub mod eager_or_lazy; pub mod higher; From 6396b8fb7f095919da061ad2bfeb008ee7fb6589 Mon Sep 17 00:00:00 2001 From: Yusuke Tanaka Date: Thu, 4 Feb 2021 00:06:26 +0900 Subject: [PATCH 11/72] Fix file names of flat_map_identity test This commit fixes the file names of the `flat_map_identity` test. Previously, their names were started with `unnecessary_flat_map` even though the lint rule name is `flat_map_identity`. This inconsistency happened probably because the rule name was changed during the discussion in the PR where this rule was introduced. ref: https://github.com/rust-lang/rust-clippy/pull/4231 --- .../{unnecessary_flat_map.fixed => flat_map_identity.fixed} | 0 tests/ui/{unnecessary_flat_map.rs => flat_map_identity.rs} | 0 .../{unnecessary_flat_map.stderr => flat_map_identity.stderr} | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename tests/ui/{unnecessary_flat_map.fixed => flat_map_identity.fixed} (100%) rename tests/ui/{unnecessary_flat_map.rs => flat_map_identity.rs} (100%) rename tests/ui/{unnecessary_flat_map.stderr => flat_map_identity.stderr} (85%) diff --git a/tests/ui/unnecessary_flat_map.fixed b/tests/ui/flat_map_identity.fixed similarity index 100% rename from tests/ui/unnecessary_flat_map.fixed rename to tests/ui/flat_map_identity.fixed diff --git a/tests/ui/unnecessary_flat_map.rs b/tests/ui/flat_map_identity.rs similarity index 100% rename from tests/ui/unnecessary_flat_map.rs rename to tests/ui/flat_map_identity.rs diff --git a/tests/ui/unnecessary_flat_map.stderr b/tests/ui/flat_map_identity.stderr similarity index 85% rename from tests/ui/unnecessary_flat_map.stderr rename to tests/ui/flat_map_identity.stderr index a1cd5745e4949..e4686ae5a5493 100644 --- a/tests/ui/unnecessary_flat_map.stderr +++ b/tests/ui/flat_map_identity.stderr @@ -1,5 +1,5 @@ error: called `flat_map(|x| x)` on an `Iterator` - --> $DIR/unnecessary_flat_map.rs:10:22 + --> $DIR/flat_map_identity.rs:10:22 | LL | let _ = iterator.flat_map(|x| x); | ^^^^^^^^^^^^^^^ help: try: `flatten()` @@ -7,7 +7,7 @@ LL | let _ = iterator.flat_map(|x| x); = note: `-D clippy::flat-map-identity` implied by `-D warnings` error: called `flat_map(std::convert::identity)` on an `Iterator` - --> $DIR/unnecessary_flat_map.rs:13:22 + --> $DIR/flat_map_identity.rs:13:22 | LL | let _ = iterator.flat_map(convert::identity); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` From 78ef0f2f6c17f5933ab4dbab544b76f7da742467 Mon Sep 17 00:00:00 2001 From: nahuakang Date: Wed, 3 Feb 2021 19:45:58 +0100 Subject: [PATCH 12/72] Add additional test cases and improve span lint --- clippy_lints/src/loops.rs | 47 ++++++----------- tests/ui/manual_flatten.rs | 18 +++++-- tests/ui/manual_flatten.stderr | 92 ++++++++++++++++++++++++++++------ 3 files changed, 108 insertions(+), 49 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 5bfdc98bc6a50..817230a29c639 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2034,42 +2034,27 @@ fn check_manual_flatten<'tcx>( // Prepare the help message let mut applicability = Applicability::MaybeIncorrect; - let arg_snippet = snippet_with_applicability( - cx, - arg.span, - "..", - &mut applicability, - ); - // Determine if `arg` is by reference, an `Iterator`, or implicitly adjusted with `into_iter` - let arg_ty = cx.typeck_results().expr_ty(arg); - let hint = if arg_ty.is_ref() { - if has_iter_method(cx, arg_ty).is_none() { - return; - } else if let ExprKind::AddrOf(_, _, arg_expr) = arg.kind { - format!("{}.iter().flatten()", snippet(cx, arg_expr.span, "..")) - } else { - return; - } - } else if let Some(id) = get_trait_def_id(cx, &paths::ITERATOR) { - let is_iterator = implements_trait(cx, arg_ty, id, &[]); - if is_iterator { - format!("{}.flatten()", arg_snippet) - } else { - format!("{}.into_iter().flatten()", arg_snippet) - } - } else { - return - }; + let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability); - span_lint_and_sugg( + span_lint_and_then( cx, MANUAL_FLATTEN, span, &msg, - "try", - hint, - applicability, - ) + |diag| { + let sugg = format!("{}.flatten()", arg_snippet); + diag.span_suggestion( + arg.span, + "try", + sugg, + Applicability::MaybeIncorrect, + ); + diag.span_help( + inner_expr.span, + "also remove the `if let` statement in the for loop", + ); + } + ); } } } diff --git a/tests/ui/manual_flatten.rs b/tests/ui/manual_flatten.rs index b97cceb66f8e6..ea3440f6da214 100644 --- a/tests/ui/manual_flatten.rs +++ b/tests/ui/manual_flatten.rs @@ -4,8 +4,8 @@ fn main() { // Test for loop over implicitly adjusted `Iterator` with `if let` expression let x = vec![Some(1), Some(2), Some(3)]; for n in x { - if let Some(n) = n { - println!("{}", n); + if let Some(y) = n { + println!("{}", y); } } @@ -24,12 +24,22 @@ fn main() { } } + // Test for loop over an implicit reference + // Note: If `clippy::manual_flatten` is made autofixable, this case will + // lead to a follow-up lint `clippy::into_iter_on_ref` + let z = &y; + for n in z { + if let Ok(n) = n { + println!("{}", n); + } + } + // Test for loop over `Iterator` with `if let` expression let z = vec![Some(1), Some(2), Some(3)]; let z = z.iter(); for n in z { - if let Some(n) = n { - println!("{}", n); + if let Some(m) = n { + println!("{}", m); } } diff --git a/tests/ui/manual_flatten.stderr b/tests/ui/manual_flatten.stderr index 754921eb73927..49b8ed0564aee 100644 --- a/tests/ui/manual_flatten.stderr +++ b/tests/ui/manual_flatten.stderr @@ -1,44 +1,108 @@ error: unnecessary `if let` since only the `Some` variant of the iterator element is used --> $DIR/manual_flatten.rs:6:5 | -LL | / for n in x { -LL | | if let Some(n) = n { -LL | | println!("{}", n); +LL | for n in x { + | ^ - help: try: `x.into_iter().flatten()` + | _____| + | | +LL | | if let Some(y) = n { +LL | | println!("{}", y); LL | | } LL | | } - | |_____^ help: try: `x.into_iter().flatten()` + | |_____^ | = note: `-D clippy::manual-flatten` implied by `-D warnings` +help: also remove the `if let` statement in the for loop + --> $DIR/manual_flatten.rs:7:9 + | +LL | / if let Some(y) = n { +LL | | println!("{}", y); +LL | | } + | |_________^ error: unnecessary `if let` since only the `Ok` variant of the iterator element is used --> $DIR/manual_flatten.rs:14:5 | -LL | / for n in y.clone() { +LL | for n in y.clone() { + | ^ --------- help: try: `y.clone().into_iter().flatten()` + | _____| + | | LL | | if let Ok(n) = n { LL | | println!("{}", n); LL | | }; LL | | } - | |_____^ help: try: `y.clone().into_iter().flatten()` + | |_____^ + | +help: also remove the `if let` statement in the for loop + --> $DIR/manual_flatten.rs:15:9 + | +LL | / if let Ok(n) = n { +LL | | println!("{}", n); +LL | | }; + | |_________^ error: unnecessary `if let` since only the `Ok` variant of the iterator element is used --> $DIR/manual_flatten.rs:21:5 | -LL | / for n in &y { +LL | for n in &y { + | ^ -- help: try: `y.iter().flatten()` + | _____| + | | LL | | if let Ok(n) = n { LL | | println!("{}", n); LL | | } LL | | } - | |_____^ help: try: `y.iter().flatten()` + | |_____^ + | +help: also remove the `if let` statement in the for loop + --> $DIR/manual_flatten.rs:22:9 + | +LL | / if let Ok(n) = n { +LL | | println!("{}", n); +LL | | } + | |_________^ -error: unnecessary `if let` since only the `Some` variant of the iterator element is used - --> $DIR/manual_flatten.rs:30:5 +error: unnecessary `if let` since only the `Ok` variant of the iterator element is used + --> $DIR/manual_flatten.rs:31:5 | -LL | / for n in z { -LL | | if let Some(n) = n { +LL | for n in z { + | ^ - help: try: `z.into_iter().flatten()` + | _____| + | | +LL | | if let Ok(n) = n { LL | | println!("{}", n); LL | | } LL | | } - | |_____^ help: try: `z.flatten()` + | |_____^ + | +help: also remove the `if let` statement in the for loop + --> $DIR/manual_flatten.rs:32:9 + | +LL | / if let Ok(n) = n { +LL | | println!("{}", n); +LL | | } + | |_________^ + +error: unnecessary `if let` since only the `Some` variant of the iterator element is used + --> $DIR/manual_flatten.rs:40:5 + | +LL | for n in z { + | ^ - help: try: `z.flatten()` + | _____| + | | +LL | | if let Some(m) = n { +LL | | println!("{}", m); +LL | | } +LL | | } + | |_____^ + | +help: also remove the `if let` statement in the for loop + --> $DIR/manual_flatten.rs:41:9 + | +LL | / if let Some(m) = n { +LL | | println!("{}", m); +LL | | } + | |_________^ -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors From 0767a0f9c76eb97fe924833b192a36186aa74fb5 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 2 Feb 2021 20:24:42 +0100 Subject: [PATCH 13/72] Fix/allow non_fmt_panic in clippy tests. --- tests/missing-test-files.rs | 14 ++++++-------- tests/ui/assertions_on_constants.rs | 2 ++ tests/ui/assertions_on_constants.stderr | 18 +++++++++--------- tests/ui/fallible_impl_from.rs | 2 +- tests/ui/fallible_impl_from.stderr | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/missing-test-files.rs b/tests/missing-test-files.rs index d87bb4be3c3f9..9cef7438d225c 100644 --- a/tests/missing-test-files.rs +++ b/tests/missing-test-files.rs @@ -9,14 +9,12 @@ fn test_missing_tests() { if !missing_files.is_empty() { assert!( false, - format!( - "Didn't see a test file for the following files:\n\n{}\n", - missing_files - .iter() - .map(|s| format!("\t{}", s)) - .collect::>() - .join("\n") - ) + "Didn't see a test file for the following files:\n\n{}\n", + missing_files + .iter() + .map(|s| format!("\t{}", s)) + .collect::>() + .join("\n") ); } } diff --git a/tests/ui/assertions_on_constants.rs b/tests/ui/assertions_on_constants.rs index 60d721c2f2049..e989de6540456 100644 --- a/tests/ui/assertions_on_constants.rs +++ b/tests/ui/assertions_on_constants.rs @@ -1,3 +1,5 @@ +#![allow(non_fmt_panic)] + macro_rules! assert_const { ($len:expr) => { assert!($len > 0); diff --git a/tests/ui/assertions_on_constants.stderr b/tests/ui/assertions_on_constants.stderr index 8f09c8ce9d52a..c66fdf093f514 100644 --- a/tests/ui/assertions_on_constants.stderr +++ b/tests/ui/assertions_on_constants.stderr @@ -1,5 +1,5 @@ error: `assert!(true)` will be optimized out by the compiler - --> $DIR/assertions_on_constants.rs:9:5 + --> $DIR/assertions_on_constants.rs:11:5 | LL | assert!(true); | ^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | assert!(true); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(false)` should probably be replaced - --> $DIR/assertions_on_constants.rs:10:5 + --> $DIR/assertions_on_constants.rs:12:5 | LL | assert!(false); | ^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | assert!(false); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(true)` will be optimized out by the compiler - --> $DIR/assertions_on_constants.rs:11:5 + --> $DIR/assertions_on_constants.rs:13:5 | LL | assert!(true, "true message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | assert!(true, "true message"); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(false, "false message")` should probably be replaced - --> $DIR/assertions_on_constants.rs:12:5 + --> $DIR/assertions_on_constants.rs:14:5 | LL | assert!(false, "false message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | assert!(false, "false message"); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(false, msg.to_uppercase())` should probably be replaced - --> $DIR/assertions_on_constants.rs:15:5 + --> $DIR/assertions_on_constants.rs:17:5 | LL | assert!(false, msg.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | assert!(false, msg.to_uppercase()); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(true)` will be optimized out by the compiler - --> $DIR/assertions_on_constants.rs:18:5 + --> $DIR/assertions_on_constants.rs:20:5 | LL | assert!(B); | ^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | assert!(B); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(false)` should probably be replaced - --> $DIR/assertions_on_constants.rs:21:5 + --> $DIR/assertions_on_constants.rs:23:5 | LL | assert!(C); | ^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | assert!(C); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(false, "C message")` should probably be replaced - --> $DIR/assertions_on_constants.rs:22:5 + --> $DIR/assertions_on_constants.rs:24:5 | LL | assert!(C, "C message"); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | assert!(C, "C message"); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `debug_assert!(true)` will be optimized out by the compiler - --> $DIR/assertions_on_constants.rs:24:5 + --> $DIR/assertions_on_constants.rs:26:5 | LL | debug_assert!(true); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/fallible_impl_from.rs b/tests/ui/fallible_impl_from.rs index 679f4a7dc357d..5d5af4e463297 100644 --- a/tests/ui/fallible_impl_from.rs +++ b/tests/ui/fallible_impl_from.rs @@ -36,7 +36,7 @@ impl From> for Invalid { fn from(s: Option) -> Invalid { let s = s.unwrap(); if !s.is_empty() { - panic!(42); + panic!("42"); } else if s.parse::().unwrap() != 42 { panic!("{:?}", s); } diff --git a/tests/ui/fallible_impl_from.stderr b/tests/ui/fallible_impl_from.stderr index ab976b947b356..f787b30bdabc5 100644 --- a/tests/ui/fallible_impl_from.stderr +++ b/tests/ui/fallible_impl_from.stderr @@ -59,8 +59,8 @@ note: potential failure(s) LL | let s = s.unwrap(); | ^^^^^^^^^^ LL | if !s.is_empty() { -LL | panic!(42); - | ^^^^^^^^^^^ +LL | panic!("42"); + | ^^^^^^^^^^^^^ LL | } else if s.parse::().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^ LL | panic!("{:?}", s); From 9f7f8b71a6f3f6f785bbcfbd7070a94f9ae28cf3 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 3 Feb 2021 10:55:33 +0100 Subject: [PATCH 14/72] Suggest panic!("{}", ..) instead of panic!(..) clippy::expect_fun_call. --- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/expect_fun_call.fixed | 10 +++++----- tests/ui/expect_fun_call.stderr | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a17c5996293e9..4ee423b383b0f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2183,7 +2183,7 @@ fn lint_expect_fun_call( span_replace_word, &format!("use of `{}` followed by a function call", name), "try this", - format!("unwrap_or_else({} {{ panic!({}) }})", closure_args, arg_root_snippet), + format!("unwrap_or_else({} {{ panic!(\"{{}}\", {}) }})", closure_args, arg_root_snippet), applicability, ); } diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed index f3d8a941a92bc..a756d1cf50659 100644 --- a/tests/ui/expect_fun_call.fixed +++ b/tests/ui/expect_fun_call.fixed @@ -74,12 +74,12 @@ fn main() { "foo" } - Some("foo").unwrap_or_else(|| { panic!(get_string()) }); - Some("foo").unwrap_or_else(|| { panic!(get_string()) }); - Some("foo").unwrap_or_else(|| { panic!(get_string()) }); + Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) }); + Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) }); + Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) }); - Some("foo").unwrap_or_else(|| { panic!(get_static_str()) }); - Some("foo").unwrap_or_else(|| { panic!(get_non_static_str(&0).to_string()) }); + Some("foo").unwrap_or_else(|| { panic!("{}", get_static_str()) }); + Some("foo").unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) }); } //Issue #3839 diff --git a/tests/ui/expect_fun_call.stderr b/tests/ui/expect_fun_call.stderr index a492e2df89d47..6dc796f5cee37 100644 --- a/tests/ui/expect_fun_call.stderr +++ b/tests/ui/expect_fun_call.stderr @@ -34,31 +34,31 @@ error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:77:21 | LL | Some("foo").expect(&get_string()); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:78:21 | LL | Some("foo").expect(get_string().as_ref()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:79:21 | LL | Some("foo").expect(get_string().as_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:81:21 | LL | Some("foo").expect(get_static_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_static_str()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_static_str()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:82:21 | LL | Some("foo").expect(get_non_static_str(&0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_non_static_str(&0).to_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:86:16 From 2f8a8d3468050f724473900bcfcc75a110314059 Mon Sep 17 00:00:00 2001 From: nahuakang Date: Thu, 4 Feb 2021 10:51:40 +0100 Subject: [PATCH 15/72] Improve lint message; add note for future autofixable updates --- clippy_lints/src/loops.rs | 2 +- tests/ui/manual_flatten.rs | 4 +++- tests/ui/manual_flatten.stderr | 10 +++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 817230a29c639..663c2df23e22b 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2051,7 +2051,7 @@ fn check_manual_flatten<'tcx>( ); diag.span_help( inner_expr.span, - "also remove the `if let` statement in the for loop", + "...and remove the `if let` statement in the for loop", ); } ); diff --git a/tests/ui/manual_flatten.rs b/tests/ui/manual_flatten.rs index ea3440f6da214..cff68eca93374 100644 --- a/tests/ui/manual_flatten.rs +++ b/tests/ui/manual_flatten.rs @@ -25,7 +25,7 @@ fn main() { } // Test for loop over an implicit reference - // Note: If `clippy::manual_flatten` is made autofixable, this case will + // Note: if `clippy::manual_flatten` is made autofixable, this case will // lead to a follow-up lint `clippy::into_iter_on_ref` let z = &y; for n in z { @@ -44,6 +44,8 @@ fn main() { } // Using the `None` variant should not trigger the lint + // Note: for an autofixable suggestion, the binding in the for loop has to take the + // name of the binding in the `if let` let z = vec![Some(1), Some(2), Some(3)]; for n in z { if n.is_none() { diff --git a/tests/ui/manual_flatten.stderr b/tests/ui/manual_flatten.stderr index 49b8ed0564aee..855dd9130e2fb 100644 --- a/tests/ui/manual_flatten.stderr +++ b/tests/ui/manual_flatten.stderr @@ -12,7 +12,7 @@ LL | | } | |_____^ | = note: `-D clippy::manual-flatten` implied by `-D warnings` -help: also remove the `if let` statement in the for loop +help: ...and remove the `if let` statement in the for loop --> $DIR/manual_flatten.rs:7:9 | LL | / if let Some(y) = n { @@ -33,7 +33,7 @@ LL | | }; LL | | } | |_____^ | -help: also remove the `if let` statement in the for loop +help: ...and remove the `if let` statement in the for loop --> $DIR/manual_flatten.rs:15:9 | LL | / if let Ok(n) = n { @@ -54,7 +54,7 @@ LL | | } LL | | } | |_____^ | -help: also remove the `if let` statement in the for loop +help: ...and remove the `if let` statement in the for loop --> $DIR/manual_flatten.rs:22:9 | LL | / if let Ok(n) = n { @@ -75,7 +75,7 @@ LL | | } LL | | } | |_____^ | -help: also remove the `if let` statement in the for loop +help: ...and remove the `if let` statement in the for loop --> $DIR/manual_flatten.rs:32:9 | LL | / if let Ok(n) = n { @@ -96,7 +96,7 @@ LL | | } LL | | } | |_____^ | -help: also remove the `if let` statement in the for loop +help: ...and remove the `if let` statement in the for loop --> $DIR/manual_flatten.rs:41:9 | LL | / if let Some(m) = n { From 233fe11ce9711a3652141fbe7e9191314fd701d5 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Thu, 4 Feb 2021 19:08:08 +0100 Subject: [PATCH 16/72] Set turbofish for every sugg and add more test cases --- clippy_lints/src/methods/mod.rs | 6 +-- tests/ui/from_iter_instead_of_collect.fixed | 34 ++++++++++++++++ tests/ui/from_iter_instead_of_collect.rs | 21 ++++++++-- tests/ui/from_iter_instead_of_collect.stderr | 42 +++++++++++++++----- 4 files changed, 86 insertions(+), 17 deletions(-) create mode 100644 tests/ui/from_iter_instead_of_collect.fixed diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f53b2f67d1db8..3e356afa2a4d9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4095,11 +4095,7 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< then { // `expr` implements `FromIterator` trait let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); - let sugg = if higher::range(&args[0]).is_some() { - format!("{}.collect::<{}>()", iter_expr, ty) - } else { - format!("{}.collect()", iter_expr) - }; + let sugg = format!("{}.collect::<{}>()", iter_expr, ty); span_lint_and_sugg( cx, FROM_ITER_INSTEAD_OF_COLLECT, diff --git a/tests/ui/from_iter_instead_of_collect.fixed b/tests/ui/from_iter_instead_of_collect.fixed new file mode 100644 index 0000000000000..96701e8639562 --- /dev/null +++ b/tests/ui/from_iter_instead_of_collect.fixed @@ -0,0 +1,34 @@ +// run-rustfix + +#![warn(clippy::from_iter_instead_of_collect)] +#![allow(unused_imports)] + +use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; +use std::iter::FromIterator; + +fn main() { + let iter_expr = std::iter::repeat(5).take(5); + let _ = iter_expr.collect::>(); + + let _ = vec![5, 5, 5, 5].iter().enumerate().collect::>(); + + Vec::from_iter(vec![42u32]); + + let a = vec![0, 1, 2]; + assert_eq!(a, (0..3).collect::>()); + + let mut b = (0..3).collect::>(); + b.push_back(4); + + let values = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]; + let bm = values.iter().cloned().collect::>(); + let mut bar = bm.range(0..2).collect::>(); + bar.insert(&4, &'e'); + + let mut bts = (0..3).collect::>(); + bts.insert(2); + { + use std::collections; + let _ = (0..3).collect::>(); + } +} diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index 6c81366c4df7f..211f57bc5374e 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -1,13 +1,16 @@ +// run-rustfix + #![warn(clippy::from_iter_instead_of_collect)] +#![allow(unused_imports)] -use std::collections::{HashMap, VecDeque}; +use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; use std::iter::FromIterator; fn main() { let iter_expr = std::iter::repeat(5).take(5); - Vec::from_iter(iter_expr); + let _ = Vec::from_iter(iter_expr); - HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + let _ = HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); Vec::from_iter(vec![42u32]); @@ -16,4 +19,16 @@ fn main() { let mut b = VecDeque::from_iter(0..3); b.push_back(4); + + let values = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]; + let bm = BTreeMap::from_iter(values.iter().cloned()); + let mut bar = BTreeMap::from_iter(bm.range(0..2)); + bar.insert(&4, &'e'); + + let mut bts = BTreeSet::from_iter(0..3); + bts.insert(2); + { + use std::collections; + let _ = collections::BTreeSet::from_iter(0..3); + } } diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index e2161dd3b5778..336e25a8adf93 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -1,28 +1,52 @@ error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:8:5 + --> $DIR/from_iter_instead_of_collect.rs:11:13 | -LL | Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect()` +LL | let _ = Vec::from_iter(iter_expr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::>()` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:10:5 + --> $DIR/from_iter_instead_of_collect.rs:13:13 | -LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect()` +LL | let _ = HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:15:19 + --> $DIR/from_iter_instead_of_collect.rs:18:19 | LL | assert_eq!(a, Vec::from_iter(0..3)); | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:17:17 + --> $DIR/from_iter_instead_of_collect.rs:20:17 | LL | let mut b = VecDeque::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` -error: aborting due to 4 previous errors +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:24:14 + | +LL | let bm = BTreeMap::from_iter(values.iter().cloned()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:25:19 + | +LL | let mut bar = BTreeMap::from_iter(bm.range(0..2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:28:19 + | +LL | let mut bts = BTreeSet::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:32:17 + | +LL | let _ = collections::BTreeSet::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: aborting due to 8 previous errors From 7b7e3ca5116983f5485bc9c8a5b2abf490900241 Mon Sep 17 00:00:00 2001 From: Philip Hayes Date: Fri, 29 Jan 2021 22:18:56 -0800 Subject: [PATCH 17/72] Support free functions in disallowed-methods lint In other words, support: `disallowed_methods = ["alloc::vec::Vec::new"]` (a free function) in addition to `disallowed_methods = ["alloc::vec::Vec::leak"]` (a method). Improve the documentation to clarify that users must specify the full qualified path for each disallowed function, which can be confusing for reexports. Include an example `clippy.toml`. Simplify the actual lint pass so we can reuse `utils::fn_def_id`. --- clippy_lints/src/disallowed_method.rs | 52 ++++++++++++------- clippy_lints/src/utils/conf.rs | 2 +- .../toml_disallowed_method/clippy.toml | 2 +- .../conf_disallowed_method.rs | 3 +- .../conf_disallowed_method.stderr | 16 ++++-- 5 files changed, 48 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/disallowed_method.rs b/clippy_lints/src/disallowed_method.rs index 581c3242e3745..56dc6d18a58f2 100644 --- a/clippy_lints/src/disallowed_method.rs +++ b/clippy_lints/src/disallowed_method.rs @@ -1,29 +1,47 @@ -use crate::utils::span_lint; +use crate::utils::{fn_def_id, span_lint}; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Symbol; declare_clippy_lint! { - /// **What it does:** Lints for specific trait methods defined in clippy.toml + /// **What it does:** Denies the configured methods and functions in clippy.toml /// /// **Why is this bad?** Some methods are undesirable in certain contexts, - /// and it would be beneficial to lint for them as needed. + /// and it's beneficial to lint for them as needed. /// - /// **Known problems:** None. + /// **Known problems:** Currently, you must write each function as a + /// fully-qualified path. This lint doesn't support aliases or reexported + /// names; be aware that many types in `std` are actually reexports. + /// + /// For example, if you want to disallow `Duration::as_secs`, your clippy.toml + /// configuration would look like + /// `disallowed-methods = ["core::time::Duration::as_secs"]` and not + /// `disallowed-methods = ["std::time::Duration::as_secs"]` as you might expect. /// /// **Example:** /// + /// An example clippy.toml configuration: + /// ```toml + /// # clippy.toml + /// disallowed-methods = ["alloc::vec::Vec::leak", "std::time::Instant::now"] + /// ``` + /// /// ```rust,ignore - /// // example code where clippy issues a warning - /// foo.bad_method(); // Foo::bad_method is disallowed in the configuration + /// // Example code where clippy issues a warning + /// let xs = vec![1, 2, 3, 4]; + /// xs.leak(); // Vec::leak is disallowed in the config. + /// + /// let _now = Instant::now(); // Instant::now is disallowed in the config. /// ``` + /// /// Use instead: /// ```rust,ignore - /// // example code which does not raise clippy warning - /// goodStruct.bad_method(); // GoodStruct::bad_method is not disallowed + /// // Example code which does not raise clippy warning + /// let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config. + /// xs.push(123); // Vec::push is _not_ disallowed in the config. /// ``` pub DISALLOWED_METHOD, nursery, @@ -50,14 +68,12 @@ impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]); impl<'tcx> LateLintPass<'tcx> for DisallowedMethod { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(_path, _, _args, _) = &expr.kind { - let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); - - let method_call = cx.get_def_path(def_id); - if self.disallowed.contains(&method_call) { - let method = method_call - .iter() - .map(|s| s.to_ident_string()) + if let Some(def_id) = fn_def_id(cx, expr) { + let func_path = cx.get_def_path(def_id); + if self.disallowed.contains(&func_path) { + let func_path_string = func_path + .into_iter() + .map(Symbol::to_ident_string) .collect::>() .join("::"); @@ -65,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethod { cx, DISALLOWED_METHOD, expr.span, - &format!("use of a disallowed method `{}`", method), + &format!("use of a disallowed method `{}`", func_path_string), ); } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index b5a8300376c16..1fb99e04de3b7 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -169,7 +169,7 @@ define_Conf! { (max_fn_params_bools, "max_fn_params_bools": u64, 3), /// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests). (warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false), - /// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses + /// Lint: DISALLOWED_METHOD. The list of disallowed methods, written as fully qualified paths. (disallowed_methods, "disallowed_methods": Vec, Vec::::new()), /// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators. (unreadable_literal_lint_fractions, "unreadable_literal_lint_fractions": bool, true), diff --git a/tests/ui-toml/toml_disallowed_method/clippy.toml b/tests/ui-toml/toml_disallowed_method/clippy.toml index a1f515e443dc5..c0df3b6e8af5d 100644 --- a/tests/ui-toml/toml_disallowed_method/clippy.toml +++ b/tests/ui-toml/toml_disallowed_method/clippy.toml @@ -1 +1 @@ -disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match"] +disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match", "regex::re_unicode::Regex::new"] diff --git a/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs index 3d3f0729abd85..1901a99377ec6 100644 --- a/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs +++ b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs @@ -4,10 +4,9 @@ extern crate regex; use regex::Regex; fn main() { - let a = vec![1, 2, 3, 4]; let re = Regex::new(r"ab.*c").unwrap(); - re.is_match("abc"); + let a = vec![1, 2, 3, 4]; a.iter().sum::(); } diff --git a/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr index ed91b5a6796d8..2b628c67fa751 100644 --- a/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr +++ b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr @@ -1,16 +1,22 @@ +error: use of a disallowed method `regex::re_unicode::Regex::new` + --> $DIR/conf_disallowed_method.rs:7:14 + | +LL | let re = Regex::new(r"ab.*c").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::disallowed-method` implied by `-D warnings` + error: use of a disallowed method `regex::re_unicode::Regex::is_match` - --> $DIR/conf_disallowed_method.rs:10:5 + --> $DIR/conf_disallowed_method.rs:8:5 | LL | re.is_match("abc"); | ^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::disallowed-method` implied by `-D warnings` error: use of a disallowed method `core::iter::traits::iterator::Iterator::sum` - --> $DIR/conf_disallowed_method.rs:12:5 + --> $DIR/conf_disallowed_method.rs:11:5 | LL | a.iter().sum::(); | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors From 67d48e1c5921146b97083c0b89d0c3424104242b Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Feb 2021 00:10:52 +0900 Subject: [PATCH 18/72] fix typo --- tests/ui/zero_div_zero.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/zero_div_zero.rs b/tests/ui/zero_div_zero.rs index 09db130a76431..ed3a9208fc3f0 100644 --- a/tests/ui/zero_div_zero.rs +++ b/tests/ui/zero_div_zero.rs @@ -7,7 +7,7 @@ fn main() { let one_more_f64_nan = 0.0f64 / 0.0f64; let zero = 0.0; let other_zero = 0.0; - let other_nan = zero / other_zero; // fine - this lint doesn't propegate constants. + let other_nan = zero / other_zero; // fine - this lint doesn't propagate constants. let not_nan = 2.0 / 0.0; // not an error: 2/0 = inf let also_not_nan = 0.0 / 2.0; // not an error: 0/2 = 0 } From 79dbf10736defbfee05ba95083ba6e2a012f6cef Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 5 Feb 2021 17:23:04 +0100 Subject: [PATCH 19/72] Use absolute path to Rust repo in ra_setup This will convert the path to the Rust repo to an absolute path. This is important for the clippy_lints/Cargo.toml file. Otherwise if a relative path is passed, rst-analyzer won't find the Rust repo, because it starts the relative path search from the clippy_lints dir, not the rust-clippy dir where the ra_setup command was run from. --- clippy_dev/src/ra_setup.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_dev/src/ra_setup.rs b/clippy_dev/src/ra_setup.rs index a3c329b578b20..d0e2193ddc5e5 100644 --- a/clippy_dev/src/ra_setup.rs +++ b/clippy_dev/src/ra_setup.rs @@ -13,7 +13,9 @@ use std::path::{Path, PathBuf}; /// Panics if `rustc_path` does not lead to a rustc repo or the files could not be read pub fn run(rustc_path: Option<&str>) { // we can unwrap here because the arg is required by clap - let rustc_path = PathBuf::from(rustc_path.unwrap()); + let rustc_path = PathBuf::from(rustc_path.unwrap()) + .canonicalize() + .expect("failed to get the absolute repo path"); assert!(rustc_path.is_dir(), "path is not a directory"); let rustc_source_basedir = rustc_path.join("compiler"); assert!( From 56f7fbb4ae67041fc1d2474da7fe52f5a2fd25a8 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 1 Feb 2021 19:22:31 -0600 Subject: [PATCH 20/72] Cleanup path to local checks --- clippy_lints/src/collapsible_match.rs | 22 +-- clippy_lints/src/eval_order_dependence.rs | 60 +++---- clippy_lints/src/functions.rs | 35 ++-- clippy_lints/src/let_if_seq.rs | 17 +- clippy_lints/src/loops.rs | 168 ++++++------------ clippy_lints/src/manual_ok_or.rs | 9 +- clippy_lints/src/manual_unwrap_or.rs | 8 +- clippy_lints/src/matches.rs | 15 +- clippy_lints/src/methods/mod.rs | 43 ++--- .../src/methods/unnecessary_filter_map.rs | 14 +- clippy_lints/src/to_string_in_display.rs | 11 +- clippy_lints/src/utils/mod.rs | 29 ++- clippy_lints/src/utils/usage.rs | 34 +--- clippy_lints/src/utils/visitors.rs | 16 +- 14 files changed, 180 insertions(+), 301 deletions(-) diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/collapsible_match.rs index 604ba10204697..834f294283e37 100644 --- a/clippy_lints/src/collapsible_match.rs +++ b/clippy_lints/src/collapsible_match.rs @@ -1,10 +1,10 @@ use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{span_lint_and_then, SpanlessEq}; +use crate::utils::{path_to_local, span_lint_and_then, SpanlessEq}; use if_chain::if_chain; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, QPath, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{DefIdTree, TyCtxt}; +use rustc_middle::ty::{DefIdTree, TyCtxt, TypeckResults}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{MultiSpan, Span}; @@ -72,7 +72,7 @@ fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) { if arms_inner.iter().all(|arm| arm.guard.is_none()); // match expression must be a local binding // match { .. } - if let Some(binding_id) = addr_adjusted_binding(expr_in, cx); + if let Some(binding_id) = path_to_local(strip_ref_operators(expr_in, cx.typeck_results())); // one of the branches must be "wild-like" if let Some(wild_inner_arm_idx) = arms_inner.iter().rposition(|arm_inner| arm_is_wild_like(arm_inner, cx.tcx)); let (wild_inner_arm, non_wild_inner_arm) = @@ -175,19 +175,15 @@ fn is_none_ctor(res: Res, tcx: TyCtxt<'_>) -> bool { false } -/// Retrieves a binding ID with optional `&` and/or `*` operators removed. (e.g. `&**foo`) -/// Returns `None` if a non-reference type is de-referenced. -/// For example, if `Vec` is de-referenced to a slice, `None` is returned. -fn addr_adjusted_binding(mut expr: &Expr<'_>, cx: &LateContext<'_>) -> Option { +/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is +/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed. +fn strip_ref_operators<'hir>(mut expr: &'hir Expr<'hir>, typeck_results: &TypeckResults<'_>) -> &'hir Expr<'hir> { loop { match expr.kind { ExprKind::AddrOf(_, _, e) => expr = e, - ExprKind::Path(QPath::Resolved(None, path)) => match path.res { - Res::Local(binding_id) => break Some(binding_id), - _ => break None, - }, - ExprKind::Unary(UnOp::UnDeref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e, - _ => break None, + ExprKind::Unary(UnOp::UnDeref, e) if typeck_results.expr_ty(e).is_ref() => expr = e, + _ => break, } } + expr } diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index bc2b2904698c7..83cee11c3a859 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -1,7 +1,6 @@ -use crate::utils::{get_parent_expr, span_lint, span_lint_and_note}; -use if_chain::if_chain; +use crate::utils::{get_parent_expr, path_to_local, path_to_local_id, span_lint, span_lint_and_note}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{def, BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, QPath, Stmt, StmtKind}; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::ty; @@ -72,20 +71,14 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence { // Find a write to a local variable. match expr.kind { ExprKind::Assign(ref lhs, ..) | ExprKind::AssignOp(_, ref lhs, _) => { - if let ExprKind::Path(ref qpath) = lhs.kind { - if let QPath::Resolved(_, ref path) = *qpath { - if path.segments.len() == 1 { - if let def::Res::Local(var) = cx.qpath_res(qpath, lhs.hir_id) { - let mut visitor = ReadVisitor { - cx, - var, - write_expr: expr, - last_expr: expr, - }; - check_for_unsequenced_reads(&mut visitor); - } - } - } + if let Some(var) = path_to_local(lhs) { + let mut visitor = ReadVisitor { + cx, + var, + write_expr: expr, + last_expr: expr, + }; + check_for_unsequenced_reads(&mut visitor); } }, _ => {}, @@ -304,27 +297,20 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { return; } - match expr.kind { - ExprKind::Path(ref qpath) => { - if_chain! { - if let QPath::Resolved(None, ref path) = *qpath; - if path.segments.len() == 1; - if let def::Res::Local(local_id) = self.cx.qpath_res(qpath, expr.hir_id); - if local_id == self.var; - // Check that this is a read, not a write. - if !is_in_assignment_position(self.cx, expr); - then { - span_lint_and_note( - self.cx, - EVAL_ORDER_DEPENDENCE, - expr.span, - "unsequenced read of a variable", - Some(self.write_expr.span), - "whether read occurs before this write depends on evaluation order" - ); - } - } + if path_to_local_id(expr, self.var) { + // Check that this is a read, not a write. + if !is_in_assignment_position(self.cx, expr) { + span_lint_and_note( + self.cx, + EVAL_ORDER_DEPENDENCE, + expr.span, + "unsequenced read of a variable", + Some(self.write_expr.span), + "whether read occurs before this write depends on evaluation order", + ); } + } + match expr.kind { // We're about to descend a closure. Since we don't know when (or // if) the closure will be evaluated, any reads in it might not // occur here (or ever). Like above, bail to avoid false positives. diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 8795425461033..8344d97472890 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,7 +1,7 @@ use crate::utils::{ attr_by_name, attrs::is_proc_macro, is_must_use_ty, is_trait_impl_item, is_type_diagnostic_item, iter_input_pats, - last_path_segment, match_def_path, must_use_attr, return_ty, snippet, snippet_opt, span_lint, span_lint_and_help, - span_lint_and_then, trait_ref_of_method, type_is_unsafe_function, + last_path_segment, match_def_path, must_use_attr, path_to_local, return_ty, snippet, snippet_opt, span_lint, + span_lint_and_help, span_lint_and_then, trait_ref_of_method, type_is_unsafe_function, }; use if_chain::if_chain; use rustc_ast::ast::Attribute; @@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit; -use rustc_hir::{def::Res, def_id::DefId}; +use rustc_hir::{def::Res, def_id::DefId, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; @@ -658,16 +658,14 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { impl<'a, 'tcx> DerefVisitor<'a, 'tcx> { fn check_arg(&self, ptr: &hir::Expr<'_>) { - if let hir::ExprKind::Path(ref qpath) = ptr.kind { - if let Res::Local(id) = self.cx.qpath_res(qpath, ptr.hir_id) { - if self.ptrs.contains(&id) { - span_lint( - self.cx, - NOT_UNSAFE_PTR_ARG_DEREF, - ptr.span, - "this public function dereferences a raw pointer but is not marked `unsafe`", - ); - } + if let Some(id) = path_to_local(ptr) { + if self.ptrs.contains(&id) { + span_lint( + self.cx, + NOT_UNSAFE_PTR_ARG_DEREF, + ptr.span, + "this public function dereferences a raw pointer but is not marked `unsafe`", + ); } } } @@ -698,7 +696,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { arg.span, &mut tys, ) - && is_mutated_static(self.cx, arg) + && is_mutated_static(arg) { self.mutates_static = true; return; @@ -707,7 +705,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { } }, Assign(ref target, ..) | AssignOp(_, ref target, _) | AddrOf(_, hir::Mutability::Mut, ref target) => { - self.mutates_static |= is_mutated_static(self.cx, target) + self.mutates_static |= is_mutated_static(target) }, _ => {}, } @@ -718,12 +716,13 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { } } -fn is_mutated_static(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool { +fn is_mutated_static(e: &hir::Expr<'_>) -> bool { use hir::ExprKind::{Field, Index, Path}; match e.kind { - Path(ref qpath) => !matches!(cx.qpath_res(qpath, e.hir_id), Res::Local(_)), - Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(cx, inner), + Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)), + Path(_) => true, + Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(inner), _ => false, } } diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 5886c2360e362..6beaa51729a02 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,8 +1,7 @@ -use crate::utils::{snippet, span_lint_and_then, visitors::LocalUsedVisitor}; +use crate::utils::{path_to_local_id, snippet, span_lint_and_then, visitors::LocalUsedVisitor}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::BindingAnnotation; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -66,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { if let hir::ExprKind::If(ref cond, ref then, ref else_) = if_.kind; if !LocalUsedVisitor::new(canonical_id).check_expr(cond); if let hir::ExprKind::Block(ref then, _) = then.kind; - if let Some(value) = check_assign(cx, canonical_id, &*then); + if let Some(value) = check_assign(canonical_id, &*then); if !LocalUsedVisitor::new(canonical_id).check_expr(value); then { let span = stmt.span.to(if_.span); @@ -79,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { let (default_multi_stmts, default) = if let Some(ref else_) = *else_ { if let hir::ExprKind::Block(ref else_, _) = else_.kind { - if let Some(default) = check_assign(cx, canonical_id, else_) { + if let Some(default) = check_assign(canonical_id, else_) { (else_.stmts.len() > 1, default) } else if let Some(ref default) = local.init { (true, &**default) @@ -134,19 +133,13 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { } } -fn check_assign<'tcx>( - cx: &LateContext<'tcx>, - decl: hir::HirId, - block: &'tcx hir::Block<'_>, -) -> Option<&'tcx hir::Expr<'tcx>> { +fn check_assign<'tcx>(decl: hir::HirId, block: &'tcx hir::Block<'_>) -> Option<&'tcx hir::Expr<'tcx>> { if_chain! { if block.expr.is_none(); if let Some(expr) = block.stmts.iter().last(); if let hir::StmtKind::Semi(ref expr) = expr.kind; if let hir::ExprKind::Assign(ref var, ref value, _) = expr.kind; - if let hir::ExprKind::Path(ref qpath) = var.kind; - if let Res::Local(local_id) = cx.qpath_res(qpath, var.hir_id); - if decl == local_id; + if path_to_local_id(var, decl); then { let mut v = LocalUsedVisitor::new(decl); diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 663c2df23e22b..d202072e920dc 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1,14 +1,13 @@ use crate::consts::constant; -use crate::utils::paths; use crate::utils::sugg::Sugg; -use crate::utils::usage::{is_unused, mutated_variables}; +use crate::utils::usage::mutated_variables; use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_ok_ctor, is_refutable, is_some_ctor, - is_type_diagnostic_item, last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, - 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, SpanlessEq, + is_type_diagnostic_item, last_path_segment, match_trait_method, match_type, multispan_sugg, path_to_local, + path_to_local_id, paths, 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, SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast; @@ -877,21 +876,6 @@ fn get_span_of_entire_for_loop(expr: &Expr<'_>) -> Span { } } -fn same_var<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, var: HirId) -> bool { - if_chain! { - if let ExprKind::Path(qpath) = &expr.kind; - if let QPath::Resolved(None, path) = qpath; - if path.segments.len() == 1; - if let Res::Local(local_id) = cx.qpath_res(qpath, expr.hir_id); - then { - // our variable! - local_id == var - } else { - false - } - } -} - /// a wrapper of `Sugg`. Besides what `Sugg` do, this removes unnecessary `0`; /// and also, it avoids subtracting a variable from the same one by replacing it with `0`. /// it exists for the convenience of the overloaded operators while normal functions can do the @@ -1044,14 +1028,9 @@ fn get_details_from_idx<'tcx>( idx: &Expr<'_>, starts: &[Start<'tcx>], ) -> Option<(StartKind<'tcx>, Offset)> { - fn get_start<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option> { - starts.iter().find_map(|start| { - if same_var(cx, e, start.id) { - Some(start.kind) - } else { - None - } - }) + fn get_start<'tcx>(e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option> { + let id = path_to_local(e)?; + starts.iter().find(|start| start.id == id).map(|start| start.kind) } fn get_offset<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option> { @@ -1060,7 +1039,7 @@ fn get_details_from_idx<'tcx>( ast::LitKind::Int(x, _ty) => Some(Sugg::NonParen(x.to_string().into())), _ => None, }, - ExprKind::Path(..) if get_start(cx, e, starts).is_none() => Some(Sugg::hir(cx, e, "???")), + ExprKind::Path(..) if get_start(e, starts).is_none() => Some(Sugg::hir(cx, e, "???")), _ => None, } } @@ -1068,18 +1047,18 @@ fn get_details_from_idx<'tcx>( match idx.kind { ExprKind::Binary(op, lhs, rhs) => match op.node { BinOpKind::Add => { - let offset_opt = get_start(cx, lhs, starts) + let offset_opt = get_start(lhs, starts) .and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, o))) - .or_else(|| get_start(cx, rhs, starts).and_then(|s| get_offset(cx, lhs, starts).map(|o| (s, o)))); + .or_else(|| get_start(rhs, starts).and_then(|s| get_offset(cx, lhs, starts).map(|o| (s, o)))); offset_opt.map(|(s, o)| (s, Offset::positive(o))) }, BinOpKind::Sub => { - get_start(cx, lhs, starts).and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, Offset::negative(o)))) + get_start(lhs, starts).and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, Offset::negative(o)))) }, _ => None, }, - ExprKind::Path(..) => get_start(cx, idx, starts).map(|s| (s, Offset::empty())), + ExprKind::Path(..) => get_start(idx, starts).map(|s| (s, Offset::empty())), _ => None, } } @@ -1096,11 +1075,10 @@ fn get_assignment<'tcx>(e: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, &'tcx /// The returned iterator yields `None` if no assignment expressions are there, /// filtering out the increments of the given whitelisted loop counters; /// because its job is to make sure there's nothing other than assignments and the increments. -fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( - cx: &'a LateContext<'tcx>, +fn get_assignments<'a, 'tcx>( Block { stmts, expr, .. }: &'tcx Block<'tcx>, - loop_counters: &'c [Start<'tcx>], -) -> impl Iterator, &'tcx Expr<'tcx>)>> + 'c { + loop_counters: &'a [Start<'tcx>], +) -> impl Iterator, &'tcx Expr<'tcx>)>> + 'a { // As the `filter` and `map` below do different things, I think putting together // just increases complexity. (cc #3188 and #4193) stmts @@ -1112,12 +1090,14 @@ fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( .chain((*expr).into_iter()) .filter(move |e| { if let ExprKind::AssignOp(_, place, _) = e.kind { - !loop_counters - .iter() - // skip the first item which should be `StartKind::Range` - // this makes it possible to use the slice with `StartKind::Range` in the same iterator loop. - .skip(1) - .any(|counter| same_var(cx, place, counter.id)) + path_to_local(place).map_or(false, |id| { + !loop_counters + .iter() + // skip the first item which should be `StartKind::Range` + // this makes it possible to use the slice with `StartKind::Range` in the same iterator loop. + .skip(1) + .any(|counter| counter.id == id) + }) } else { true } @@ -1174,7 +1154,7 @@ fn build_manual_memcpy_suggestion<'tcx>( if method.ident.name == sym!(len); if len_args.len() == 1; if let Some(arg) = len_args.get(0); - if var_def_id(cx, arg) == var_def_id(cx, base); + if path_to_local(arg) == path_to_local(base); then { if sugg.as_str() == end_str { sugg::EMPTY.into() @@ -1279,7 +1259,7 @@ fn detect_manual_memcpy<'tcx>( if let Some(loop_counters) = get_loop_counters(cx, block, expr) { starts.extend(loop_counters); } - iter_a = Some(get_assignments(cx, block, &starts)); + iter_a = Some(get_assignments(block, &starts)); } else { iter_b = Some(get_assignment(body)); } @@ -1301,7 +1281,7 @@ fn detect_manual_memcpy<'tcx>( if let Some((start_right, offset_right)) = get_details_from_idx(cx, &idx_right, &starts); // Source and destination must be different - if var_def_id(cx, base_left) != var_def_id(cx, base_right); + if path_to_local(base_left) != path_to_local(base_right); then { Some((IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left }, IndexExpr { base: base_right, idx: start_right, idx_offset: offset_right })) @@ -2018,9 +1998,7 @@ fn check_manual_flatten<'tcx>( ) = inner_expr.kind; // Ensure match_expr in `if let` statement is the same as the pat from the for-loop if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind; - if let ExprKind::Path(QPath::Resolved(None, match_expr_path)) = match_expr.kind; - if let Res::Local(match_expr_path_id) = match_expr_path.res; - if pat_hir_id == match_expr_path_id; + if path_to_local_id(match_expr, pat_hir_id); // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result` if let PatKind::TupleStruct(QPath::Resolved(None, path), _, _) = match_arms[0].pat.kind; let some_ctor = is_some_ctor(cx, path.res); @@ -2131,20 +2109,11 @@ fn mut_warn_with_span(cx: &LateContext<'_>, span: Option) { fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option { if_chain! { - if let ExprKind::Path(ref qpath) = bound.kind; - if let QPath::Resolved(None, _) = *qpath; + if let Some(hir_id) = path_to_local(bound); + if let Node::Binding(pat) = cx.tcx.hir().get(hir_id); + if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind; then { - let res = cx.qpath_res(qpath, bound.hir_id); - if let Res::Local(hir_id) = res { - let node_str = cx.tcx.hir().get(hir_id); - if_chain! { - if let Node::Binding(pat) = node_str; - if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind; - then { - return Some(hir_id); - } - } - } + return Some(hir_id); } } None @@ -2179,7 +2148,9 @@ fn check_for_mutation<'tcx>( fn pat_is_wild<'tcx>(pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { match *pat { PatKind::Wild => true, - PatKind::Binding(.., ident, None) if ident.as_str().starts_with('_') => is_unused(&ident, body), + PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => { + !LocalUsedVisitor::new(id).check_expr(body) + }, _ => false, } } @@ -2215,7 +2186,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { if let QPath::Resolved(None, ref seqvar) = *seqpath; if seqvar.segments.len() == 1; then { - let index_used_directly = same_var(self.cx, idx, self.var); + let index_used_directly = path_to_local_id(idx, self.var); let indexed_indirectly = { let mut used_visitor = LocalUsedVisitor::new(self.var); walk_expr(&mut used_visitor, idx); @@ -2286,17 +2257,14 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { if_chain! { // directly using a variable - if let ExprKind::Path(ref qpath) = expr.kind; - if let QPath::Resolved(None, ref path) = *qpath; - if path.segments.len() == 1; + if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind; + if let Res::Local(local_id) = path.res; then { - if let Res::Local(local_id) = self.cx.qpath_res(qpath, expr.hir_id) { - if local_id == self.var { - self.nonindex = true; - } else { - // not the correct variable, but still a variable - self.referenced.insert(path.segments[0].ident.name); - } + if local_id == self.var { + self.nonindex = true; + } else { + // not the correct variable, but still a variable + self.referenced.insert(path.segments[0].ident.name); } } } @@ -2354,7 +2322,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { } fn is_used_inside<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, container: &'tcx Expr<'_>) -> bool { - let def_id = match var_def_id(cx, expr) { + let def_id = match path_to_local(expr) { Some(id) => id, None => return false, }; @@ -2367,12 +2335,11 @@ fn is_used_inside<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, container: } fn is_iterator_used_after_while_let<'tcx>(cx: &LateContext<'tcx>, iter_expr: &'tcx Expr<'_>) -> bool { - let def_id = match var_def_id(cx, iter_expr) { + let def_id = match path_to_local(iter_expr) { Some(id) => id, None => return false, }; let mut visitor = VarUsedAfterLoopVisitor { - cx, def_id, iter_expr_id: iter_expr.hir_id, past_while_let: false, @@ -2384,20 +2351,19 @@ fn is_iterator_used_after_while_let<'tcx>(cx: &LateContext<'tcx>, iter_expr: &'t visitor.var_used_after_while_let } -struct VarUsedAfterLoopVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, +struct VarUsedAfterLoopVisitor { def_id: HirId, iter_expr_id: HirId, past_while_let: bool, var_used_after_while_let: bool, } -impl<'a, 'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if self.past_while_let { - if Some(self.def_id) == var_def_id(self.cx, expr) { + if path_to_local_id(expr, self.def_id) { self.var_used_after_while_let = true; } } else if self.iter_expr_id == expr.hir_id { @@ -2519,7 +2485,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { } // If node is a variable - if let Some(def_id) = var_def_id(self.cx, expr) { + if let Some(def_id) = path_to_local(expr) { if let Some(parent) = get_parent_expr(self.cx, expr) { let state = self.states.entry(def_id).or_insert(IncrementVisitorVarState::Initial); if *state == IncrementVisitorVarState::IncrOnce { @@ -2646,7 +2612,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } // If node is the desired variable, see how it's used - if var_def_id(self.cx, expr) == Some(self.var_id) { + if path_to_local_id(expr, self.var_id) { if self.past_loop { self.state = InitializeVisitorState::DontWarn; return; @@ -2693,16 +2659,6 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } } -fn var_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - if let ExprKind::Path(ref qpath) = expr.kind { - let path_res = cx.qpath_res(qpath, expr.hir_id); - if let Res::Local(hir_id) = path_res { - return Some(hir_id); - } - } - None -} - fn is_loop(expr: &Expr<'_>) -> bool { matches!(expr.kind, ExprKind::Loop(..)) } @@ -2725,8 +2681,8 @@ fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) fn is_loop_nested(cx: &LateContext<'_>, loop_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool { let mut id = loop_expr.hir_id; - let iter_name = if let Some(name) = path_name(iter_expr) { - name + let iter_id = if let Some(id) = path_to_local(iter_expr) { + id } else { return true; }; @@ -2744,7 +2700,7 @@ fn is_loop_nested(cx: &LateContext<'_>, loop_expr: &Expr<'_>, iter_expr: &Expr<' Some(Node::Block(block)) => { let mut block_visitor = LoopNestVisitor { hir_id: id, - iterator: iter_name, + iterator: iter_id, nesting: Unknown, }; walk_block(&mut block_visitor, block); @@ -2772,7 +2728,7 @@ use self::Nesting::{LookFurther, RuledOut, Unknown}; struct LoopNestVisitor { hir_id: HirId, - iterator: Symbol, + iterator: HirId, nesting: Nesting, } @@ -2797,7 +2753,7 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { } match expr.kind { ExprKind::Assign(ref path, _, _) | ExprKind::AssignOp(_, ref path, _) => { - if match_var(path, self.iterator) { + if path_to_local_id(path, self.iterator) { self.nesting = RuledOut; } }, @@ -2809,8 +2765,8 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { if self.nesting != Unknown { return; } - if let PatKind::Binding(.., span_name, _) = pat.kind { - if self.iterator == span_name.name { + if let PatKind::Binding(_, id, ..) = pat.kind { + if id == self.iterator { self.nesting = RuledOut; return; } @@ -2823,16 +2779,6 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { } } -fn path_name(e: &Expr<'_>) -> Option { - if let ExprKind::Path(QPath::Resolved(_, ref path)) = e.kind { - let segments = &path.segments; - if segments.len() == 1 { - return Some(segments[0].ident.name); - } - }; - None -} - fn check_infinite_loop<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) { if constant(cx, cx.typeck_results(), cond).is_some() { // A pure constant condition (e.g., `while false`) is not linted. @@ -3194,7 +3140,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if same_var(self.cx, expr, self.id) { + if path_to_local_id(expr, self.id) { self.count += 1; } else { walk_expr(self, expr); diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index 8c77e155b70ce..efb05b8ffdf4f 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -1,9 +1,10 @@ use crate::utils::{ - indent_of, is_type_diagnostic_item, match_qpath, paths, reindent_multiline, snippet_opt, span_lint_and_sugg, + indent_of, is_type_diagnostic_item, match_qpath, path_to_local_id, paths, reindent_multiline, snippet_opt, + span_lint_and_sugg, }; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{def, Expr, ExprKind, PatKind, QPath}; +use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -90,8 +91,6 @@ fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; if match_qpath(ok_path, &paths::RESULT_OK); - if let ExprKind::Path(QPath::Resolved(_, ok_arg_path)) = ok_arg.kind; - if let def::Res::Local(ok_arg_path_id) = ok_arg_path.res; - then { param_id == ok_arg_path_id } else { false } + then { path_to_local_id(ok_arg, param_id) } else { false } } } diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 9e2c6c7f231da..b452225b5db6c 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -1,9 +1,9 @@ use crate::consts::constant_simple; use crate::utils; -use crate::utils::sugg; +use crate::utils::{path_to_local_id, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{def, Arm, Expr, ExprKind, Pat, PatKind, QPath}; +use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind}; use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -83,9 +83,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if utils::match_qpath(unwrap_qpath, &utils::paths::OPTION_SOME) || utils::match_qpath(unwrap_qpath, &utils::paths::RESULT_OK); if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind; - if let ExprKind::Path(QPath::Resolved(_, body_path)) = unwrap_arm.body.kind; - if let def::Res::Local(body_path_hir_id) = body_path.res; - if body_path_hir_id == binding_hir_id; + if path_to_local_id(unwrap_arm.body, binding_hir_id); if !utils::usage::contains_return_break_continue_macro(or_arm.body); then { Some(or_arm) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index ba7b9bd04248d..c4aa2b30e7b52 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1,11 +1,12 @@ use crate::consts::{constant, miri_to_const, Constant}; use crate::utils::sugg::Sugg; -use crate::utils::usage::is_unused; +use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ - expr_block, get_arg_name, get_parent_expr, implements_trait, 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, + expr_block, get_parent_expr, implements_trait, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, + is_type_diagnostic_item, is_wild, match_qpath, match_type, meets_msrv, multispan_sugg, path_to_local_id, peel_hir_pat_refs, peel_mid_ty_refs, peel_n_hir_expr_refs, remove_blocks, snippet, snippet_block, snippet_opt, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, + strip_pat_refs, }; use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; use if_chain::if_chain; @@ -616,9 +617,9 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if let PatKind::TupleStruct( QPath::Resolved(None, ref variant_name), ref args, _) = arms[0].pat.kind; if args.len() == 1; - if let Some(arg) = get_arg_name(&args[0]); + if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind; let body = remove_blocks(&arms[0].body); - if match_var(body, arg); + if path_to_local_id(body, arg); then { let mut applicability = Applicability::MachineApplicable; @@ -922,8 +923,8 @@ fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { if !matching_wild { // Looking for unused bindings (i.e.: `_e`) inner.iter().for_each(|pat| { - if let PatKind::Binding(.., ident, None) = &pat.kind { - if ident.as_str().starts_with('_') && is_unused(ident, arm.body) { + if let PatKind::Binding(_, id, ident, None) = pat.kind { + if ident.as_str().starts_with('_') && !LocalUsedVisitor::new(id).check_expr(arm.body) { ident_bind_name = (&ident.name.as_str()).to_string(); matching_wild = true; } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a17c5996293e9..3dc4cd278e6b2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -15,8 +15,7 @@ use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def::Res; -use rustc_hir::{Expr, ExprKind, PatKind, QPath, TraitItem, TraitItemKind, UnOp}; +use rustc_hir::{Expr, ExprKind, PatKind, TraitItem, TraitItemKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; @@ -30,12 +29,12 @@ use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_return, 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, 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, + contains_return, contains_ty, 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, meets_msrv, method_calls, method_chain_args, path_to_local_id, 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, strip_pat_refs, sugg, walk_ptrs_ty_depth, + SpanlessEq, }; declare_clippy_lint! { @@ -2396,11 +2395,12 @@ fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: if bin_op.node == op; // Extract the names of the two arguments to the closure - if let Some(first_arg_ident) = get_arg_name(&closure_body.params[0].pat); - if let Some(second_arg_ident) = get_arg_name(&closure_body.params[1].pat); + if let [param_a, param_b] = closure_body.params; + if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(¶m_a.pat).kind; + if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(¶m_b.pat).kind; - if match_var(&*left_expr, first_arg_ident); - if replacement_has_args || match_var(&*right_expr, second_arg_ident); + if path_to_local_id(left_expr, first_arg_id); + if replacement_has_args || path_to_local_id(right_expr, second_arg_id); then { let mut applicability = Applicability::MachineApplicable; @@ -3068,10 +3068,8 @@ fn lint_filter_map<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_f }; // let the filter closure arg and the map closure arg be equal if_chain! { - if let ExprKind::Path(QPath::Resolved(None, a_path)) = a_path.kind; - if let ExprKind::Path(QPath::Resolved(None, b_path)) = b.kind; - if a_path.res == Res::Local(filter_param_id); - if b_path.res == Res::Local(map_param_id); + if path_to_local_id(a_path, filter_param_id); + if path_to_local_id(b, map_param_id); if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b)); then { return true; @@ -3255,8 +3253,9 @@ fn lint_search_is_some<'tcx>( then { if let hir::PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) - } else if let Some(name) = get_arg_name(&closure_arg.pat) { - Some(search_snippet.replace(&format!("*{}", name), &name.as_str())) + } else if let PatKind::Binding(_, _, ident, _) = strip_pat_refs(&closure_arg.pat).kind { + let name = &*ident.name.as_str(); + Some(search_snippet.replace(&format!("*{}", name), name)) } else { None } @@ -3688,9 +3687,7 @@ fn lint_option_as_ref_deref<'tcx>( hir::ExprKind::MethodCall(_, _, args, _) => { if_chain! { if args.len() == 1; - if let hir::ExprKind::Path(qpath) = &args[0].kind; - if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, args[0].hir_id); - if closure_body.params[0].pat.hir_id == local_id; + if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id); let adj = cx .typeck_results() .expr_adjustments(&args[0]) @@ -3710,10 +3707,8 @@ fn lint_option_as_ref_deref<'tcx>( if_chain! { if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner1) = inner.kind; if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner2) = inner1.kind; - if let hir::ExprKind::Path(ref qpath) = inner2.kind; - if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, inner2.hir_id); then { - closure_body.params[0].pat.hir_id == local_id + path_to_local_id(inner2, closure_body.params[0].pat.hir_id) } else { false } diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index d98e6160d3085..5691fcb88e95c 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,8 +1,6 @@ -use crate::utils::paths; use crate::utils::usage::mutated_variables; -use crate::utils::{match_qpath, match_trait_method, span_lint}; +use crate::utils::{match_qpath, match_trait_method, path_to_local_id, paths, span_lint}; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; @@ -59,14 +57,8 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc if let hir::ExprKind::Path(ref path) = func.kind; then { if match_qpath(path, &paths::OPTION_SOME) { - if_chain! { - if let hir::ExprKind::Path(path) = &args[0].kind; - if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id); - then { - if arg_id == *local { - return (false, false) - } - } + if path_to_local_id(&args[0], arg_id) { + return (false, false) } return (true, false); } diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs index fa508df865e48..fdd105e624605 100644 --- a/clippy_lints/src/to_string_in_display.rs +++ b/clippy_lints/src/to_string_in_display.rs @@ -1,6 +1,5 @@ -use crate::utils::{match_def_path, match_trait_method, paths, span_lint}; +use crate::utils::{match_def_path, match_trait_method, path_to_local_id, paths, span_lint}; use if_chain::if_chain; -use rustc_hir::def::Res; use rustc_hir::{Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -89,14 +88,12 @@ impl LateLintPass<'_> for ToStringInDisplay { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { + if self.in_display_impl; + if let Some(self_hir_id) = self.self_hir_id; if let ExprKind::MethodCall(ref path, _, args, _) = expr.kind; if path.ident.name == sym!(to_string); if match_trait_method(cx, expr, &paths::TO_STRING); - if self.in_display_impl; - if let ExprKind::Path(ref qpath) = args[0].kind; - if let Res::Local(hir_id) = cx.qpath_res(qpath, args[0].hir_id); - if let Some(self_hir_id) = self.self_hir_id; - if hir_id == self_hir_id; + if path_to_local_id(&args[0], self_hir_id); then { span_lint( cx, diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index cf93ee0a7a5c6..15a254244c18d 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -307,6 +307,22 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { .all(|(a, b)| a.ident.name.as_str() == *b) } +/// If the expression is a path to a local, returns the canonical `HirId` of the local. +pub fn path_to_local(expr: &Expr<'_>) -> Option { + if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind { + if let Res::Local(id) = path.res { + return Some(id); + } + } + None +} + +/// Returns true if the expression is a path to a local with the specified `HirId`. +/// Use this function to see if an expression matches a function argument or a match binding. +pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool { + path_to_local(expr) == Some(id) +} + /// Gets the definition associated to a path. #[allow(clippy::shadow_unrelated)] // false positive #6563 pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res { @@ -1135,9 +1151,7 @@ pub fn is_try<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pat.kind; if match_qpath(path, &paths::RESULT_OK[1..]); if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind; - if let ExprKind::Path(QPath::Resolved(None, ref path)) = arm.body.kind; - if let Res::Local(lid) = path.res; - if lid == hir_id; + if path_to_local_id(arm.body, hir_id); then { return true; } @@ -1181,12 +1195,11 @@ pub fn is_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow } -pub fn get_arg_name(pat: &Pat<'_>) -> Option { - match pat.kind { - PatKind::Binding(.., ident, None) => Some(ident.name), - PatKind::Ref(ref subpat, _) => get_arg_name(subpat), - _ => None, +pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> { + while let PatKind::Ref(subpat, _) = pat.kind { + pat = subpat; } + pat } pub fn int_bits(tcx: TyCtxt<'_>, ity: ty::IntTy) -> u64 { diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index fc0db7f64ec95..7c7580a2c6612 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -1,16 +1,14 @@ use crate::utils; -use crate::utils::match_var; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit; -use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; use rustc_hir::{Expr, ExprKind, HirId, Path}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; use rustc_middle::ty; -use rustc_span::symbol::{Ident, Symbol}; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined. @@ -81,36 +79,6 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { } } -pub struct UsedVisitor { - pub var: Symbol, // var to look for - pub used: bool, // has the var been used otherwise? -} - -impl<'tcx> Visitor<'tcx> for UsedVisitor { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if match_var(expr, self.var) { - self.used = true; - } else { - walk_expr(self, expr); - } - } - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None - } -} - -pub fn is_unused<'tcx>(ident: &'tcx Ident, body: &'tcx Expr<'_>) -> bool { - let mut visitor = UsedVisitor { - var: ident.name, - used: false, - }; - walk_expr(&mut visitor, body); - !visitor.used -} - pub struct ParamBindingIdCollector { binding_hir_ids: Vec, } diff --git a/clippy_lints/src/utils/visitors.rs b/clippy_lints/src/utils/visitors.rs index ebf69df31ca41..a4064c3e705cd 100644 --- a/clippy_lints/src/utils/visitors.rs +++ b/clippy_lints/src/utils/visitors.rs @@ -1,7 +1,7 @@ +use crate::utils::path_to_local_id; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::intravisit::{self, walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{Arm, Expr, ExprKind, HirId, QPath, Stmt}; +use rustc_hir::{Arm, Expr, HirId, Stmt}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; @@ -168,15 +168,11 @@ impl<'v> Visitor<'v> for LocalUsedVisitor { type Map = Map<'v>; fn visit_expr(&mut self, expr: &'v Expr<'v>) { - if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind { - if let Res::Local(id) = path.res { - if id == self.local_hir_id { - self.used = true; - return; - } - } + if path_to_local_id(expr, self.local_hir_id) { + self.used = true; + } else { + walk_expr(self, expr); } - walk_expr(self, expr); } fn nested_visit_map(&mut self) -> NestedVisitorMap { From eb9c6698ee36570efe79343d746afa3dcd04c7a9 Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Sun, 20 Dec 2020 11:48:56 +0100 Subject: [PATCH 21/72] First version of the lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 4 ++ .../src/semicolon_if_nothing_returned.rs | 58 +++++++++++++++++++ tests/ui/semicolon_if_nothing_returned.rs | 18 ++++++ tests/ui/semicolon_if_nothing_returned.stderr | 17 ++++++ 5 files changed, 98 insertions(+) create mode 100644 clippy_lints/src/semicolon_if_nothing_returned.rs create mode 100644 tests/ui/semicolon_if_nothing_returned.rs create mode 100644 tests/ui/semicolon_if_nothing_returned.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 45321751ba7e8..d0164d3be377f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2185,6 +2185,7 @@ Released 2018-09-13 [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some [`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment +[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7f5c4f56f9e05..f6014c246d685 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -310,6 +310,7 @@ mod regex; mod repeat_once; mod returns; mod self_assignment; +mod semicolon_if_nothing_returned; mod serde_api; mod shadow; mod single_component_path_imports; @@ -876,6 +877,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &returns::LET_AND_RETURN, &returns::NEEDLESS_RETURN, &self_assignment::SELF_ASSIGNMENT, + &semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED, &serde_api::SERDE_API_MISUSE, &shadow::SHADOW_REUSE, &shadow::SHADOW_SAME, @@ -1237,6 +1239,7 @@ 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 manual_ok_or::ManualOkOr); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); + store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned); store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::>(); store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods)); @@ -1364,6 +1367,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ranges::RANGE_PLUS_ONE), LintId::of(&redundant_else::REDUNDANT_ELSE), LintId::of(&ref_option_ref::REF_OPTION_REF), + LintId::of(&semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), LintId::of(&shadow::SHADOW_UNRELATED), LintId::of(&strings::STRING_ADD_ASSIGN), LintId::of(&trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS), diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs new file mode 100644 index 0000000000000..99e5841d5a99a --- /dev/null +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -0,0 +1,58 @@ +use crate::utils::{match_def_path, paths, span_lint_and_then, sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::*; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** + /// + /// **Why is this bad?** + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // example code where clippy issues a warning + /// ``` + /// Use instead: + /// ```rust + /// // example code which does not raise clippy warning + /// ``` + pub SEMICOLON_IF_NOTHING_RETURNED, + pedantic, + "default lint description" +} + +declare_lint_pass!(SemicolonIfNothingReturned => [SEMICOLON_IF_NOTHING_RETURNED]); + +impl LateLintPass<'_> for SemicolonIfNothingReturned { + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { + if_chain! { + if let Some(expr) = block.expr; + let t_expr = cx.typeck_results().expr_ty(expr); + if t_expr.is_unit(); + then { + let sugg = sugg::Sugg::hir(cx, &expr, ".."); + let suggestion = format!("{0};", sugg); + span_lint_and_then( + cx, + SEMICOLON_IF_NOTHING_RETURNED, + expr.span, + "add `;` to terminate block", + | diag | { + diag.span_suggestion( + expr.span, + "add `;`", + suggestion, + Applicability::MaybeIncorrect, + ); + } + ) + } + } + } +} diff --git a/tests/ui/semicolon_if_nothing_returned.rs b/tests/ui/semicolon_if_nothing_returned.rs new file mode 100644 index 0000000000000..6790e91d81338 --- /dev/null +++ b/tests/ui/semicolon_if_nothing_returned.rs @@ -0,0 +1,18 @@ +#![warn(clippy::semicolon_if_nothing_returned)] + +fn get_unit() {} + +// the functions below trigger the lint +fn main() { + println!("Hello") +} + +fn hello() { + get_unit() +} + +// this is fine +fn print_sum(a: i32, b: i32) { + println!("{}", a + b); + assert_eq!(true, false); +} diff --git a/tests/ui/semicolon_if_nothing_returned.stderr b/tests/ui/semicolon_if_nothing_returned.stderr new file mode 100644 index 0000000000000..ecb284ecf045f --- /dev/null +++ b/tests/ui/semicolon_if_nothing_returned.stderr @@ -0,0 +1,17 @@ +error: add `;` to terminate block + --> $DIR/semicolon_if_nothing_returned.rs:7:5 + | +LL | println!("Hello") + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings` + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: add `;` to terminate block + --> $DIR/semicolon_if_nothing_returned.rs:11:5 + | +LL | get_unit() + | ^^^^^^^^^^ help: add `;`: `get_unit();` + +error: aborting due to 2 previous errors + From f907986580887ba8b0f30d91792bae81b394ab91 Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Mon, 21 Dec 2020 18:24:08 +0100 Subject: [PATCH 22/72] Added documentation --- .../src/semicolon_if_nothing_returned.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 99e5841d5a99a..84d14b9b48abc 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -7,24 +7,31 @@ use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** + /// **What it does:** Looks for blocks of expressions and fires if the last expression returns `()` + /// but is not followed by a semicolon. /// - /// **Why is this bad?** + /// **Why is this bad?** The semicolon might be optional but when + /// extending the block with new code, it doesn't require a change in previous last line. + /// It's also more idiomatic. /// /// **Known problems:** None. /// /// **Example:** /// /// ```rust - /// // example code where clippy issues a warning + /// fn main() { + /// println!("Hello world") + /// } /// ``` /// Use instead: /// ```rust - /// // example code which does not raise clippy warning + /// fn main() { + /// println!("Hello world"); + /// } /// ``` pub SEMICOLON_IF_NOTHING_RETURNED, pedantic, - "default lint description" + "add a semicolon if nothing is returned" } declare_lint_pass!(SemicolonIfNothingReturned => [SEMICOLON_IF_NOTHING_RETURNED]); From 55bfaa12d346572aecfe190a964b122932e22521 Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Fri, 5 Feb 2021 18:54:13 +0100 Subject: [PATCH 23/72] Fixed macro edge case for `semicolon_if_nothing_returned lint` --- .../src/semicolon_if_nothing_returned.rs | 16 +++++++--- tests/ui/semicolon_if_nothing_returned.rs | 30 +++++++++++++++++++ tests/ui/semicolon_if_nothing_returned.stderr | 12 ++++++-- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 84d14b9b48abc..22cd10ced189f 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,9 +1,8 @@ -use crate::utils::{match_def_path, paths, span_lint_and_then, sugg}; +use crate::utils::{in_macro, span_lint_and_then, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::*; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -20,13 +19,13 @@ declare_clippy_lint! { /// /// ```rust /// fn main() { - /// println!("Hello world") + /// println!("Hello world") /// } /// ``` /// Use instead: /// ```rust /// fn main() { - /// println!("Hello world"); + /// println!("Hello world"); /// } /// ``` pub SEMICOLON_IF_NOTHING_RETURNED, @@ -39,10 +38,19 @@ declare_lint_pass!(SemicolonIfNothingReturned => [SEMICOLON_IF_NOTHING_RETURNED] impl LateLintPass<'_> for SemicolonIfNothingReturned { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { if_chain! { + if !in_macro(block.span); if let Some(expr) = block.expr; let t_expr = cx.typeck_results().expr_ty(expr); if t_expr.is_unit(); then { + match expr.kind { + ExprKind::Loop(..) | + ExprKind::Match(..) | + ExprKind::Block(..) | + ExprKind::If(..) if !in_macro(expr.span) => return, + _ => (), + } + let sugg = sugg::Sugg::hir(cx, &expr, ".."); let suggestion = format!("{0};", sugg); span_lint_and_then( diff --git a/tests/ui/semicolon_if_nothing_returned.rs b/tests/ui/semicolon_if_nothing_returned.rs index 6790e91d81338..2c07cc9df40d6 100644 --- a/tests/ui/semicolon_if_nothing_returned.rs +++ b/tests/ui/semicolon_if_nothing_returned.rs @@ -1,4 +1,5 @@ #![warn(clippy::semicolon_if_nothing_returned)] +#![feature(label_break_value)] fn get_unit() {} @@ -11,8 +12,37 @@ fn hello() { get_unit() } +fn basic101(x: i32) { + let y: i32; + y = x + 1 +} + // this is fine fn print_sum(a: i32, b: i32) { println!("{}", a + b); assert_eq!(true, false); } + +fn foo(x: i32) { + let y: i32; + if x < 1 { + y = 4; + } else { + y = 5; + } +} + +fn bar(x: i32) { + let y: i32; + match x { + 1 => y = 4, + _ => y = 32, + } +} + +fn foobar(x: i32) { + let y: i32; + 'label: { + y = x + 1; + } +} diff --git a/tests/ui/semicolon_if_nothing_returned.stderr b/tests/ui/semicolon_if_nothing_returned.stderr index ecb284ecf045f..6026320f4b47d 100644 --- a/tests/ui/semicolon_if_nothing_returned.stderr +++ b/tests/ui/semicolon_if_nothing_returned.stderr @@ -1,5 +1,5 @@ error: add `;` to terminate block - --> $DIR/semicolon_if_nothing_returned.rs:7:5 + --> $DIR/semicolon_if_nothing_returned.rs:8:5 | LL | println!("Hello") | ^^^^^^^^^^^^^^^^^ @@ -8,10 +8,16 @@ LL | println!("Hello") = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: add `;` to terminate block - --> $DIR/semicolon_if_nothing_returned.rs:11:5 + --> $DIR/semicolon_if_nothing_returned.rs:12:5 | LL | get_unit() | ^^^^^^^^^^ help: add `;`: `get_unit();` -error: aborting due to 2 previous errors +error: add `;` to terminate block + --> $DIR/semicolon_if_nothing_returned.rs:17:5 + | +LL | y = x + 1 + | ^^^^^^^^^ help: add `;`: `y = x + 1;` + +error: aborting due to 3 previous errors From ac5e9c8d2691da5a3872a8eec97ce694193c1e5c Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 5 Feb 2021 14:45:24 -0600 Subject: [PATCH 24/72] Fix let_underscore_drop implements Drop logic This fixes false positives and false negatives. --- clippy_lints/src/let_underscore.rs | 13 ++----------- tests/ui/let_underscore_drop.rs | 8 ++++++++ 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 6a5a77f8690a9..7e96dfcc7da0f 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -5,7 +5,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{implements_trait, is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help}; +use crate::utils::{is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help}; declare_clippy_lint! { /// **What it does:** Checks for `let _ = ` @@ -125,15 +125,6 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }); - let implements_drop = cx.tcx.lang_items().drop_trait().map_or(false, |drop_trait| - init_ty.walk().any(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => { - implements_trait(cx, inner_ty, drop_trait, &[]) - }, - - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, - }) - ); if contains_sync_guard { span_lint_and_help( cx, @@ -144,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" ) - } else if implements_drop { + } else if init_ty.needs_drop(cx.tcx, cx.param_env) { span_lint_and_help( cx, LET_UNDERSCORE_DROP, diff --git a/tests/ui/let_underscore_drop.rs b/tests/ui/let_underscore_drop.rs index 98593edb9c591..50744f81c3cf8 100644 --- a/tests/ui/let_underscore_drop.rs +++ b/tests/ui/let_underscore_drop.rs @@ -16,4 +16,12 @@ fn main() { let _ = Box::new(()); let _ = Droppable; let _ = Some(Droppable); + + // no lint for reference + let _ = droppable_ref(); +} + +#[must_use] +fn droppable_ref() -> &'static mut Droppable { + unimplemented!() } From a9ad4923cde48ef0c90c5e18646bd745face03ac Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 5 Feb 2021 18:29:05 -0500 Subject: [PATCH 25/72] Bump clippy version --- Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e60aa472846cf..e7755c46eb80d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.51" +version = "0.1.52" authors = [ "Manish Goregaokar ", "Andre Bogus ", diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index a9516560a6195..840341fefc6a2 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints" # begin automatic update -version = "0.1.51" +version = "0.1.52" # end automatic update authors = [ "Manish Goregaokar ", From 93daf27a4006f4d06f8b1653c23783ec52e93a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 6 Feb 2021 00:56:54 +0100 Subject: [PATCH 26/72] tests: ignore check_that_clippy_has_the_same_major_version_as_rustc() inside the rustc repo. Do not check if clippy version matches rustc version when runnning tests inside the rustc repo. This makes sure that upstream rustc maintainers do not have to deal with our test failing/mismatching versions when the rustc version bump is happening. cc #6683 --- tests/versioncheck.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index 76b6126c76c6a..bc5ed0816cc81 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -23,6 +23,12 @@ fn check_that_clippy_lints_has_the_same_version_as_clippy() { #[test] fn check_that_clippy_has_the_same_major_version_as_rustc() { + // do not run this test inside the upstream rustc repo: + // https://github.com/rust-lang/rust-clippy/issues/6683 + if option_env!("RUSTC_TEST_SUITE").is_some() { + return; + } + let clippy_version = rustc_tools_util::get_version_info!(); let clippy_major = clippy_version.major; let clippy_minor = clippy_version.minor; From a60c143fe0cec1125e894f3d2d5008cc317fdacf Mon Sep 17 00:00:00 2001 From: Yusuke Tanaka Date: Wed, 3 Feb 2021 23:24:06 +0900 Subject: [PATCH 27/72] Add new lint `filter_map_identity` This commit adds a new lint named `filter_map_identity`. This lint is the same as `flat_map_identity` except that it checks for `filter_map`. Closes #6643 --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 + .../src/methods/filter_map_identity.rs | 56 +++++++++++++++++++ clippy_lints/src/methods/mod.rs | 30 +++++++++- tests/ui/filter_map_identity.fixed | 16 ++++++ tests/ui/filter_map_identity.rs | 16 ++++++ tests/ui/filter_map_identity.stderr | 22 ++++++++ 7 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/methods/filter_map_identity.rs create mode 100644 tests/ui/filter_map_identity.fixed create mode 100644 tests/ui/filter_map_identity.rs create mode 100644 tests/ui/filter_map_identity.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 45321751ba7e8..f32f5529751b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1955,6 +1955,7 @@ Released 2018-09-13 [`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file [`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map +[`filter_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_identity [`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next [`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next [`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7f5c4f56f9e05..760b490dc129d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -742,6 +742,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::EXPECT_USED, &methods::FILETYPE_IS_FILE, &methods::FILTER_MAP, + &methods::FILTER_MAP_IDENTITY, &methods::FILTER_MAP_NEXT, &methods::FILTER_NEXT, &methods::FLAT_MAP_IDENTITY, @@ -1531,6 +1532,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::CLONE_DOUBLE_REF), LintId::of(&methods::CLONE_ON_COPY), LintId::of(&methods::EXPECT_FUN_CALL), + LintId::of(&methods::FILTER_MAP_IDENTITY), LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT), @@ -1838,6 +1840,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::WILDCARD_IN_OR_PATTERNS), LintId::of(&methods::BIND_INSTEAD_OF_MAP), LintId::of(&methods::CLONE_ON_COPY), + LintId::of(&methods::FILTER_MAP_IDENTITY), LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::INSPECT_FOR_EACH), diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs new file mode 100644 index 0000000000000..d04e4be87ac29 --- /dev/null +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -0,0 +1,56 @@ +use crate::utils::{match_qpath, match_trait_method, paths, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::source_map::Span; + +use super::FILTER_MAP_IDENTITY; + +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + filter_map_args: &[hir::Expr<'_>], + filter_map_span: Span, +) { + if match_trait_method(cx, expr, &paths::ITERATOR) { + let arg_node = &filter_map_args[1].kind; + + let apply_lint = |message: &str| { + span_lint_and_sugg( + cx, + FILTER_MAP_IDENTITY, + filter_map_span.with_hi(expr.span.hi()), + message, + "try", + "flatten()".to_string(), + Applicability::MachineApplicable, + ); + }; + + if_chain! { + if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node; + let body = cx.tcx.hir().body(*body_id); + + if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind; + if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.kind; + + if path.segments.len() == 1; + if path.segments[0].ident.name == binding_ident.name; + + then { + apply_lint("called `filter_map(|x| x)` on an `Iterator`"); + } + } + + if_chain! { + if let hir::ExprKind::Path(ref qpath) = arg_node; + + if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY); + + then { + apply_lint("called `filter_map(std::convert::identity)` on an `Iterator`"); + } + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a17c5996293e9..2f68bc0121aa1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,4 +1,5 @@ mod bind_instead_of_map; +mod filter_map_identity; mod inefficient_to_string; mod inspect_for_each; mod manual_saturating_arithmetic; @@ -1467,6 +1468,29 @@ declare_clippy_lint! { "using `.inspect().for_each()`, which can be replaced with `.for_each()`" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `filter_map(|x| x)`. + /// + /// **Why is this bad?** Readability, this can be written more concisely by using `flatten`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// # let iter = vec![Some(1)].into_iter(); + /// iter.filter_map(|x| x); + /// ``` + /// Use instead: + /// ```rust + /// # let iter = vec![Some(1)].into_iter(); + /// iter.flatten(); + /// ``` + pub FILTER_MAP_IDENTITY, + complexity, + "call to `filter_map` where `flatten` is sufficient" +} + pub struct Methods { msrv: Option, } @@ -1504,6 +1528,7 @@ impl_lint_pass!(Methods => [ FILTER_NEXT, SKIP_WHILE_NEXT, FILTER_MAP, + FILTER_MAP_IDENTITY, MANUAL_FILTER_MAP, MANUAL_FIND_MAP, FILTER_MAP_NEXT, @@ -1597,7 +1622,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]), ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]), ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0], method_spans[0]), - ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]), + ["filter_map", ..] => { + unnecessary_filter_map::lint(cx, expr, arg_lists[0]); + filter_map_identity::check(cx, expr, arg_lists[0], method_spans[0]); + }, ["count", "map"] => lint_suspicious_map(cx, expr), ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr), ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => { diff --git a/tests/ui/filter_map_identity.fixed b/tests/ui/filter_map_identity.fixed new file mode 100644 index 0000000000000..23ce28d8e9be4 --- /dev/null +++ b/tests/ui/filter_map_identity.fixed @@ -0,0 +1,16 @@ +// run-rustfix + +#![allow(unused_imports)] +#![warn(clippy::filter_map_identity)] + +fn main() { + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.flatten(); + + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.flatten(); + + use std::convert::identity; + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.flatten(); +} diff --git a/tests/ui/filter_map_identity.rs b/tests/ui/filter_map_identity.rs new file mode 100644 index 0000000000000..e698df13eea47 --- /dev/null +++ b/tests/ui/filter_map_identity.rs @@ -0,0 +1,16 @@ +// run-rustfix + +#![allow(unused_imports)] +#![warn(clippy::filter_map_identity)] + +fn main() { + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.filter_map(|x| x); + + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.filter_map(std::convert::identity); + + use std::convert::identity; + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.filter_map(identity); +} diff --git a/tests/ui/filter_map_identity.stderr b/tests/ui/filter_map_identity.stderr new file mode 100644 index 0000000000000..596a6320608c7 --- /dev/null +++ b/tests/ui/filter_map_identity.stderr @@ -0,0 +1,22 @@ +error: called `filter_map(|x| x)` on an `Iterator` + --> $DIR/filter_map_identity.rs:8:22 + | +LL | let _ = iterator.filter_map(|x| x); + | ^^^^^^^^^^^^^^^^^ help: try: `flatten()` + | + = note: `-D clippy::filter-map-identity` implied by `-D warnings` + +error: called `filter_map(std::convert::identity)` on an `Iterator` + --> $DIR/filter_map_identity.rs:11:22 + | +LL | let _ = iterator.filter_map(std::convert::identity); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: called `filter_map(std::convert::identity)` on an `Iterator` + --> $DIR/filter_map_identity.rs:15:22 + | +LL | let _ = iterator.filter_map(identity); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: aborting due to 3 previous errors + From fbe436b1d4369603a6f89cbb8fb382ef5fe210f7 Mon Sep 17 00:00:00 2001 From: Yusuke Tanaka Date: Sat, 6 Feb 2021 18:06:58 +0900 Subject: [PATCH 28/72] Use flatten instead of filter_map --- clippy_lints/src/loops.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 663c2df23e22b..ac4005d0cfdea 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -739,7 +739,7 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult { let stmts = block.stmts.iter().map(stmt_to_expr); let expr = once(block.expr.as_deref()); - let mut iter = stmts.chain(expr).filter_map(|e| e); + let mut iter = stmts.chain(expr).flatten(); never_loop_expr_seq(&mut iter, main_loop_id) } From cb3021999c87b480db0a5fd8f7fb2a06f3ffa1ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 6 Feb 2021 11:59:34 +0100 Subject: [PATCH 29/72] lintcheck: update logs --- lintcheck-logs/logs.txt | 125 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 10 deletions(-) diff --git a/lintcheck-logs/logs.txt b/lintcheck-logs/logs.txt index e565691e0e396..2ba4bd5a021f2 100644 --- a/lintcheck-logs/logs.txt +++ b/lintcheck-logs/logs.txt @@ -1,6 +1,6 @@ -clippy 0.1.51 (c6701036b 2021-01-23) +clippy 0.1.51 (3e4179766 2021-02-03) -cargo-0.49.0//home/matthias/.rustup/toolchains/nightly-2021-01-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/macros/mod.rs:393:34 clippy::match_same_arms "this `match` has identical arm bodies" +cargo-0.49.0//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/macros/mod.rs:409:34 clippy::match_same_arms "this `match` has identical arm bodies" cargo-0.49.0/build.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.categories` metadata" cargo-0.49.0/build.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.keywords` metadata" cargo-0.49.0/src/bin/cargo/cli.rs:104:34 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" @@ -99,6 +99,7 @@ cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:411:9 clippy:: cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:420:69 clippy::doc_markdown "you should put `mode/target_kind` between ticks in the documentation" cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:423:19 clippy::doc_markdown "you should put `CrateTypes` between ticks in the documentation" cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:424:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:424:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:469:58 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:603:19 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:665:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -111,6 +112,7 @@ cargo-0.49.0/src/cargo/core/compiler/build_plan.rs:4:9 clippy::doc_markdown "you cargo-0.49.0/src/cargo/core/compiler/build_plan.rs:5:66 clippy::doc_markdown "you should put `BuildPlan` between ticks in the documentation" cargo-0.49.0/src/cargo/core/compiler/build_plan.rs:66:40 clippy::ptr_arg "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do." cargo-0.49.0/src/cargo/core/compiler/compilation.rs:150:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/compilation.rs:150:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/compilation.rs:169:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/compiler/compilation.rs:185:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/compiler/compilation.rs:193:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -121,6 +123,7 @@ cargo-0.49.0/src/cargo/core/compiler/compilation.rs:91:5 clippy::missing_errors_ cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:118:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:123:18 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison" cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:147:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:157:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:157:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:33:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -132,18 +135,23 @@ cargo-0.49.0/src/cargo/core/compiler/context/compilation_files.rs:324:66 clippy: cargo-0.49.0/src/cargo/core/compiler/context/compilation_files.rs:393:37 clippy::match_same_arms "this `match` has identical arm bodies" cargo-0.49.0/src/cargo/core/compiler/context/compilation_files.rs:426:71 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:125:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:125:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:125:5 clippy::too_many_lines "this function has too many lines (107/100)" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:270:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:286:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:308:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:308:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:340:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:340:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:349:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:349:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:354:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:358:21 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:361:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:374:43 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:378:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:383:41 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation" +cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:384:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:384:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:391:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:397:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -162,8 +170,10 @@ cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:353:56 clippy::manual_strip cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:448:27 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:464:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:481:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:481:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:48:56 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:561:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:561:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:567:20 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:576:28 clippy::shadow_unrelated "`mut value` is being shadowed" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:606:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -255,6 +265,7 @@ cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:134:1 clippy::missing_error cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:16:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:30:28 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:34:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:34:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/timings.rs:16:1 clippy::struct_excessive_bools "more than 3 bools in a struct" cargo-0.49.0/src/cargo/core/compiler/timings.rs:192:64 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body" cargo-0.49.0/src/cargo/core/compiler/timings.rs:212:58 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body" @@ -279,6 +290,7 @@ cargo-0.49.0/src/cargo/core/compiler/unit_graph.rs:65:1 clippy::missing_errors_d cargo-0.49.0/src/cargo/core/compiler/unit_graph.rs:65:1 clippy::module_name_repetitions "item name ends with its containing module's name" cargo-0.49.0/src/cargo/core/dependency.rs:157:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/dependency.rs:182:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/dependency.rs:203:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/dependency.rs:203:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:224:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:23:1 clippy::struct_excessive_bools "more than 3 bools in a struct" @@ -288,10 +300,13 @@ cargo-0.49.0/src/cargo/core/dependency.rs:274:5 clippy::must_use_candidate "this cargo-0.49.0/src/cargo/core/dependency.rs:278:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:287:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:291:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/dependency.rs:296:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/dependency.rs:305:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:311:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:319:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/dependency.rs:323:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/dependency.rs:337:75 clippy::redundant_closure_for_method_calls "redundant closure found" +cargo-0.49.0/src/cargo/core/dependency.rs:379:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/dependency.rs:397:56 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/dependency.rs:403:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:408:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -419,6 +434,7 @@ cargo-0.49.0/src/cargo/core/package.rs:174:5 clippy::must_use_candidate "this me cargo-0.49.0/src/cargo/core/package.rs:182:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/package.rs:186:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/package.rs:190:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/package.rs:194:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/package.rs:194:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/package.rs:198:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/package.rs:202:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -436,10 +452,12 @@ cargo-0.49.0/src/cargo/core/package.rs:287:1 clippy::module_name_repetitions "it cargo-0.49.0/src/cargo/core/package.rs:385:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/package.rs:421:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)" cargo-0.49.0/src/cargo/core/package.rs:425:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/package.rs:425:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/package.rs:452:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/package.rs:453:60 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/package.rs:459:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/package.rs:473:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/package.rs:552:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/package.rs:587:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/package.rs:588:9 clippy::needless_question_mark "Question mark operator is useless here" cargo-0.49.0/src/cargo/core/package.rs:682:46 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value" @@ -450,6 +468,7 @@ cargo-0.49.0/src/cargo/core/package.rs:731:5 clippy::missing_errors_doc "docs fo cargo-0.49.0/src/cargo/core/package.rs:790:13 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" cargo-0.49.0/src/cargo/core/package.rs:988:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" cargo-0.49.0/src/cargo/core/package_id.rs:115:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/package_id.rs:124:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/package_id.rs:124:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/package_id.rs:139:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/package_id.rs:142:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -468,14 +487,17 @@ cargo-0.49.0/src/cargo/core/package_id_spec.rs:179:5 clippy::missing_errors_doc cargo-0.49.0/src/cargo/core/package_id_spec.rs:212:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/core/package_id_spec.rs:231:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" cargo-0.49.0/src/cargo/core/package_id_spec.rs:51:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/package_id_spec.rs:51:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/package_id_spec.rs:77:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/package_id_spec.rs:88:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/profiles.rs:1004:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/profiles.rs:1004:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:1014:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:1018:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:1028:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:106:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/core/profiles.rs:143:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`" +cargo-0.49.0/src/cargo/core/profiles.rs:286:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/profiles.rs:286:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:294:40 clippy::if_not_else "unnecessary boolean `not` operation" cargo-0.49.0/src/cargo/core/profiles.rs:30:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -483,6 +505,7 @@ cargo-0.49.0/src/cargo/core/profiles.rs:342:25 clippy::shadow_unrelated "`maker` cargo-0.49.0/src/cargo/core/profiles.rs:370:41 clippy::unused_self "unused `self` argument" cargo-0.49.0/src/cargo/core/profiles.rs:370:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:372:9 clippy::field_reassign_with_default "field assignment outside of initializer for an instance created with Default::default()" +cargo-0.49.0/src/cargo/core/profiles.rs:382:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/profiles.rs:382:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:383:28 clippy::if_not_else "unnecessary boolean `not` operation" cargo-0.49.0/src/cargo/core/profiles.rs:397:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -499,7 +522,9 @@ cargo-0.49.0/src/cargo/core/registry.rs:19:5 clippy::missing_errors_doc "docs fo cargo-0.49.0/src/cargo/core/registry.rs:240:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/registry.rs:26:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/registry.rs:344:49 clippy::redundant_closure_for_method_calls "redundant closure found" +cargo-0.49.0/src/cargo/core/registry.rs:358:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/registry.rs:369:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/registry.rs:424:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/registry.rs:424:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/registry.rs:49:1 clippy::module_name_repetitions "item name ends with its containing module's name" cargo-0.49.0/src/cargo/core/registry.rs:520:17 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" @@ -513,6 +538,7 @@ cargo-0.49.0/src/cargo/core/resolver/context.rs:274:53 clippy::redundant_closure cargo-0.49.0/src/cargo/core/resolver/context.rs:42:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/core/resolver/context.rs:74:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::too_many_lines "this function has too many lines (164/100)" cargo-0.49.0/src/cargo/core/resolver/encode.rs:339:17 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants" cargo-0.49.0/src/cargo/core/resolver/encode.rs:438:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" @@ -570,6 +596,7 @@ cargo-0.49.0/src/cargo/core/resolver/resolve.rs:255:5 clippy::must_use_candidate cargo-0.49.0/src/cargo/core/resolver/resolve.rs:259:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/resolver/resolve.rs:263:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/resolver/resolve.rs:269:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/resolver/resolve.rs:273:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/resolver/resolve.rs:273:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/resolver/resolve.rs:274:9 clippy::map_unwrap_or "called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead" cargo-0.49.0/src/cargo/core/resolver/resolve.rs:280:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -611,6 +638,7 @@ cargo-0.49.0/src/cargo/core/shell.rs:282:5 clippy::missing_errors_doc "docs for cargo-0.49.0/src/cargo/core/shell.rs:314:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/shell.rs:322:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/shell.rs:330:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/shell.rs:345:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/shell.rs:98:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/mod.rs:103:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/source/mod.rs:247:1 clippy::module_name_repetitions "item name starts with its containing module's name" @@ -630,6 +658,7 @@ cargo-0.49.0/src/cargo/core/source/mod.rs:63:5 clippy::missing_errors_doc "docs cargo-0.49.0/src/cargo/core/source/mod.rs:74:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/source/mod.rs:83:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:107:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/source/source_id.rs:107:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:128:50 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/source/source_id.rs:147:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:156:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -640,6 +669,7 @@ cargo-0.49.0/src/cargo/core/source/source_id.rs:171:19 clippy::doc_markdown "you cargo-0.49.0/src/cargo/core/source/source_id.rs:172:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:178:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:187:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/source/source_id.rs:187:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:18:74 clippy::default_trait_access "calling `std::sync::Mutex::default()` is more clear than this expression" cargo-0.49.0/src/cargo/core/source/source_id.rs:195:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:207:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -652,10 +682,12 @@ cargo-0.49.0/src/cargo/core/source/source_id.rs:241:5 clippy::must_use_candidate cargo-0.49.0/src/cargo/core/source/source_id.rs:252:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:257:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:262:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/source/source_id.rs:262:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:305:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:310:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:318:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:326:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/source/source_id.rs:338:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:355:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:393:61 clippy::match_same_arms "this `match` has identical arm bodies" cargo-0.49.0/src/cargo/core/source/source_id.rs:394:42 clippy::match_same_arms "this `match` has identical arm bodies" @@ -730,8 +762,10 @@ cargo-0.49.0/src/cargo/core/workspace.rs:150:5 clippy::missing_errors_doc "docs cargo-0.49.0/src/cargo/core/workspace.rs:159:16 clippy::redundant_else "redundant else block" cargo-0.49.0/src/cargo/core/workspace.rs:197:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/workspace.rs:225:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/workspace.rs:225:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/workspace.rs:255:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/workspace.rs:267:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/workspace.rs:317:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/workspace.rs:329:37 clippy::doc_markdown "you should put `VirtualManifest` between ticks in the documentation" cargo-0.49.0/src/cargo/core/workspace.rs:410:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/workspace.rs:440:9 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`" @@ -742,9 +776,12 @@ cargo-0.49.0/src/cargo/core/workspace.rs:615:22 clippy::redundant_closure_for_me cargo-0.49.0/src/cargo/core/workspace.rs:762:27 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" cargo-0.49.0/src/cargo/core/workspace.rs:784:17 clippy::if_not_else "unnecessary boolean `not` operation" cargo-0.49.0/src/cargo/core/workspace.rs:849:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/workspace.rs:849:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/workspace.rs:893:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/workspace.rs:906:24 clippy::redundant_else "redundant else block" cargo-0.49.0/src/cargo/core/workspace.rs:932:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/workspace.rs:932:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +cargo-0.49.0/src/cargo/lib.rs:177:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/lib.rs:177:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/lib.rs:180:36 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/lib.rs:180:36 clippy::redundant_closure_for_method_calls "redundant closure found" @@ -771,6 +808,7 @@ cargo-0.49.0/src/cargo/ops/cargo_compile.rs:249:1 clippy::missing_errors_doc "do cargo-0.49.0/src/cargo/ops/cargo_compile.rs:258:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:267:16 clippy::needless_question_mark "Question mark operator is useless here" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:275:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/cargo_compile.rs:275:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:275:1 clippy::too_many_lines "this function has too many lines (219/100)" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:468:9 clippy::default_trait_access "calling `std::collections::HashMap::default()` is more clear than this expression" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:548:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -786,6 +824,7 @@ cargo-0.49.0/src/cargo/ops/cargo_compile.rs:612:21 clippy::doc_markdown "you sho cargo-0.49.0/src/cargo/ops/cargo_compile.rs:613:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:618:9 clippy::similar_names "binding's name is too similar to existing binding" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:641:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/ops/cargo_compile.rs:652:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:652:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:655:50 clippy::match_same_arms "this `match` has identical arm bodies" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:673:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -801,6 +840,7 @@ cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:160:5 clippy::items_after_ cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:175:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:22:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:37:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:37:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:37:1 clippy::too_many_lines "this function has too many lines (171/100)" cargo-0.49.0/src/cargo/ops/cargo_install.rs:13:5 clippy::wildcard_imports "usage of wildcard import" cargo-0.49.0/src/cargo/ops/cargo_install.rs:148:1 clippy::fn_params_excessive_bools "more than 3 bools in function parameters" @@ -843,6 +883,7 @@ cargo-0.49.0/src/cargo/ops/cargo_pkgid.rs:5:1 clippy::missing_errors_doc "docs f cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:14:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:171:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:37:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:37:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:57:49 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:69:37 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/ops/cargo_run.rs:25:24 clippy::if_not_else "unnecessary boolean `not` operation" @@ -851,6 +892,7 @@ cargo-0.49.0/src/cargo/ops/cargo_run.rs:37:16 clippy::redundant_else "redundant cargo-0.49.0/src/cargo/ops/cargo_run.rs:53:9 clippy::if_not_else "unnecessary boolean `not` operation" cargo-0.49.0/src/cargo/ops/cargo_run.rs:65:16 clippy::redundant_else "redundant else block" cargo-0.49.0/src/cargo/ops/cargo_run.rs:9:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/cargo_run.rs:9:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/cargo_test.rs:16:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/cargo_test.rs:43:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/cargo_test.rs:84:17 clippy::similar_names "binding's name is too similar to existing binding" @@ -909,6 +951,7 @@ cargo-0.49.0/src/cargo/ops/registry.rs:505:38 clippy::default_trait_access "call cargo-0.49.0/src/cargo/ops/registry.rs:510:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/registry.rs:529:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/ops/registry.rs:53:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/registry.rs:53:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/registry.rs:573:22 clippy::match_same_arms "this `match` has identical arm bodies" cargo-0.49.0/src/cargo/ops/registry.rs:608:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/registry.rs:621:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -923,6 +966,7 @@ cargo-0.49.0/src/cargo/ops/registry.rs:794:16 clippy::single_match_else "you see cargo-0.49.0/src/cargo/ops/registry.rs:828:14 clippy::doc_markdown "you should put `SourceId` between ticks in the documentation" cargo-0.49.0/src/cargo/ops/registry.rs:848:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::too_many_lines "this function has too many lines (137/100)" cargo-0.49.0/src/cargo/ops/resolve.rs:241:28 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" @@ -953,6 +997,7 @@ cargo-0.49.0/src/cargo/ops/tree/mod.rs:360:30 clippy::match_same_arms "this `mat cargo-0.49.0/src/cargo/ops/tree/mod.rs:58:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/ops/vendor.rs:14:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/ops/vendor.rs:21:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/vendor.rs:21:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/vendor.rs:314:34 clippy::match_same_arms "this `match` has identical arm bodies" cargo-0.49.0/src/cargo/ops/vendor.rs:320:29 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison" cargo-0.49.0/src/cargo/ops/vendor.rs:320:60 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison" @@ -971,8 +1016,10 @@ cargo-0.49.0/src/cargo/sources/directory.rs:14:1 clippy::module_name_repetitions cargo-0.49.0/src/cargo/sources/directory.rs:90:56 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/sources/git/source.rs:14:1 clippy::module_name_repetitions "item name ends with its containing module's name" cargo-0.49.0/src/cargo/sources/git/source.rs:25:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/sources/git/source.rs:25:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/sources/git/source.rs:49:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/sources/git/source.rs:53:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/sources/git/source.rs:53:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/sources/git/source.rs:69:20 clippy::comparison_to_empty "comparison to empty slice" cargo-0.49.0/src/cargo/sources/git/utils.rs:1025:19 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" cargo-0.49.0/src/cargo/sources/git/utils.rs:1157:36 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison" @@ -984,6 +1031,7 @@ cargo-0.49.0/src/cargo/sources/git/utils.rs:184:5 clippy::missing_errors_doc "do cargo-0.49.0/src/cargo/sources/git/utils.rs:188:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/sources/git/utils.rs:242:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/sources/git/utils.rs:253:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/sources/git/utils.rs:253:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/sources/git/utils.rs:262:13 clippy::if_not_else "unnecessary boolean `not` operation" cargo-0.49.0/src/cargo/sources/git/utils.rs:289:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/sources/git/utils.rs:294:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -1013,6 +1061,7 @@ cargo-0.49.0/src/cargo/sources/path.rs:429:5 clippy::missing_errors_doc "docs fo cargo-0.49.0/src/cargo/sources/path.rs:460:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/sources/path.rs:473:43 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/sources/path.rs:482:43 clippy::redundant_closure_for_method_calls "redundant closure found" +cargo-0.49.0/src/cargo/sources/path.rs:55:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/sources/path.rs:63:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/sources/path.rs:77:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/sources/path.rs:98:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -1046,6 +1095,7 @@ cargo-0.49.0/src/cargo/sources/registry/remote.rs:72:13 clippy::single_match_els cargo-0.49.0/src/cargo/sources/replaced.rs:12:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/sources/replaced.rs:5:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/util/canonical_url.rs:19:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/canonical_url.rs:19:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/canonical_url.rs:50:41 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison" cargo-0.49.0/src/cargo/util/canonical_url.rs:65:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/command_prelude.rs:218:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" @@ -1091,6 +1141,7 @@ cargo-0.49.0/src/cargo/util/config/mod.rs:100:71 clippy::doc_markdown "you shoul cargo-0.49.0/src/cargo/util/config/mod.rs:1049:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1064:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1090:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/config/mod.rs:1090:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1166:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1179:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1181:33 clippy::needless_question_mark "Question mark operator is useless here" @@ -1105,6 +1156,7 @@ cargo-0.49.0/src/cargo/util/config/mod.rs:1225:5 clippy::missing_errors_doc "doc cargo-0.49.0/src/cargo/util/config/mod.rs:1229:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:124:1 clippy::struct_excessive_bools "more than 3 bools in a struct" cargo-0.49.0/src/cargo/util/config/mod.rs:1254:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/config/mod.rs:1263:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1279:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1281:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" cargo-0.49.0/src/cargo/util/config/mod.rs:1323:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" @@ -1120,6 +1172,7 @@ cargo-0.49.0/src/cargo/util/config/mod.rs:1588:5 clippy::must_use_candidate "thi cargo-0.49.0/src/cargo/util/config/mod.rs:1598:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/config/mod.rs:1619:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/config/mod.rs:1623:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/config/mod.rs:1623:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1623:64 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body" cargo-0.49.0/src/cargo/util/config/mod.rs:1649:9 clippy::option_if_let_else "use Option::map_or_else instead of an if let/else" cargo-0.49.0/src/cargo/util/config/mod.rs:1699:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" @@ -1151,14 +1204,13 @@ cargo-0.49.0/src/cargo/util/config/mod.rs:699:5 clippy::fn_params_excessive_bool cargo-0.49.0/src/cargo/util/config/mod.rs:699:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:719:58 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/util/config/mod.rs:816:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" -cargo-0.49.0/src/cargo/util/config/mod.rs:875:36 clippy::similar_names "binding's name is too similar to existing binding" -cargo-0.49.0/src/cargo/util/config/mod.rs:876:37 clippy::similar_names "binding's name is too similar to existing binding" cargo-0.49.0/src/cargo/util/config/path.rs:10:1 clippy::module_name_repetitions "item name ends with its containing module's name" cargo-0.49.0/src/cargo/util/config/path.rs:14:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/config/path.rs:48:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/util/config/target.rs:12:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/util/config/target.rs:24:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/util/config/value.rs:29:1 clippy::module_name_repetitions "item name ends with its containing module's name" +cargo-0.49.0/src/cargo/util/config/value.rs:70:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/config/value.rs:80:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/config/value.rs:81:9 clippy::match_like_matches_macro "match expression looks like `matches!` macro" cargo-0.49.0/src/cargo/util/cpu.rs:11:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -1166,9 +1218,12 @@ cargo-0.49.0/src/cargo/util/cpu.rs:22:5 clippy::must_use_candidate "this method cargo-0.49.0/src/cargo/util/cpu.rs:82:25 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" cargo-0.49.0/src/cargo/util/cpu.rs:82:9 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" cargo-0.49.0/src/cargo/util/dependency_queue.rs:109:27 clippy::redundant_closure_for_method_calls "redundant closure found" +cargo-0.49.0/src/cargo/util/dependency_queue.rs:125:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/dependency_queue.rs:151:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/dependency_queue.rs:156:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/util/dependency_queue.rs:168:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/dependency_queue.rs:46:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/util/dependency_queue.rs:66:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/dependency_queue.rs:91:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/util/diagnostic_server.rs:218:1 clippy::module_name_repetitions "item name ends with its containing module's name" cargo-0.49.0/src/cargo/util/diagnostic_server.rs:230:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -1182,6 +1237,7 @@ cargo-0.49.0/src/cargo/util/errors.rs:143:5 clippy::must_use_candidate "this met cargo-0.49.0/src/cargo/util/errors.rs:150:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/errors.rs:15:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/errors.rs:237:5 clippy::pub_enum_variant_names "variant name ends with the enum's name" +cargo-0.49.0/src/cargo/util/errors.rs:245:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/errors.rs:245:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/errors.rs:321:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/errors.rs:328:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -1199,15 +1255,19 @@ cargo-0.49.0/src/cargo/util/flock.rs:150:5 clippy::missing_errors_doc "docs for cargo-0.49.0/src/cargo/util/flock.rs:156:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/flock.rs:170:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/flock.rs:192:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/flock.rs:29:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/flock.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/flock.rs:321:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/util/flock.rs:335:23 clippy::cast_possible_truncation "casting `i64` to `u32` may truncate the value" cargo-0.49.0/src/cargo/util/flock.rs:335:23 clippy::cast_sign_loss "casting `i64` to `u32` may lose the sign of the value" cargo-0.49.0/src/cargo/util/flock.rs:335:44 clippy::cast_possible_truncation "casting `i64` to `u32` may truncate the value" cargo-0.49.0/src/cargo/util/flock.rs:379:35 clippy::match_same_arms "this `match` has identical arm bodies" +cargo-0.49.0/src/cargo/util/flock.rs:37:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/flock.rs:37:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/util/flock.rs:43:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/flock.rs:43:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/flock.rs:52:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/flock.rs:52:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/graph.rs:10:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/graph.rs:41:51 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/util/graph.rs:45:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -1226,6 +1286,7 @@ cargo-0.49.0/src/cargo/util/hex.rs:8:9 clippy::cast_possible_truncation "casting cargo-0.49.0/src/cargo/util/hex.rs:9:9 clippy::cast_possible_truncation "casting `u64` to `u8` may truncate the value" cargo-0.49.0/src/cargo/util/important_paths.rs:23:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/important_paths.rs:6:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/interning.rs:66:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/interning.rs:66:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/interning.rs:77:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/into_url.rs:10:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -1268,7 +1329,9 @@ cargo-0.49.0/src/cargo/util/paths.rs:415:1 clippy::missing_errors_doc "docs for cargo-0.49.0/src/cargo/util/paths.rs:445:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/paths.rs:459:45 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/util/paths.rs:469:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/paths.rs:469:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/paths.rs:54:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/util/paths.rs:61:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/paths.rs:61:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/paths.rs:63:19 clippy::option_if_let_else "use Option::map_or_else instead of an if let/else" cargo-0.49.0/src/cargo/util/paths.rs:88:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -1281,6 +1344,7 @@ cargo-0.49.0/src/cargo/util/process_builder.rs:152:5 clippy::missing_errors_doc cargo-0.49.0/src/cargo/util/process_builder.rs:185:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/process_builder.rs:190:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/process_builder.rs:218:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/process_builder.rs:218:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/process_builder.rs:307:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/process_builder.rs:343:39 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body" cargo-0.49.0/src/cargo/util/progress.rs:122:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -1300,16 +1364,22 @@ cargo-0.49.0/src/cargo/util/progress.rs:282:9 clippy::single_char_add_str "calli cargo-0.49.0/src/cargo/util/progress.rs:89:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/progress.rs:97:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/queue.rs:25:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/util/queue.rs:36:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +cargo-0.49.0/src/cargo/util/queue.rs:42:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +cargo-0.49.0/src/cargo/util/queue.rs:52:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +cargo-0.49.0/src/cargo/util/queue.rs:69:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/read2.rs:11:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/read2.rs:31:17 clippy::similar_names "binding's name is too similar to existing binding" cargo-0.49.0/src/cargo/util/restricted_names.rs:13:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/restricted_names.rs:26:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/restricted_names.rs:35:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/restricted_names.rs:45:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/restricted_names.rs:87:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/restricted_names.rs:87:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/restricted_names.rs:89:21 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/util/restricted_names.rs:8:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/rustc.rs:103:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/rustc.rs:103:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/rustc.rs:114:5 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link" cargo-0.49.0/src/cargo/util/rustc.rs:115:5 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link" cargo-0.49.0/src/cargo/util/rustc.rs:162:17 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" @@ -1349,6 +1419,7 @@ cargo-0.49.0/src/cargo/util/toml/mod.rs:824:1 clippy::module_name_repetitions "i cargo-0.49.0/src/cargo/util/toml/mod.rs:834:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/toml/mod.rs:83:42 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/util/toml/mod.rs:852:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/toml/mod.rs:852:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/toml/mod.rs:852:5 clippy::too_many_lines "this function has too many lines (138/100)" cargo-0.49.0/src/cargo/util/toml/mod.rs:962:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/util/toml/mod.rs:979:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" @@ -1394,6 +1465,7 @@ iron-0.6.1/src/middleware/mod.rs:173:5 clippy::missing_errors_doc "docs for func iron-0.6.1/src/middleware/mod.rs:182:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" iron-0.6.1/src/middleware/mod.rs:192:1 clippy::module_name_repetitions "item name ends with its containing module's name" iron-0.6.1/src/middleware/mod.rs:217:25 clippy::doc_markdown "you should put `ChainBuilder` between ticks in the documentation" +iron-0.6.1/src/middleware/mod.rs:264:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" iron-0.6.1/src/middleware/mod.rs:328:20 clippy::similar_names "binding's name is too similar to existing binding" iron-0.6.1/src/middleware/mod.rs:360:16 clippy::similar_names "binding's name is too similar to existing binding" iron-0.6.1/src/middleware/mod.rs:368:33 clippy::similar_names "binding's name is too similar to existing binding" @@ -1424,8 +1496,11 @@ iron-0.6.1/src/request/url.rs:22:5 clippy::missing_errors_doc "docs for function iron-0.6.1/src/request/url.rs:31:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" iron-0.6.1/src/request/url.rs:47:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" iron-0.6.1/src/request/url.rs:52:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +iron-0.6.1/src/request/url.rs:57:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" iron-0.6.1/src/request/url.rs:57:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +iron-0.6.1/src/request/url.rs:63:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" iron-0.6.1/src/request/url.rs:63:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +iron-0.6.1/src/request/url.rs:73:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" iron-0.6.1/src/request/url.rs:73:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" iron-0.6.1/src/request/url.rs:83:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" iron-0.6.1/src/request/url.rs:96:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -1915,6 +1990,7 @@ log-0.4.11/src/lib.rs:1118:5 clippy::must_use_candidate "this method could have log-0.4.11/src/lib.rs:1177:1 clippy::inline_always "you have declared `#[inline(always)]` on `max_level`. This is usually a bad idea" log-0.4.11/src/lib.rs:1178:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" log-0.4.11/src/lib.rs:1306:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +log-0.4.11/src/lib.rs:1306:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" log-0.4.11/src/lib.rs:1358:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" log-0.4.11/src/lib.rs:1359:5 clippy::if_not_else "unnecessary `!=` operation" log-0.4.11/src/lib.rs:1407:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" @@ -1923,6 +1999,7 @@ log-0.4.11/src/lib.rs:356:1 clippy::expl_impl_clone_on_copy "you are implementin log-0.4.11/src/lib.rs:448:12 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation" log-0.4.11/src/lib.rs:500:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" log-0.4.11/src/lib.rs:506:28 clippy::trivially_copy_pass_by_ref "this argument (8 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)" +log-0.4.11/src/lib.rs:506:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" log-0.4.11/src/lib.rs:506:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" log-0.4.11/src/lib.rs:520:27 clippy::derive_hash_xor_eq "you are deriving `Hash` but have implemented `PartialEq` explicitly" log-0.4.11/src/lib.rs:538:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type" @@ -2013,6 +2090,7 @@ quote-1.0.7/src/ext.rs:10:1 clippy::module_name_repetitions "item name ends with quote-1.0.7/src/ext.rs:7:5 clippy::doc_markdown "you should put `TokenStream` between ticks in the documentation" quote-1.0.7/src/ident_fragment.rs:13:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" quote-1.0.7/src/ident_fragment.rs:51:31 clippy::manual_strip "stripping a prefix manually" +quote-1.0.7/src/runtime.rs:332:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" quote-1.0.7/src/runtime.rs:52:5 clippy::module_name_repetitions "item name ends with its containing module's name" quote-1.0.7/src/runtime.rs:63:5 clippy::module_name_repetitions "item name ends with its containing module's name" quote-1.0.7/src/runtime.rs:66:33 clippy::doc_markdown "you should put `DoesNotHaveIter` between ticks in the documentation" @@ -2049,6 +2127,7 @@ rand-0.7.3/src/distributions/binomial.rs:233:32 clippy::cast_precision_loss "cas rand-0.7.3/src/distributions/binomial.rs:234:27 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" rand-0.7.3/src/distributions/binomial.rs:251:22 clippy::cast_sign_loss "casting `i64` to `u64` may lose the sign of the value" rand-0.7.3/src/distributions/binomial.rs:255:9 clippy::if_not_else "unnecessary `!=` operation" +rand-0.7.3/src/distributions/binomial.rs:35:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/binomial.rs:35:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand-0.7.3/src/distributions/binomial.rs:45:17 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" rand-0.7.3/src/distributions/binomial.rs:46:5 clippy::cast_possible_truncation "casting `f64` to `i64` may truncate the value" @@ -2059,18 +2138,25 @@ rand-0.7.3/src/distributions/binomial.rs:81:21 clippy::cast_precision_loss "cast rand-0.7.3/src/distributions/binomial.rs:82:32 clippy::cast_possible_truncation "casting `u64` to `i32` may truncate the value" rand-0.7.3/src/distributions/binomial.rs:88:26 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" rand-0.7.3/src/distributions/binomial.rs:99:21 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" +rand-0.7.3/src/distributions/cauchy.rs:33:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/cauchy.rs:33:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand-0.7.3/src/distributions/dirichlet.rs:52:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand-0.7.3/src/distributions/dirichlet.rs:64:32 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore" rand-0.7.3/src/distributions/dirichlet.rs:65:23 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore" +rand-0.7.3/src/distributions/exponential.rs:76:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/exponential.rs:76:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand-0.7.3/src/distributions/float.rs:73:1 clippy::module_name_repetitions "item name ends with its containing module's name" rand-0.7.3/src/distributions/gamma.rs:13:5 clippy::enum_glob_use "usage of wildcard import for enum variants" rand-0.7.3/src/distributions/gamma.rs:14:5 clippy::enum_glob_use "usage of wildcard import for enum variants" +rand-0.7.3/src/distributions/gamma.rs:189:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/gamma.rs:189:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +rand-0.7.3/src/distributions/gamma.rs:230:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/gamma.rs:230:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +rand-0.7.3/src/distributions/gamma.rs:259:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/gamma.rs:259:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +rand-0.7.3/src/distributions/gamma.rs:287:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/gamma.rs:287:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +rand-0.7.3/src/distributions/gamma.rs:90:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/gamma.rs:90:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand-0.7.3/src/distributions/integer.rs:23:9 clippy::cast_possible_truncation "casting `u32` to `u8` may truncate the value" rand-0.7.3/src/distributions/integer.rs:30:9 clippy::cast_possible_truncation "casting `u32` to `u16` may truncate the value" @@ -2084,6 +2170,7 @@ rand-0.7.3/src/distributions/normal.rs:47:25 clippy::unseparated_literal_suffix rand-0.7.3/src/distributions/normal.rs:48:25 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore" rand-0.7.3/src/distributions/other.rs:89:9 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value" rand-0.7.3/src/distributions/pareto.rs:32:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +rand-0.7.3/src/distributions/poisson.rs:35:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/poisson.rs:35:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand-0.7.3/src/distributions/poisson.rs:87:30 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value" rand-0.7.3/src/distributions/poisson.rs:87:30 clippy::cast_sign_loss "casting `f64` to `u64` may lose the sign of the value" @@ -2153,11 +2240,13 @@ rand-0.7.3/src/distributions/weighted/alias_method.rs:259:28 clippy::clone_on_co rand-0.7.3/src/distributions/weighted/alias_method.rs:296:9 clippy::map_clone "you are using an explicit closure for copying elements" rand-0.7.3/src/distributions/weighted/alias_method.rs:321:9 clippy::map_clone "you are using an explicit closure for copying elements" rand-0.7.3/src/distributions/weighted/alias_method.rs:78:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +rand-0.7.3/src/distributions/weighted/alias_method.rs:78:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/weighted/alias_method.rs:78:5 clippy::too_many_lines "this function has too many lines (106/100)" rand-0.7.3/src/distributions/weighted/alias_method.rs:85:17 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers" rand-0.7.3/src/distributions/weighted/alias_method.rs:87:31 clippy::map_unwrap_or "called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead" rand-0.7.3/src/distributions/weighted/mod.rs:100:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" rand-0.7.3/src/distributions/weighted/mod.rs:144:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +rand-0.7.3/src/distributions/weighted/mod.rs:144:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/weighted/mod.rs:169:16 clippy::int_plus_one "unnecessary `>= y + 1` or `x - 1 >=`" rand-0.7.3/src/distributions/weighted/mod.rs:386:1 clippy::module_name_repetitions "item name starts with its containing module's name" rand-0.7.3/src/distributions/weighted/mod.rs:85:1 clippy::module_name_repetitions "item name starts with its containing module's name" @@ -2188,6 +2277,7 @@ rand-0.7.3/src/rngs/std.rs:54:5 clippy::inline_always "you have declared `#[inli rand-0.7.3/src/rngs/std.rs:63:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_seed`. This is usually a bad idea" rand-0.7.3/src/rngs/std.rs:68:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_rng`. This is usually a bad idea" rand-0.7.3/src/rngs/thread.rs:57:1 clippy::module_name_repetitions "item name starts with its containing module's name" +rand-0.7.3/src/rngs/thread.rs:80:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/rngs/thread.rs:80:1 clippy::module_name_repetitions "item name starts with its containing module's name" rand-0.7.3/src/rngs/thread.rs:80:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" rand-0.7.3/src/rngs/thread.rs:81:35 clippy::redundant_closure_for_method_calls "redundant closure found" @@ -2198,6 +2288,7 @@ rand-0.7.3/src/seq/index.rs:139:13 clippy::enum_glob_use "usage of wildcard impo rand-0.7.3/src/seq/index.rs:159:1 clippy::module_name_repetitions "item name starts with its containing module's name" rand-0.7.3/src/seq/index.rs:171:13 clippy::enum_glob_use "usage of wildcard import for enum variants" rand-0.7.3/src/seq/index.rs:180:13 clippy::enum_glob_use "usage of wildcard import for enum variants" +rand-0.7.3/src/seq/index.rs:213:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/seq/index.rs:223:18 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers" rand-0.7.3/src/seq/index.rs:224:18 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers" rand-0.7.3/src/seq/index.rs:233:25 clippy::cast_precision_loss "casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)" @@ -2222,12 +2313,14 @@ rand-0.7.3/src/seq/mod.rs:45:4 clippy::needless_doctest_main "needless `fn main` rand-0.7.3/src/seq/mod.rs:527:26 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers" rand_core-0.6.0/src/block.rs:117:1 clippy::module_name_repetitions "item name starts with its containing module's name" rand_core-0.6.0/src/block.rs:153:5 clippy::inline_always "you have declared `#[inline(always)]` on `index`. This is usually a bad idea" +rand_core-0.6.0/src/block.rs:168:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand_core-0.6.0/src/block.rs:230:5 clippy::inline_always "you have declared `#[inline(always)]` on `try_fill_bytes`. This is usually a bad idea" rand_core-0.6.0/src/block.rs:240:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_seed`. This is usually a bad idea" rand_core-0.6.0/src/block.rs:245:5 clippy::inline_always "you have declared `#[inline(always)]` on `seed_from_u64`. This is usually a bad idea" rand_core-0.6.0/src/block.rs:250:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_rng`. This is usually a bad idea" rand_core-0.6.0/src/block.rs:280:1 clippy::module_name_repetitions "item name starts with its containing module's name" rand_core-0.6.0/src/block.rs:319:5 clippy::inline_always "you have declared `#[inline(always)]` on `index`. This is usually a bad idea" +rand_core-0.6.0/src/block.rs:335:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand_core-0.6.0/src/block.rs:405:5 clippy::inline_always "you have declared `#[inline(always)]` on `try_fill_bytes`. This is usually a bad idea" rand_core-0.6.0/src/block.rs:415:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_seed`. This is usually a bad idea" rand_core-0.6.0/src/block.rs:420:5 clippy::inline_always "you have declared `#[inline(always)]` on `seed_from_u64`. This is usually a bad idea" @@ -2237,6 +2330,8 @@ rand_core-0.6.0/src/block.rs:68:1 clippy::module_name_repetitions "item name sta rand_core-0.6.0/src/error.rs:106:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand_core-0.6.0/src/error.rs:87:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand_core-0.6.0/src/error.rs:95:74 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value" +rand_core-0.6.0/src/le.rs:18:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +rand_core-0.6.0/src/le.rs:27:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand_core-0.6.0/src/lib.rs:179:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" rand_core-0.6.0/src/lib.rs:301:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand_core-0.6.0/src/lib.rs:303:26 clippy::unreadable_literal "long literal lacking separators" @@ -2548,6 +2643,7 @@ regex-1.3.2/src/compile.rs:1040:38 clippy::cast_possible_truncation "casting `u1 regex-1.3.2/src/compile.rs:1051:25 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore" regex-1.3.2/src/compile.rs:1071:8 clippy::cast_lossless "casting `u32` to `u64` may become silently lossy if you later change the type" regex-1.3.2/src/compile.rs:112:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +regex-1.3.2/src/compile.rs:112:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" regex-1.3.2/src/compile.rs:154:30 clippy::redundant_closure_for_method_calls "redundant closure found" regex-1.3.2/src/compile.rs:156:30 clippy::redundant_closure_for_method_calls "redundant closure found" regex-1.3.2/src/compile.rs:185:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`" @@ -2877,6 +2973,7 @@ regex-1.3.2/src/re_bytes.rs:256:13 clippy::redundant_field_names "redundant fiel regex-1.3.2/src/re_bytes.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" regex-1.3.2/src/re_bytes.rs:35:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" regex-1.3.2/src/re_bytes.rs:42:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +regex-1.3.2/src/re_bytes.rs:483:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" regex-1.3.2/src/re_bytes.rs:48:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" regex-1.3.2/src/re_bytes.rs:558:29 clippy::doc_markdown "you should put `shortest_match` between ticks in the documentation" regex-1.3.2/src/re_bytes.rs:55:33 clippy::redundant_field_names "redundant field names in struct initialization" @@ -2917,6 +3014,7 @@ regex-1.3.2/src/re_unicode.rs:313:13 clippy::redundant_field_names "redundant fi regex-1.3.2/src/re_unicode.rs:38:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" regex-1.3.2/src/re_unicode.rs:44:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" regex-1.3.2/src/re_unicode.rs:51:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +regex-1.3.2/src/re_unicode.rs:533:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" regex-1.3.2/src/re_unicode.rs:57:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" regex-1.3.2/src/re_unicode.rs:617:29 clippy::doc_markdown "you should put `shortest_match` between ticks in the documentation" regex-1.3.2/src/re_unicode.rs:631:29 clippy::doc_markdown "you should put `is_match` between ticks in the documentation" @@ -2960,10 +3058,10 @@ regex-1.3.2/src/utf8.rs:85:19 clippy::cast_lossless "casting `u8` to `u32` may b regex-1.3.2/src/utf8.rs:92:23 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four" regex-1.3.2/src/utf8.rs:92:9 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four" regex-1.3.2/src/utf8.rs:97:16 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four" -ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-01-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/macros.rs:14:27 clippy::match_same_arms "this `match` has identical arm bodies" -ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-01-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/macros.rs:14:27 clippy::match_same_arms "this `match` has identical arm bodies" -ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-01-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/macros.rs:14:27 clippy::match_same_arms "this `match` has identical arm bodies" -ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-01-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/macros.rs:14:27 clippy::match_same_arms "this `match` has identical arm bodies" +ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:30:27 clippy::match_same_arms "this `match` has identical arm bodies" +ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:30:27 clippy::match_same_arms "this `match` has identical arm bodies" +ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:30:27 clippy::match_same_arms "this `match` has identical arm bodies" +ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:30:27 clippy::match_same_arms "this `match` has identical arm bodies" ripgrep-12.1.1/build.rs:133:19 clippy::option_as_ref_deref "called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `githash.as_deref()` instead" ripgrep-12.1.1/build.rs:18:18 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" ripgrep-12.1.1/build.rs:225:14 clippy::redundant_closure_for_method_calls "redundant closure found" @@ -3063,12 +3161,18 @@ ripgrep-12.1.1/crates/core/search.rs:533:5 clippy::cast_precision_loss "casting ripgrep-12.1.1/crates/core/subject.rs:20:1 clippy::module_name_repetitions "item name starts with its containing module's name" ripgrep-12.1.1/crates/core/subject.rs:4:1 clippy::single_component_path_imports "this import is redundant" syn-1.0.54/build.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata" -syn-1.0.54/build.rs:1:null clippy::multiple_crate_versions "could not read cargo metadata: `cargo metadata` exited with an error: Downloading crates ...\n Downloaded syn-test-suite v0.0.0\nerror: failed to verify the checksum of `syn-test-suite v0.0.0`" +syn-1.0.54/build.rs:1:null clippy::multiple_crate_versions "could not read cargo metadata: `cargo metadata` exited with an error: Downloading crates ...\n Downloaded httparse v1.3.5\n Downloaded tokio v0.2.25\n Downloaded syn-test-suite v0.0.0\nerror: failed to verify the checksum of `syn-test-suite v0.0.0`" +syn-1.0.54/src/generics.rs:174:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" syn-1.0.54/src/lib.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata" syn-1.0.54/src/lib.rs:1:null clippy::multiple_crate_versions "could not read cargo metadata: `cargo metadata` exited with an error: Downloading crates ...\n Downloaded syn-test-suite v0.0.0\nerror: failed to verify the checksum of `syn-test-suite v0.0.0`" syn-1.0.54/src/lit.rs:1397:40 clippy::redundant_else "redundant else block" syn-1.0.54/src/lit.rs:1405:28 clippy::redundant_else "redundant else block" syn-1.0.54/src/lit.rs:1485:32 clippy::redundant_else "redundant else block" +syn-1.0.54/src/lit.rs:343:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +syn-1.0.54/src/lit.rs:437:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +syn-1.0.54/src/lit.rs:916:9 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +syn-1.0.54/src/token.rs:974:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +syn-1.0.54/src/token.rs:996:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" unicode-xid-0.2.1/src/lib.rs:1:null clippy::cargo_common_metadata "package `unicode-xid` is missing `package.categories` metadata" unicode-xid-0.2.1/src/lib.rs:56:11 clippy::upper_case_acronyms "name `UnicodeXID` contains a capitalized acronym" unicode-xid-0.2.1/src/lib.rs:57:64 clippy::doc_markdown "you should put `XID_Start` between ticks in the documentation" @@ -3359,8 +3463,9 @@ clippy::unseparated_literal_suffix 41 clippy::single_match_else 45 clippy::inline_always 59 clippy::match_same_arms 64 -clippy::similar_names 79 +clippy::similar_names 77 clippy::cast_possible_truncation 91 +clippy::missing_panics_doc 106 clippy::redundant_field_names 111 clippy::redundant_closure_for_method_calls 135 clippy::module_name_repetitions 137 From 64982cc435fc4546cbdc9ce3935cdd63ac636e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 5 Feb 2021 23:13:59 +0100 Subject: [PATCH 30/72] lintcheck: make TomlCrate also accept git-data from lintcheck_crates.toml --- clippy_dev/lintcheck_crates.toml | 34 ++++++++++++++++---------------- clippy_dev/src/lintcheck.rs | 32 +++++++++++++++++++----------- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/clippy_dev/lintcheck_crates.toml b/clippy_dev/lintcheck_crates.toml index 1fbf7930d3ecf..657efb1623316 100644 --- a/clippy_dev/lintcheck_crates.toml +++ b/clippy_dev/lintcheck_crates.toml @@ -1,20 +1,20 @@ [crates] # some of these are from cargotest -cargo = ['0.49.0'] -iron = ['0.6.1'] -ripgrep = ['12.1.1'] -xsv = ['0.13.0'] -#tokei = ['12.0.4'] -rayon = ['1.5.0'] -serde = ['1.0.118'] +cargo = {name = "cargo", versions = ['0.49.0']} +iron = {name = "iron", versions = ['0.6.1']} +ripgrep = {name = "ripgrep", versions = ['12.1.1']} +xsv = {name = "xsv", versions = ['0.13.0']} +#tokei = { name = "tokei", versions = ['12.0.4']} +rayon = {name = "rayon", versions = ['1.5.0']} +serde = {name = "serde", versions = ['1.0.118']} # top 10 crates.io dls -bitflags = ['1.2.1'] -libc = ['0.2.81'] -log = ['0.4.11'] -proc-macro2 = ['1.0.24'] -quote = ['1.0.7'] -rand = ['0.7.3'] -rand_core = ['0.6.0'] -regex = ['1.3.2'] -syn = ['1.0.54'] -unicode-xid = ['0.2.1'] +bitflags = {name = "bitflags", versions = ['1.2.1']} +libc = {name = "libc", versions = ['0.2.81']} +log = {name = "log", versions = ['0.4.11']} +proc-macro2 = {name = "proc-macro2", versions = ['1.0.24']} +quote = {name = "quote", versions = ['1.0.7']} +rand = {name = "rand", versions = ['0.7.3']} +rand_core = {name = "rand_core", versions = ['0.6.0']} +regex = {name = "regex", versions = ['1.3.2']} +syn = {name = "syn", versions = ['1.0.54']} +unicode-xid = {name = "unicode-xid", versions = ['0.2.1']} diff --git a/clippy_dev/src/lintcheck.rs b/clippy_dev/src/lintcheck.rs index 785c692d3cb98..e3587c7bdfe69 100644 --- a/clippy_dev/src/lintcheck.rs +++ b/clippy_dev/src/lintcheck.rs @@ -20,14 +20,17 @@ use serde_json::Value; // use this to store the crates when interacting with the crates.toml file #[derive(Debug, Serialize, Deserialize)] struct CrateList { - crates: HashMap>, + crates: HashMap, } // crate data we stored in the toml, can have multiple versions per crate // A single TomlCrate is laster mapped to several CrateSources in that case +#[derive(Debug, Serialize, Deserialize)] struct TomlCrate { name: String, - versions: Vec, + versions: Option>, + git_url: Option, + git_hash: Option, } // represents an archive we download from crates.io @@ -114,7 +117,7 @@ impl Crate { let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir/"); - let all_output = std::process::Command::new(cargo_clippy_path) + let all_output = std::process::Command::new(&cargo_clippy_path) .env("CARGO_TARGET_DIR", shared_target_dir) // lint warnings will look like this: // src/cargo/ops/cargo_compile.rs:127:35: warning: usage of `FromIterator::from_iter` @@ -128,7 +131,12 @@ impl Crate { ]) .current_dir(&self.path) .output() - .unwrap(); + .unwrap_or_else(|error| { + dbg!(error); + dbg!(&cargo_clippy_path); + dbg!(&self.path); + panic!("something was not found?") + }); let stdout = String::from_utf8_lossy(&all_output.stdout); let output_lines = stdout.lines(); //dbg!(&output_lines); @@ -160,19 +168,21 @@ fn read_crates() -> Vec { let tomlcrates: Vec = crate_list .crates .into_iter() - .map(|(name, versions)| TomlCrate { name, versions }) + .map(|(_cratename, tomlcrate)| tomlcrate) .collect(); // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate => // multiple Cratesources) let mut crate_sources = Vec::new(); tomlcrates.into_iter().for_each(|tk| { - tk.versions.iter().for_each(|ver| { - crate_sources.push(CrateSource { - name: tk.name.clone(), - version: ver.to_string(), - }); - }) + if let Some(ref versions) = tk.versions { + versions.iter().for_each(|ver| { + crate_sources.push(CrateSource { + name: tk.name.clone(), + version: ver.to_string(), + }); + }) + } }); crate_sources } From 10fbafa562b3196dd0cc1b8496e9866e4afab5cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 6 Feb 2021 12:02:42 +0100 Subject: [PATCH 31/72] implement the download_and_extract() step for git sources --- clippy_dev/src/lintcheck.rs | 128 +++++++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 40 deletions(-) diff --git a/clippy_dev/src/lintcheck.rs b/clippy_dev/src/lintcheck.rs index e3587c7bdfe69..63f78db13f8d9 100644 --- a/clippy_dev/src/lintcheck.rs +++ b/clippy_dev/src/lintcheck.rs @@ -16,6 +16,7 @@ use std::{fmt, fs::write, path::PathBuf}; use clap::ArgMatches; use serde::{Deserialize, Serialize}; use serde_json::Value; +//use git2::Repository; // use this to store the crates when interacting with the crates.toml file #[derive(Debug, Serialize, Deserialize)] @@ -35,12 +36,13 @@ struct TomlCrate { // represents an archive we download from crates.io #[derive(Debug, Serialize, Deserialize, Eq, Hash, PartialEq)] -struct CrateSource { - name: String, - version: String, +enum CrateSource { + CratesIo { name: String, version: String }, + Git { name: String, url: String, commit: String }, } // represents the extracted sourcecode of a crate +// we actually don't need to special-case git repos here because it does not matter for clippy, yay! (clippy only needs a simple path) #[derive(Debug)] struct Crate { version: String, @@ -72,40 +74,70 @@ impl std::fmt::Display for ClippyWarning { impl CrateSource { fn download_and_extract(&self) -> Crate { - let extract_dir = PathBuf::from("target/lintcheck/crates"); - let krate_download_dir = PathBuf::from("target/lintcheck/downloads"); - - // url to download the crate from crates.io - let url = format!( - "https://crates.io/api/v1/crates/{}/{}/download", - self.name, self.version - ); - println!("Downloading and extracting {} {} from {}", self.name, self.version, url); - let _ = std::fs::create_dir("target/lintcheck/"); - let _ = std::fs::create_dir(&krate_download_dir); - let _ = std::fs::create_dir(&extract_dir); - - let krate_file_path = krate_download_dir.join(format!("{}-{}.crate.tar.gz", &self.name, &self.version)); - // don't download/extract if we already have done so - if !krate_file_path.is_file() { - // create a file path to download and write the crate data into - let mut krate_dest = std::fs::File::create(&krate_file_path).unwrap(); - let mut krate_req = ureq::get(&url).call().unwrap().into_reader(); - // copy the crate into the file - std::io::copy(&mut krate_req, &mut krate_dest).unwrap(); - - // unzip the tarball - let ungz_tar = flate2::read::GzDecoder::new(std::fs::File::open(&krate_file_path).unwrap()); - // extract the tar archive - let mut archive = tar::Archive::new(ungz_tar); - archive.unpack(&extract_dir).expect("Failed to extract!"); - } - // crate is extracted, return a new Krate object which contains the path to the extracted - // sources that clippy can check - Crate { - version: self.version.clone(), - name: self.name.clone(), - path: extract_dir.join(format!("{}-{}/", self.name, self.version)), + match self { + CrateSource::CratesIo { name, version } => { + let extract_dir = PathBuf::from("target/lintcheck/crates"); + let krate_download_dir = PathBuf::from("target/lintcheck/downloads"); + + // url to download the crate from crates.io + let url = format!("https://crates.io/api/v1/crates/{}/{}/download", name, version); + println!("Downloading and extracting {} {} from {}", name, version, url); + let _ = std::fs::create_dir("target/lintcheck/"); + let _ = std::fs::create_dir(&krate_download_dir); + let _ = std::fs::create_dir(&extract_dir); + + let krate_file_path = krate_download_dir.join(format!("{}-{}.crate.tar.gz", name, version)); + // don't download/extract if we already have done so + if !krate_file_path.is_file() { + // create a file path to download and write the crate data into + let mut krate_dest = std::fs::File::create(&krate_file_path).unwrap(); + let mut krate_req = ureq::get(&url).call().unwrap().into_reader(); + // copy the crate into the file + std::io::copy(&mut krate_req, &mut krate_dest).unwrap(); + + // unzip the tarball + let ungz_tar = flate2::read::GzDecoder::new(std::fs::File::open(&krate_file_path).unwrap()); + // extract the tar archive + let mut archive = tar::Archive::new(ungz_tar); + archive.unpack(&extract_dir).expect("Failed to extract!"); + } + // crate is extracted, return a new Krate object which contains the path to the extracted + // sources that clippy can check + Crate { + version: version.clone(), + name: name.clone(), + path: extract_dir.join(format!("{}-{}/", name, version)), + } + }, + CrateSource::Git { name, url, commit } => { + let repo_path = { + let mut repo_path = PathBuf::from("target/lintcheck/downloads"); + // add a -git suffix in case we have the same crate from crates.io and a git repo + repo_path.push(format!("{}-git", name)); + repo_path + }; + // clone the repo if we have not done so + if !repo_path.is_dir() { + Command::new("git") + .arg("clone") + .arg(url) + .arg(&repo_path) + .output() + .expect("Failed to clone git repo!"); + } + // check out the commit/branch/whatever + Command::new("git") + .arg("checkout") + .arg(commit) + .output() + .expect("Failed to check out commit"); + + Crate { + version: commit.clone(), + name: name.clone(), + path: repo_path, + } + }, } } } @@ -175,14 +207,30 @@ fn read_crates() -> Vec { // multiple Cratesources) let mut crate_sources = Vec::new(); tomlcrates.into_iter().for_each(|tk| { + // if we have multiple versions, save each one if let Some(ref versions) = tk.versions { versions.iter().for_each(|ver| { - crate_sources.push(CrateSource { + crate_sources.push(CrateSource::CratesIo { name: tk.name.clone(), version: ver.to_string(), }); }) } + // otherwise, we should have a git source + if tk.git_url.is_some() && tk.git_hash.is_some() { + crate_sources.push(CrateSource::Git { + name: tk.name.clone(), + url: tk.git_url.clone().unwrap(), + commit: tk.git_hash.clone().unwrap(), + }); + } + // if we have a version as well as a git data OR only one git data, something is funky + if tk.versions.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some()) + || tk.git_hash.is_some() != tk.git_url.is_some() + { + dbg!(tk); + unreachable!("Failed to translate TomlCrate into CrateSource!"); + } }); crate_sources } @@ -239,13 +287,13 @@ pub fn run(clap_config: &ArgMatches) { let clippy_warnings: Vec = if let Some(only_one_crate) = clap_config.value_of("only") { // if we don't have the specified crated in the .toml, throw an error - if !crates.iter().any(|krate| krate.name == only_one_crate) { + /* if !crates.iter().any(|krate| krate.name == only_one_crate) { eprintln!( "ERROR: could not find crate '{}' in clippy_dev/lintcheck_crates.toml", only_one_crate ); std::process::exit(1); - } + } */ //@FIXME // only check a single crate that was passed via cmdline crates From 9ab505a3c779c7ad9b078d7d24ace4e3b05d7f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 6 Feb 2021 11:36:06 +0100 Subject: [PATCH 32/72] lintcheck: add git source as an example and update logs --- clippy_dev/lintcheck_crates.toml | 1 + clippy_dev/src/lintcheck.rs | 1 + lintcheck-logs/logs.txt | 82 +++++++++++++++++++++++++++----- 3 files changed, 71 insertions(+), 13 deletions(-) diff --git a/clippy_dev/lintcheck_crates.toml b/clippy_dev/lintcheck_crates.toml index 657efb1623316..c83b4b2ba4224 100644 --- a/clippy_dev/lintcheck_crates.toml +++ b/clippy_dev/lintcheck_crates.toml @@ -12,6 +12,7 @@ bitflags = {name = "bitflags", versions = ['1.2.1']} libc = {name = "libc", versions = ['0.2.81']} log = {name = "log", versions = ['0.4.11']} proc-macro2 = {name = "proc-macro2", versions = ['1.0.24']} +puffin = {name = "puffin", git_url = "https://github.com/EmbarkStudios/puffin", git_hash = "02dd4a3"} quote = {name = "quote", versions = ['1.0.7']} rand = {name = "rand", versions = ['0.7.3']} rand_core = {name = "rand_core", versions = ['0.6.0']} diff --git a/clippy_dev/src/lintcheck.rs b/clippy_dev/src/lintcheck.rs index 63f78db13f8d9..0473b09b1d7ca 100644 --- a/clippy_dev/src/lintcheck.rs +++ b/clippy_dev/src/lintcheck.rs @@ -118,6 +118,7 @@ impl CrateSource { }; // clone the repo if we have not done so if !repo_path.is_dir() { + println!("Cloning {} and checking out {}", url, commit); Command::new("git") .arg("clone") .arg(url) diff --git a/lintcheck-logs/logs.txt b/lintcheck-logs/logs.txt index 2ba4bd5a021f2..cee18278b4266 100644 --- a/lintcheck-logs/logs.txt +++ b/lintcheck-logs/logs.txt @@ -2086,6 +2086,61 @@ proc-macro2-1.0.24/src/parse.rs:808:15 clippy::explicit_iter_loop "it is more co proc-macro2-1.0.24/src/wrapper.rs:415:24 clippy::trivially_copy_pass_by_ref "this argument (4 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)" proc-macro2-1.0.24/src/wrapper.rs:429:23 clippy::trivially_copy_pass_by_ref "this argument (4 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)" proc-macro2-1.0.24/src/wrapper.rs:492:17 clippy::trivially_copy_pass_by_ref "this argument (4 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:158:15 clippy::cast_precision_loss "casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:175:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin-imgui/src/ui.rs:183:5 clippy::too_many_lines "this function has too many lines (115/100)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:1:5 clippy::wildcard_imports "usage of wildcard import" +puffin-02dd4a3/puffin-imgui/src/ui.rs:207:16 clippy::collapsible_else_if "this `else { if .. }` block can be collapsed" +puffin-02dd4a3/puffin-imgui/src/ui.rs:271:67 clippy::cast_precision_loss "casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:2:5 clippy::wildcard_imports "usage of wildcard import" +puffin-02dd4a3/puffin-imgui/src/ui.rs:376:29 clippy::cast_precision_loss "casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:381:44 clippy::cast_precision_loss "casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:453:9 clippy::similar_names "binding's name is too similar to existing binding" +puffin-02dd4a3/puffin-imgui/src/ui.rs:540:14 clippy::cast_possible_truncation "casting `f64` to `f32` may truncate the value" +puffin-02dd4a3/puffin-imgui/src/ui.rs:551:5 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:584:39 clippy::cast_precision_loss "casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:59:26 clippy::unsafe_derive_deserialize "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`" +puffin-02dd4a3/puffin-imgui/src/ui.rs:61:1 clippy::module_name_repetitions "item name ends with its containing module's name" +puffin-02dd4a3/puffin-imgui/src/ui.rs:627:39 clippy::cast_precision_loss "casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:674:47 clippy::cast_precision_loss "casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:690:9 clippy::cast_precision_loss "casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin/src/data.rs:102:25 clippy::cast_possible_truncation "casting `usize` to `u8` may truncate the value" +puffin-02dd4a3/puffin/src/data.rs:112:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/data.rs:116:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +puffin-02dd4a3/puffin/src/data.rs:137:24 clippy::match_same_arms "this `match` has identical arm bodies" +puffin-02dd4a3/puffin/src/data.rs:177:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +puffin-02dd4a3/puffin/src/data.rs:211:21 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers" +puffin-02dd4a3/puffin/src/data.rs:24:5 clippy::wildcard_imports "usage of wildcard import" +puffin-02dd4a3/puffin/src/data.rs:75:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +puffin-02dd4a3/puffin/src/lib.rs:113:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:147:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +puffin-02dd4a3/puffin/src/lib.rs:147:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +puffin-02dd4a3/puffin/src/lib.rs:165:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +puffin-02dd4a3/puffin/src/lib.rs:200:21 clippy::default_trait_access "calling `Stream::default()` is more clear than this expression" +puffin-02dd4a3/puffin/src/lib.rs:257:78 clippy::default_trait_access "calling `std::cell::RefCell::default()` is more clear than this expression" +puffin-02dd4a3/puffin/src/lib.rs:297:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:302:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:308:28 clippy::default_trait_access "calling `FullProfileData::default()` is more clear than this expression" +puffin-02dd4a3/puffin/src/lib.rs:316:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:321:5 clippy::cast_possible_truncation "casting `u128` to `i64` may truncate the value" +puffin-02dd4a3/puffin/src/lib.rs:348:28 clippy::default_trait_access "calling `std::marker::PhantomData::default()` is more clear than this expression" +puffin-02dd4a3/puffin/src/lib.rs:359:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:375:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:376:5 clippy::option_if_let_else "use Option::map_or instead of an if let/else" +puffin-02dd4a3/puffin/src/lib.rs:377:9 clippy::option_if_let_else "use Option::map_or instead of an if let/else" +puffin-02dd4a3/puffin/src/lib.rs:406:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:408:5 clippy::option_if_let_else "use Option::map_or instead of an if let/else" +puffin-02dd4a3/puffin/src/lib.rs:69:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:73:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:77:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/merge.rs:21:1 clippy::module_name_repetitions "item name starts with its containing module's name" +puffin-02dd4a3/puffin/src/merge.rs:28:1 clippy::module_name_repetitions "item name starts with its containing module's name" +puffin-02dd4a3/puffin/src/merge.rs:28:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/merge.rs:35:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +puffin-02dd4a3/puffin/src/merge.rs:35:1 clippy::module_name_repetitions "item name starts with its containing module's name" +puffin-02dd4a3/puffin/src/merge.rs:64:43 clippy::default_trait_access "calling `std::vec::Vec::default()` is more clear than this expression" +puffin-02dd4a3/puffin/src/merge.rs:65:54 clippy::default_trait_access "calling `std::collections::HashMap::default()` is more clear than this expression" +puffin-02dd4a3/puffin/src/merge.rs:9:1 clippy::module_name_repetitions "item name starts with its containing module's name" quote-1.0.7/src/ext.rs:10:1 clippy::module_name_repetitions "item name ends with its containing module's name" quote-1.0.7/src/ext.rs:7:5 clippy::doc_markdown "you should put `TokenStream` between ticks in the documentation" quote-1.0.7/src/ident_fragment.rs:13:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -3383,6 +3438,7 @@ clippy::should_implement_trait 1 clippy::stable_sort_primitive 1 clippy::unit_arg 1 clippy::unnecessary_lazy_evaluations 1 +clippy::unsafe_derive_deserialize 1 clippy::used_underscore_binding 1 clippy::verbose_bit_mask 1 clippy::while_let_on_iterator 1 @@ -3410,7 +3466,6 @@ clippy::ptr_arg 3 clippy::zero_ptr 3 clippy::let_underscore_drop 4 clippy::too_many_arguments 4 -clippy::collapsible_else_if 5 clippy::explicit_iter_loop 5 clippy::field_reassign_with_default 5 clippy::identity_op 5 @@ -3419,6 +3474,7 @@ clippy::match_like_matches_macro 5 clippy::needless_return 5 clippy::new_without_default 5 clippy::ptr_as_ptr 5 +clippy::collapsible_else_if 6 clippy::manual_strip 6 clippy::non_ascii_literal 6 clippy::single_component_path_imports 6 @@ -3436,12 +3492,11 @@ clippy::missing_safety_doc 10 clippy::needless_doctest_main 10 clippy::multiple_crate_versions 11 clippy::needless_lifetimes 12 -clippy::option_if_let_else 12 clippy::cargo_common_metadata 13 clippy::shadow_unrelated 13 clippy::linkedlist 14 clippy::single_char_add_str 14 -clippy::default_trait_access 16 +clippy::option_if_let_else 15 clippy::needless_pass_by_value 18 clippy::upper_case_acronyms 18 clippy::cast_possible_wrap 19 @@ -3452,26 +3507,27 @@ clippy::unusual_byte_groupings 19 clippy::map_unwrap_or 20 clippy::struct_excessive_bools 20 clippy::redundant_static_lifetimes 21 +clippy::default_trait_access 22 clippy::cast_lossless 23 clippy::trivially_copy_pass_by_ref 26 clippy::redundant_else 29 -clippy::too_many_lines 31 -clippy::cast_precision_loss 35 +clippy::too_many_lines 32 clippy::if_not_else 35 clippy::enum_glob_use 40 clippy::unseparated_literal_suffix 41 +clippy::cast_precision_loss 44 clippy::single_match_else 45 clippy::inline_always 59 -clippy::match_same_arms 64 -clippy::similar_names 77 -clippy::cast_possible_truncation 91 -clippy::missing_panics_doc 106 +clippy::match_same_arms 65 +clippy::similar_names 78 +clippy::cast_possible_truncation 95 +clippy::missing_panics_doc 108 clippy::redundant_field_names 111 clippy::redundant_closure_for_method_calls 135 -clippy::module_name_repetitions 137 clippy::items_after_statements 139 -clippy::wildcard_imports 160 +clippy::module_name_repetitions 142 +clippy::wildcard_imports 163 clippy::doc_markdown 178 -clippy::missing_errors_doc 338 +clippy::missing_errors_doc 343 clippy::unreadable_literal 365 -clippy::must_use_candidate 552 +clippy::must_use_candidate 565 From e1c284bff74cef5c1684491bc2eb1b0b814332a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 6 Feb 2021 12:04:31 +0100 Subject: [PATCH 33/72] lintcheck: cleanup, fix --only for git crates, better error msgs --- clippy_dev/src/lintcheck.rs | 21 +++++++++++++++------ lintcheck-logs/logs.txt | 6 ++++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/clippy_dev/src/lintcheck.rs b/clippy_dev/src/lintcheck.rs index 0473b09b1d7ca..35c2659952c42 100644 --- a/clippy_dev/src/lintcheck.rs +++ b/clippy_dev/src/lintcheck.rs @@ -16,7 +16,6 @@ use std::{fmt, fs::write, path::PathBuf}; use clap::ArgMatches; use serde::{Deserialize, Serialize}; use serde_json::Value; -//use git2::Repository; // use this to store the crates when interacting with the crates.toml file #[derive(Debug, Serialize, Deserialize)] @@ -42,7 +41,8 @@ enum CrateSource { } // represents the extracted sourcecode of a crate -// we actually don't need to special-case git repos here because it does not matter for clippy, yay! (clippy only needs a simple path) +// we actually don't need to special-case git repos here because it does not matter for clippy, yay! +// (clippy only needs a simple path) #[derive(Debug)] struct Crate { version: String, @@ -229,7 +229,10 @@ fn read_crates() -> Vec { if tk.versions.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some()) || tk.git_hash.is_some() != tk.git_url.is_some() { - dbg!(tk); + dbg!(&tk); + if tk.git_hash.is_some() != tk.git_url.is_some() { + panic!("Encountered TomlCrate with only one of git_hash and git_url!") + } unreachable!("Failed to translate TomlCrate into CrateSource!"); } }); @@ -287,14 +290,20 @@ pub fn run(clap_config: &ArgMatches) { let crates = read_crates(); let clippy_warnings: Vec = if let Some(only_one_crate) = clap_config.value_of("only") { - // if we don't have the specified crated in the .toml, throw an error - /* if !crates.iter().any(|krate| krate.name == only_one_crate) { + // if we don't have the specified crate in the .toml, throw an error + if !crates.iter().any(|krate| { + let name = match krate { + CrateSource::CratesIo { name, .. } => name, + CrateSource::Git { name, .. } => name, + }; + name == only_one_crate + }) { eprintln!( "ERROR: could not find crate '{}' in clippy_dev/lintcheck_crates.toml", only_one_crate ); std::process::exit(1); - } */ //@FIXME + } // only check a single crate that was passed via cmdline crates diff --git a/lintcheck-logs/logs.txt b/lintcheck-logs/logs.txt index cee18278b4266..3bc7758033b28 100644 --- a/lintcheck-logs/logs.txt +++ b/lintcheck-logs/logs.txt @@ -1,4 +1,4 @@ -clippy 0.1.51 (3e4179766 2021-02-03) +clippy 0.1.51 (7f5bb7fd0 2021-02-06) cargo-0.49.0//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/macros/mod.rs:409:34 clippy::match_same_arms "this `match` has identical arm bodies" cargo-0.49.0/build.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.categories` metadata" @@ -855,6 +855,7 @@ cargo-0.49.0/src/cargo/ops/cargo_install.rs:37:1 clippy::missing_errors_doc "doc cargo-0.49.0/src/cargo/ops/cargo_install.rs:454:22 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/ops/cargo_install.rs:483:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/ops/cargo_install.rs:683:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/cargo_install.rs:708:5 clippy::manual_flatten "unnecessary `if let` since only the `Some` variant of the iterator element is used" cargo-0.49.0/src/cargo/ops/cargo_new.rs:101:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/cargo_new.rs:245:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/ops/cargo_new.rs:251:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" @@ -3216,7 +3217,7 @@ ripgrep-12.1.1/crates/core/search.rs:533:5 clippy::cast_precision_loss "casting ripgrep-12.1.1/crates/core/subject.rs:20:1 clippy::module_name_repetitions "item name starts with its containing module's name" ripgrep-12.1.1/crates/core/subject.rs:4:1 clippy::single_component_path_imports "this import is redundant" syn-1.0.54/build.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata" -syn-1.0.54/build.rs:1:null clippy::multiple_crate_versions "could not read cargo metadata: `cargo metadata` exited with an error: Downloading crates ...\n Downloaded httparse v1.3.5\n Downloaded tokio v0.2.25\n Downloaded syn-test-suite v0.0.0\nerror: failed to verify the checksum of `syn-test-suite v0.0.0`" +syn-1.0.54/build.rs:1:null clippy::multiple_crate_versions "could not read cargo metadata: `cargo metadata` exited with an error: Downloading crates ...\n Downloaded syn-test-suite v0.0.0\nerror: failed to verify the checksum of `syn-test-suite v0.0.0`" syn-1.0.54/src/generics.rs:174:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" syn-1.0.54/src/lib.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata" syn-1.0.54/src/lib.rs:1:null clippy::multiple_crate_versions "could not read cargo metadata: `cargo metadata` exited with an error: Downloading crates ...\n Downloaded syn-test-suite v0.0.0\nerror: failed to verify the checksum of `syn-test-suite v0.0.0`" @@ -3425,6 +3426,7 @@ clippy::explicit_deref_methods 1 clippy::from_iter_instead_of_collect 1 clippy::from_over_into 1 clippy::int_plus_one 1 +clippy::manual_flatten 1 clippy::manual_saturating_arithmetic 1 clippy::mem_replace_with_default 1 clippy::nonminimal_bool 1 From 6626295fbc747d04f1a8d14f19ee48c789b90e50 Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Sat, 6 Feb 2021 14:07:49 +0100 Subject: [PATCH 34/72] Fixed for loop problem, corrected all occurences that got linted --- clippy_lints/src/assertions_on_constants.rs | 2 +- clippy_lints/src/attrs.rs | 6 ++-- clippy_lints/src/bit_mask.rs | 6 ++-- clippy_lints/src/booleans.rs | 6 ++-- clippy_lints/src/collapsible_if.rs | 2 +- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/eq_op.rs | 10 +++--- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/eval_order_dependence.rs | 2 +- clippy_lints/src/functions.rs | 6 ++-- clippy_lints/src/future_not_send.rs | 2 +- clippy_lints/src/infinite_iter.rs | 2 +- clippy_lints/src/inherent_impl.rs | 4 +-- clippy_lints/src/len_zero.rs | 4 +-- clippy_lints/src/let_underscore.rs | 8 ++--- clippy_lints/src/lifetimes.rs | 4 +-- clippy_lints/src/literal_representation.rs | 8 ++--- clippy_lints/src/loops.rs | 22 ++++++------- clippy_lints/src/macro_use.rs | 6 ++-- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/map_clone.rs | 6 ++-- clippy_lints/src/matches.rs | 6 ++-- .../src/methods/bind_instead_of_map.rs | 2 +- clippy_lints/src/methods/mod.rs | 20 ++++++------ clippy_lints/src/mut_reference.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 2 +- .../src/needless_arbitrary_self_type.rs | 2 +- clippy_lints/src/needless_bool.rs | 18 +++++------ clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 2 +- clippy_lints/src/open_options.rs | 10 +++--- clippy_lints/src/question_mark.rs | 2 +- clippy_lints/src/redundant_closure_call.rs | 2 +- clippy_lints/src/redundant_pub_crate.rs | 2 +- clippy_lints/src/returns.rs | 4 +-- .../src/semicolon_if_nothing_returned.rs | 32 ++++++++----------- clippy_lints/src/shadow.rs | 10 +++--- .../src/slow_vector_initialization.rs | 2 +- .../src/suspicious_operation_groupings.rs | 6 ++-- clippy_lints/src/transmute.rs | 6 ++-- clippy_lints/src/types.rs | 6 ++-- clippy_lints/src/unicode.rs | 4 +-- clippy_lints/src/unused_self.rs | 2 +- clippy_lints/src/upper_case_acronyms.rs | 2 +- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/utils/attrs.rs | 2 +- clippy_lints/src/utils/author.rs | 2 +- clippy_lints/src/utils/diagnostics.rs | 2 +- clippy_lints/src/utils/mod.rs | 2 +- clippy_lints/src/utils/sugg.rs | 2 +- clippy_lints/src/utils/usage.rs | 6 ++-- clippy_lints/src/utils/visitors.rs | 2 +- clippy_lints/src/verbose_file_reads.rs | 2 +- clippy_lints/src/write.rs | 2 +- tests/ui/semicolon_if_nothing_returned.rs | 7 ++++ tests/ui/semicolon_if_nothing_returned.stderr | 10 +++--- 55 files changed, 149 insertions(+), 148 deletions(-) diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index aa431f0596cca..b9de478017306 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { &format!("`assert!(false, {})` should probably be replaced", panic_message), None, &format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message), - ) + ); }; if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") { diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 652d1fa16b6de..90463d7f026d3 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -277,7 +277,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if is_relevant_item(cx, item) { - check_attrs(cx, item.span, item.ident.name, &item.attrs) + check_attrs(cx, item.span, item.ident.name, &item.attrs); } match item.kind { ItemKind::ExternCrate(..) | ItemKind::Use(..) => { @@ -353,13 +353,13 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { if is_relevant_impl(cx, item) { - check_attrs(cx, item.span, item.ident.name, &item.attrs) + check_attrs(cx, item.span, item.ident.name, &item.attrs); } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if is_relevant_trait(cx, item) { - check_attrs(cx, item.span, item.ident.name, &item.attrs) + check_attrs(cx, item.span, item.ident.name, &item.attrs); } } } diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index a4ee54076ee98..8d9fbcf4fd19e 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -115,9 +115,9 @@ impl<'tcx> LateLintPass<'tcx> for BitMask { if let ExprKind::Binary(cmp, left, right) = &e.kind { if cmp.node.is_comparison() { if let Some(cmp_opt) = fetch_int_literal(cx, right) { - check_compare(cx, left, cmp.node, cmp_opt, e.span) + check_compare(cx, left, cmp.node, cmp_opt, e.span); } else if let Some(cmp_val) = fetch_int_literal(cx, left) { - check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span) + check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span); } } } @@ -171,7 +171,7 @@ fn check_compare(cx: &LateContext<'_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp } fetch_int_literal(cx, right) .or_else(|| fetch_int_literal(cx, left)) - .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span)) + .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span)); } } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 90bb0bd555f27..75f011a7fa0bd 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool { _: Span, _: HirId, ) { - NonminimalBoolVisitor { cx }.visit_body(body) + NonminimalBoolVisitor { cx }.visit_body(body); } } @@ -184,7 +184,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { Term(n) => { let terminal = self.terminals[n as usize]; if let Some(str) = simplify_not(self.cx, terminal) { - self.output.push_str(&str) + self.output.push_str(&str); } else { self.output.push('!'); let snip = snippet_opt(self.cx, terminal.span)?; @@ -452,7 +452,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { } match &e.kind { ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => { - self.bool_expr(e) + self.bool_expr(e); }, ExprKind::Unary(UnOp::UnNot, inner) => { if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() { diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 93ccc76d0c9cd..4e7a6250add6f 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -92,7 +92,7 @@ declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]); impl EarlyLintPass for CollapsibleIf { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { if !expr.span.from_expansion() { - check_if(cx, expr) + check_if(cx, expr); } } } diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 90d31dece1311..59b1c806e23a6 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -118,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { "`if` chain can be rewritten with `match`", None, "Consider rewriting the `if` chain to use `cmp` and `match`.", - ) + ); } } diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 6308f6e2e7e9d..e2881315b5663 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { vec![(left.span, lsnip), (right.span, rsnip)], ); }, - ) + ); } else if lcpy && !rcpy && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()]) @@ -175,7 +175,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ) + ); } else if !lcpy && rcpy && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()]) @@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ) + ); } }, // &foo == bar @@ -218,7 +218,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ) + ); } }, // foo == &bar @@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { rsnip, Applicability::MaybeIncorrect, // FIXME #2597 ); - }) + }); } }, _ => {}, diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 1a722d39f730b..91f9df4649bfc 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { match expr.kind { ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => { for arg in args { - check_closure(cx, arg) + check_closure(cx, arg); } }, _ => (), diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index bc2b2904698c7..8df14d80026b6 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -116,7 +116,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { self.visit_expr(e); for arm in arms { if let Some(Guard::If(if_expr)) = arm.guard { - self.visit_expr(if_expr) + self.visit_expr(if_expr); } // make sure top level arm expressions aren't linted self.maybe_walk_expr(&*arm.body); diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 8795425461033..45973c8b0f7d5 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -270,7 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions { _, ) | intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => { - self.check_arg_number(cx, decl, span.with_hi(decl.output.span().hi())) + self.check_arg_number(cx, decl, span.with_hi(decl.output.span().hi())); }, _ => {}, } @@ -434,7 +434,7 @@ impl<'tcx> Functions { TOO_MANY_LINES, span, &format!("this function has too many lines ({}/{})", line_count, self.max_lines), - ) + ); } } @@ -707,7 +707,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { } }, Assign(ref target, ..) | AssignOp(_, ref target, _) | AddrOf(_, hir::Mutability::Mut, ref target) => { - self.mutates_static |= is_mutated_static(self.cx, target) + self.mutates_static |= is_mutated_static(self.cx, target); }, _ => {}, } diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 7208e66ff7be1..55bdda7138ede 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { )); } } - }) + }); }, ); } diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 129abd7d89749..dd0a3d1610b53 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter { return; }, }; - span_lint(cx, lint, expr.span, msg) + span_lint(cx, lint, expr.span, msg); } } diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index ea26c84cde16a..2c5e6f11216e5 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -85,8 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { |diag| { diag.span_note(*initial_span, "first implementation here"); }, - ) - }) + ); + }); } } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index e95caf6a35f90..599602c4a0bd1 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -256,9 +256,9 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> } } - check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to) + check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to); } else { - check_empty_expr(cx, span, method, lit, op) + check_empty_expr(cx, span, method, lit, op); } } diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 6a5a77f8690a9..3362177574281 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { None, "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" - ) + ); } else if implements_drop { span_lint_and_help( cx, @@ -153,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { None, "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" - ) + ); } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { span_lint_and_help( cx, @@ -162,7 +162,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "non-binding let on an expression with `#[must_use]` type", None, "consider explicitly using expression value" - ) + ); } else if is_must_use_func_call(cx, init) { span_lint_and_help( cx, @@ -171,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "non-binding let on a result of a `#[must_use]` function", None, "consider explicitly using function result" - ) + ); } } } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index e84c8b4e5b3e0..740f207b214db 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -205,7 +205,7 @@ fn could_use_elision<'tcx>( output_visitor.visit_ty(ty); } for lt in named_generics { - input_visitor.visit_generic_param(lt) + input_visitor.visit_generic_param(lt); } if input_visitor.abort() || output_visitor.abort() { @@ -460,7 +460,7 @@ impl<'tcx> Visitor<'tcx> for LifetimeChecker { // `'b` in `'a: 'b` is useless unless used elsewhere in // a non-lifetime bound if let GenericParamKind::Type { .. } = param.kind { - walk_generic_param(self, param) + walk_generic_param(self, param); } } fn nested_visit_map(&mut self) -> NestedVisitorMap { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 87a957a9bd241..7b75ab89bb847 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -229,7 +229,7 @@ impl EarlyLintPass for LiteralDigitGrouping { } if let ExprKind::Lit(ref lit) = expr.kind { - self.check_lit(cx, lit) + self.check_lit(cx, lit); } } } @@ -292,7 +292,7 @@ impl LiteralDigitGrouping { } }; if should_warn { - warning_type.display(num_lit.format(), cx, lit.span) + warning_type.display(num_lit.format(), cx, lit.span); } } } @@ -422,7 +422,7 @@ impl EarlyLintPass for DecimalLiteralRepresentation { } if let ExprKind::Lit(ref lit) = expr.kind { - self.check_lit(cx, lit) + self.check_lit(cx, lit); } } } @@ -444,7 +444,7 @@ impl DecimalLiteralRepresentation { let hex = format!("{:#X}", val); let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false); let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| { - warning_type.display(num_lit.format(), cx, lit.span) + warning_type.display(num_lit.format(), cx, lit.span); }); } } diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 663c2df23e22b..c7e0d32ca2731 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1426,7 +1426,7 @@ fn detect_same_item_push<'tcx>( "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", item_str, vec_str, item_str ), - ) + ); } if !matches!(pat.kind, PatKind::Wild) { @@ -1714,7 +1714,7 @@ fn lint_iter_method(cx: &LateContext<'_>, args: &[Expr<'_>], arg: &Expr<'_>, met "to write this more concisely, try", format!("&{}{}", muta, object), applicability, - ) + ); } fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: &Expr<'_>) { @@ -1753,7 +1753,7 @@ fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: }, ); if TyS::same_type(receiver_ty_adjusted, ref_receiver_ty) { - lint_iter_method(cx, args, arg, method_name) + lint_iter_method(cx, args, arg, method_name); } } } else if method_name == "next" && match_trait_method(cx, arg, &paths::ITERATOR) { @@ -2075,10 +2075,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { if let ty::BorrowKind::MutBorrow = bk { if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low { - self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)) + self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)); } if Some(id) == self.hir_id_high { - self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)) + self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)); } } } @@ -2087,10 +2087,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low { - self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)) + self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)); } if Some(id) == self.hir_id_high { - self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)) + self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)); } } } @@ -2543,10 +2543,10 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { } }, ExprKind::Assign(ref lhs, _, _) if lhs.hir_id == expr.hir_id => { - *state = IncrementVisitorVarState::DontWarn + *state = IncrementVisitorVarState::DontWarn; }, ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => { - *state = IncrementVisitorVarState::DontWarn + *state = IncrementVisitorVarState::DontWarn; }, _ => (), } @@ -2670,7 +2670,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } }, ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => { - self.state = InitializeVisitorState::DontWarn + self.state = InitializeVisitorState::DontWarn; }, _ => (), } @@ -2815,7 +2815,7 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { return; } } - walk_pat(self, pat) + walk_pat(self, pat); } fn nested_visit_map(&mut self) -> NestedVisitorMap { diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index bb52888883af5..f4ffe18994061 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -206,9 +206,9 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { let mut suggestions = vec![]; for ((root, span), path) in used { if path.len() == 1 { - suggestions.push((span, format!("{}::{}", root, path[0]))) + suggestions.push((span, format!("{}::{}", root, path[0]))); } else { - suggestions.push((span, format!("{}::{{{}}}", root, path.join(", ")))) + suggestions.push((span, format!("{}::{{{}}}", root, path.join(", ")))); } } @@ -225,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { "remove the attribute and import the macro directly, try", help, Applicability::MaybeIncorrect, - ) + ); } } } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 42a92104a4919..11d101c502522 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { kind_word, snippet(cx, pattern.span, "..")))] .into_iter().chain(strippings.into_iter().map(|span| (span, "".into()))), - ) + ); }); } } diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 1818836d5d5e8..b3be755d4884e 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -122,7 +122,7 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { "remove the `map` call", String::new(), Applicability::MachineApplicable, - ) + ); } fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { @@ -139,7 +139,7 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { snippet_with_applicability(cx, root, "..", &mut applicability) ), applicability, - ) + ); } else { span_lint_and_sugg( cx, @@ -152,6 +152,6 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { snippet_with_applicability(cx, root, "..", &mut applicability) ), applicability, - ) + ); } } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index ba7b9bd04248d..74d3677777928 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1046,7 +1046,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) "try this", suggestion[0].clone(), Applicability::MaybeIncorrect, - ) + ); }; span_lint_and_sugg( @@ -1057,7 +1057,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) "try this", suggestion.join(" | "), Applicability::MaybeIncorrect, - ) + ); } } @@ -1156,7 +1156,7 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp cast, ), applicability, - ) + ); } } } diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 540a1484a8558..897a3194ca181 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -151,7 +151,7 @@ pub(crate) trait BindInsteadOfMap { .into_iter() .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())), ), - ) + ); }); } can_sugg diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a17c5996293e9..e02b640381996 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1582,10 +1582,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]), ["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0], method_spans[1]), ["is_some", "position"] => { - lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0], method_spans[1]) + lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0], method_spans[1]); }, ["is_some", "rposition"] => { - lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) + lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]); }, ["extend", ..] => lint_extend(cx, expr, arg_lists[0]), ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), @@ -1601,17 +1601,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["count", "map"] => lint_suspicious_map(cx, expr), ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr), ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => { - manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..]) + manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..]); }, ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => { - check_pointer_offset(cx, expr, arg_lists[0]) + 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, self.msrv.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()) + 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"), @@ -2446,16 +2446,16 @@ fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: if let hir::ExprKind::Lit(ref lit) = fold_args[1].kind { match lit.node { ast::LitKind::Bool(false) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Or, "any", true) + check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Or, "any", true); }, ast::LitKind::Bool(true) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::And, "all", true) + check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::And, "all", true); }, ast::LitKind::Int(0, _) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Add, "sum", false) + check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Add, "sum", false); }, ast::LitKind::Int(1, _) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Mul, "product", false) + check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Mul, "product", false); }, _ => (), } diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 3f0b765df1561..7c21632c9d594 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(e.hir_id); let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs); - check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method") + check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method"); }, _ => (), } diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 76417aa7ed09d..b99e9576f5e16 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -106,7 +106,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> { _ if !self.found => self.expr_span = Some(expr.span), _ => return, } - walk_expr(self, expr) + walk_expr(self, expr); } fn nested_visit_map(&mut self) -> NestedVisitorMap { diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 7687962bdd9bf..107d6a5796604 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -120,7 +120,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { match &p.ty.kind { TyKind::Path(None, path) => { if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind { - check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl) + check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl); } }, TyKind::Rptr(lifetime, mut_ty) => { diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index d795f12645794..614a1e8980cd2 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { } if parent_node_is_if_expr(&e, &cx) { - snip = snip.blockify() + snip = snip.blockify(); } span_lint_and_sugg( @@ -142,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison { |h: Sugg<'_>| !h, "equality checks against false can be replaced by a negation", )); - check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal) + check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal); }, BinOpKind::Ne => { let true_case = Some(( @@ -150,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison { "inequality checks against true can be replaced by a negation", )); let false_case = Some((|h| h, "inequality checks against false are unnecessary")); - check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal) + check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal); }, BinOpKind::Lt => check_comparison( cx, @@ -249,22 +249,22 @@ fn check_comparison<'a, 'tcx>( snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability) ), applicability, - ) + ); } } match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) { (Bool(true), Other) => left_true.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, right_side, applicability, m, h) + suggest_bool_comparison(cx, e, right_side, applicability, m, h); }), (Other, Bool(true)) => right_true.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, left_side, applicability, m, h) + suggest_bool_comparison(cx, e, left_side, applicability, m, h); }), (Bool(false), Other) => left_false.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, right_side, applicability, m, h) + suggest_bool_comparison(cx, e, right_side, applicability, m, h); }), (Other, Bool(false)) => right_false.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, left_side, applicability, m, h) + suggest_bool_comparison(cx, e, left_side, applicability, m, h); }), (Other, Other) => no_literal.map_or((), |(h, m)| { let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability); @@ -277,7 +277,7 @@ fn check_comparison<'a, 'tcx>( "try simplifying it as shown", h(left_side, right_side).to_string(), applicability, - ) + ); }), _ => (), } diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 4fb899125e8ad..6a20d5f139a43 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { types produces code that is hard to read and refactor, please \ consider using the `partial_cmp` method instead, to make it \ clear that the two values could be incomparable" - ) + ); } } } diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index 73a99a3a2f870..82143f7a28886 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -125,7 +125,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `create` is called more than once", ); } else { - create = true + create = true; } create_arg = create_arg || (arg == Argument::True); }, @@ -138,7 +138,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `append` is called more than once", ); } else { - append = true + append = true; } append_arg = append_arg || (arg == Argument::True); }, @@ -151,7 +151,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `truncate` is called more than once", ); } else { - truncate = true + truncate = true; } truncate_arg = truncate_arg || (arg == Argument::True); }, @@ -164,7 +164,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `read` is called more than once", ); } else { - read = true + read = true; } read_arg = read_arg || (arg == Argument::True); }, @@ -177,7 +177,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `write` is called more than once", ); } else { - write = true + write = true; } write_arg = write_arg || (arg == Argument::True); }, diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 6c480d48c7561..63c904b7fb4c5 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -88,7 +88,7 @@ impl QuestionMark { "replace it with", replacement_str, applicability, - ) + ); } } } diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index f398b3fff25a3..daea1592018d6 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -56,7 +56,7 @@ impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor { self.found_return = true; } - ast_visit::walk_expr(self, ex) + ast_visit::walk_expr(self, ex); } } diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index acd9047ace617..127f6078dabb6 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { Applicability::MachineApplicable, ); }, - ) + ); } } } diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index e438f92b136ac..e7b66c5ebcf07 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { } else { RetReplacement::Empty }; - check_final_expr(cx, &body.value, Some(body.value.span), replacement) + check_final_expr(cx, &body.value, Some(body.value.span), replacement); }, FnKind::ItemFn(..) | FnKind::Method(..) => { if let ExprKind::Block(ref block, _) = body.value.kind { @@ -239,7 +239,7 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option match replacement { RetReplacement::Empty => { diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 22cd10ced189f..f47ca1b69b170 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,7 +1,7 @@ -use crate::utils::{in_macro, span_lint_and_then, sugg}; +use crate::utils::{in_macro, span_lint_and_sugg, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -42,31 +42,25 @@ impl LateLintPass<'_> for SemicolonIfNothingReturned { if let Some(expr) = block.expr; let t_expr = cx.typeck_results().expr_ty(expr); if t_expr.is_unit(); + if let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(expr.span.source_callsite()); + if !snippet.ends_with('}'); then { - match expr.kind { - ExprKind::Loop(..) | - ExprKind::Match(..) | - ExprKind::Block(..) | - ExprKind::If(..) if !in_macro(expr.span) => return, - _ => (), + // filter out the desugared `for` loop + if let ExprKind::DropTemps(..) = &expr.kind { + return; } let sugg = sugg::Sugg::hir(cx, &expr, ".."); let suggestion = format!("{0};", sugg); - span_lint_and_then( + span_lint_and_sugg( cx, SEMICOLON_IF_NOTHING_RETURNED, expr.span, - "add `;` to terminate block", - | diag | { - diag.span_suggestion( - expr.span, - "add `;`", - suggestion, - Applicability::MaybeIncorrect, - ); - } - ) + "Consider adding a `;` to the last statement for consistent formatting", + "add a `;` here", + suggestion, + Applicability::MaybeIncorrect, + ); } } } diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index d5b1767e945b9..3af98632712f2 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -118,7 +118,7 @@ fn check_fn<'tcx>(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>, body: &'tcx Bo let mut bindings = Vec::with_capacity(decl.inputs.len()); for arg in iter_input_pats(decl, body) { if let PatKind::Binding(.., ident, _) = arg.pat.kind { - bindings.push((ident.name, ident.span)) + bindings.push((ident.name, ident.span)); } } check_expr(cx, &body.value, &mut bindings); @@ -154,7 +154,7 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: & .. } = *local; if let Some(ref t) = *ty { - check_ty(cx, t, bindings) + check_ty(cx, t, bindings); } if let Some(ref o) = *init { check_expr(cx, o, bindings); @@ -330,7 +330,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut // ExprKind::MethodCall ExprKind::Array(v) | ExprKind::Tup(v) => { for e in v { - check_expr(cx, e, bindings) + check_expr(cx, e, bindings); } }, ExprKind::If(ref cond, ref then, ref otherwise) => { @@ -371,11 +371,11 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<( check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings); }, TyKind::Ptr(MutTy { ty: ref mty, .. }) | TyKind::Rptr(_, MutTy { ty: ref mty, .. }) => { - check_ty(cx, mty, bindings) + check_ty(cx, mty, bindings); }, TyKind::Tup(tup) => { for t in tup { - check_ty(cx, t, bindings) + check_ty(cx, t, bindings); } }, TyKind::Typeof(ref anon_const) => check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings), diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 96f6881556cf3..9ba9b4187d26e 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -306,7 +306,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { fn visit_block(&mut self, block: &'tcx Block<'_>) { if self.initialization_found { if let Some(ref s) = block.stmts.get(0) { - self.visit_stmt(s) + self.visit_stmt(s); } self.initialization_found = false; diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index cccd24ccf9401..f245789d75dcf 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -265,7 +265,7 @@ fn emit_suggestion(cx: &EarlyContext<'_>, span: Span, sugg: String, applicabilit "I think you meant", sugg, applicability, - ) + ); } fn ident_swap_sugg( @@ -476,7 +476,7 @@ impl Add for IdentLocation { impl AddAssign for IdentLocation { fn add_assign(&mut self, other: Self) { - *self = *self + other + *self = *self + other; } } @@ -507,7 +507,7 @@ impl Add for IdentDifference { impl AddAssign for IdentDifference { fn add_assign(&mut self, other: Self) { - *self = *self + other + *self = *self + other; } } diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index d977cea4da50b..e619a1a698a3c 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -463,7 +463,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { Applicability::Unspecified, ); }, - ) + ); }, (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) => { if_chain! { @@ -519,7 +519,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { Applicability::Unspecified, ); }, - ) + ); } } } @@ -552,7 +552,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { Applicability::Unspecified, ); }, - ) + ); }, (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context => span_lint_and_then( cx, diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 1b0f1e309aa2c..dd3e934889aad 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -630,7 +630,7 @@ impl Types { TyKind::Rptr(ref lt, ref mut_ty) => self.check_ty_rptr(cx, hir_ty, is_local, lt, mut_ty), // recurse TyKind::Slice(ref ty) | TyKind::Array(ref ty, _) | TyKind::Ptr(MutTy { ref ty, .. }) => { - self.check_ty(cx, ty, is_local) + self.check_ty(cx, ty, is_local); }, TyKind::Tup(tys) => { for ty in tys { @@ -2436,7 +2436,7 @@ fn upcast_comparison_bounds_err<'tcx>( }, Rel::Eq | Rel::Ne => unreachable!(), } { - err_upcast_comparison(cx, span, lhs, true) + err_upcast_comparison(cx, span, lhs, true); } else if match rel { Rel::Lt => { if invert { @@ -2454,7 +2454,7 @@ fn upcast_comparison_bounds_err<'tcx>( }, Rel::Eq | Rel::Ne => unreachable!(), } { - err_upcast_comparison(cx, span, lhs, false) + err_upcast_comparison(cx, span, lhs, false); } } } diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index 93d59cc7fcd17..9346e3c1d3bef 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -69,7 +69,7 @@ impl LateLintPass<'_> for Unicode { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { if let ExprKind::Lit(ref lit) = expr.kind { if let LitKind::Str(_, _) = lit.node { - check_str(cx, lit.span, expr.hir_id) + check_str(cx, lit.span, expr.hir_id); } } } @@ -80,7 +80,7 @@ fn escape>(s: T) -> String { for c in s { if c as u32 > 0x7F { for d in c.escape_unicode() { - result.push(d) + result.push(d); } } else { result.push(c); diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 5349c4f7eb8a7..83ba9c897e0dc 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -94,7 +94,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnusedSelfVisitor<'a, 'tcx> { return; } if let Res::Local(hir_id) = &path.res { - self.uses_self = self.self_hir_id == hir_id + self.uses_self = self.self_hir_id == hir_id; } walk_path(self, path); } diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index 61e7031716a9d..0f04a4a62ce14 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -69,7 +69,7 @@ fn check_ident(cx: &EarlyContext<'_>, ident: &Ident) { "consider making the acronym lowercase, except the initial letter", corrected, Applicability::MaybeIncorrect, - ) + ); } } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 72d1ca7392913..4bbfb3fbeb19a 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -103,7 +103,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SemanticUseSelfVisitor<'a, 'tcx> { } } - walk_ty(self, hir_ty) + walk_ty(self, hir_ty); } fn nested_visit_map(&mut self) -> NestedVisitorMap { diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs index 8d28421d70d70..588c31ea40f32 100644 --- a/clippy_lints/src/utils/attrs.rs +++ b/clippy_lints/src/utils/attrs.rs @@ -115,7 +115,7 @@ fn parse_attrs(sess: &Session, attrs: &[ast::Attribute], name: &' for attr in get_attr(sess, attrs, name) { if let Some(ref value) = attr.value_str() { if let Ok(value) = FromStr::from_str(&value.as_str()) { - f(value) + f(value); } else { sess.span_err(attr.span, "not a number"); } diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index ca60d335262b3..b8c5011249780 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -293,7 +293,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { LitKind::Str(ref text, _) => { let str_pat = self.next("s"); println!(" if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat); - println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str()) + println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str()); }, } }, diff --git a/clippy_lints/src/utils/diagnostics.rs b/clippy_lints/src/utils/diagnostics.rs index 269be217c2d87..f74ce999b5c7a 100644 --- a/clippy_lints/src/utils/diagnostics.rs +++ b/clippy_lints/src/utils/diagnostics.rs @@ -211,7 +211,7 @@ pub fn multispan_sugg(diag: &mut DiagnosticBuilder<'_>, help_msg: &str, sugg: where I: IntoIterator, { - multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg) + multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg); } pub fn multispan_sugg_with_applicability( diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index cf93ee0a7a5c6..a519dce66d4af 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -464,7 +464,7 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option DiagnosticBuilderExt for rustc_errors::DiagnosticBuilder if let Some(non_whitespace_offset) = non_whitespace_offset { remove_span = remove_span - .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large"))) + .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large"))); } } diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index fc0db7f64ec95..8bf169c0d06a8 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -60,7 +60,7 @@ impl<'tcx> MutVarsDelegate { //FIXME: This causes false negatives. We can't get the `NodeId` from //`Categorization::Upvar(_)`. So we search for any `Upvar`s in the //`while`-body, not just the ones in the condition. - self.skip = true + self.skip = true; }, _ => {}, } @@ -72,12 +72,12 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) { if let ty::BorrowKind::MutBorrow = bk { - self.update(&cmt) + self.update(&cmt); } } fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) { - self.update(&cmt) + self.update(&cmt); } } diff --git a/clippy_lints/src/utils/visitors.rs b/clippy_lints/src/utils/visitors.rs index ebf69df31ca41..caaf636c89743 100644 --- a/clippy_lints/src/utils/visitors.rs +++ b/clippy_lints/src/utils/visitors.rs @@ -87,7 +87,7 @@ where } fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { - intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) + intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt); } fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index 32574d9d6c9a8..92965e95cdaa3 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for VerboseFileReads { "use of `File::read_to_string`", None, "consider using `fs::read_to_string` instead", - ) + ); } } } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index e40fdca6a9947..f9ccf322dda05 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -298,7 +298,7 @@ impl EarlyLintPass for Write { Applicability::MachineApplicable, ); }, - ) + ); } } } else if mac.path == sym!(writeln) { diff --git a/tests/ui/semicolon_if_nothing_returned.rs b/tests/ui/semicolon_if_nothing_returned.rs index 2c07cc9df40d6..0abe2cca26757 100644 --- a/tests/ui/semicolon_if_nothing_returned.rs +++ b/tests/ui/semicolon_if_nothing_returned.rs @@ -46,3 +46,10 @@ fn foobar(x: i32) { y = x + 1; } } + +fn loop_test(x: i32) { + let y: i32; + for &ext in &["stdout", "stderr", "fixed"] { + println!("{}", ext); + } +} diff --git a/tests/ui/semicolon_if_nothing_returned.stderr b/tests/ui/semicolon_if_nothing_returned.stderr index 6026320f4b47d..2bc73342467d7 100644 --- a/tests/ui/semicolon_if_nothing_returned.stderr +++ b/tests/ui/semicolon_if_nothing_returned.stderr @@ -1,4 +1,4 @@ -error: add `;` to terminate block +error: Consider adding a `;` to the last statement for consistent formatting --> $DIR/semicolon_if_nothing_returned.rs:8:5 | LL | println!("Hello") @@ -7,17 +7,17 @@ LL | println!("Hello") = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: add `;` to terminate block +error: Consider adding a `;` to the last statement for consistent formatting --> $DIR/semicolon_if_nothing_returned.rs:12:5 | LL | get_unit() - | ^^^^^^^^^^ help: add `;`: `get_unit();` + | ^^^^^^^^^^ help: add a `;` here: `get_unit();` -error: add `;` to terminate block +error: Consider adding a `;` to the last statement for consistent formatting --> $DIR/semicolon_if_nothing_returned.rs:17:5 | LL | y = x + 1 - | ^^^^^^^^^ help: add `;`: `y = x + 1;` + | ^^^^^^^^^ help: add a `;` here: `y = x + 1;` error: aborting due to 3 previous errors From cd6748749a454e07a3f7f72c79bc62c2f5d6b9e4 Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Sat, 6 Feb 2021 16:44:57 +0100 Subject: [PATCH 35/72] Revert "Fixed for loop problem, corrected all occurences that got linted" This reverts commit 6626295fbc747d04f1a8d14f19ee48c789b90e50. --- clippy_lints/src/assertions_on_constants.rs | 2 +- clippy_lints/src/attrs.rs | 6 ++-- clippy_lints/src/bit_mask.rs | 6 ++-- clippy_lints/src/booleans.rs | 6 ++-- clippy_lints/src/collapsible_if.rs | 2 +- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/eq_op.rs | 10 +++--- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/eval_order_dependence.rs | 2 +- clippy_lints/src/functions.rs | 6 ++-- clippy_lints/src/future_not_send.rs | 2 +- clippy_lints/src/infinite_iter.rs | 2 +- clippy_lints/src/inherent_impl.rs | 4 +-- clippy_lints/src/len_zero.rs | 4 +-- clippy_lints/src/let_underscore.rs | 8 ++--- clippy_lints/src/lifetimes.rs | 4 +-- clippy_lints/src/literal_representation.rs | 8 ++--- clippy_lints/src/loops.rs | 22 ++++++------- clippy_lints/src/macro_use.rs | 6 ++-- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/map_clone.rs | 6 ++-- clippy_lints/src/matches.rs | 6 ++-- .../src/methods/bind_instead_of_map.rs | 2 +- clippy_lints/src/methods/mod.rs | 20 ++++++------ clippy_lints/src/mut_reference.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 2 +- .../src/needless_arbitrary_self_type.rs | 2 +- clippy_lints/src/needless_bool.rs | 18 +++++------ clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 2 +- clippy_lints/src/open_options.rs | 10 +++--- clippy_lints/src/question_mark.rs | 2 +- clippy_lints/src/redundant_closure_call.rs | 2 +- clippy_lints/src/redundant_pub_crate.rs | 2 +- clippy_lints/src/returns.rs | 4 +-- .../src/semicolon_if_nothing_returned.rs | 32 +++++++++++-------- clippy_lints/src/shadow.rs | 10 +++--- .../src/slow_vector_initialization.rs | 2 +- .../src/suspicious_operation_groupings.rs | 6 ++-- clippy_lints/src/transmute.rs | 6 ++-- clippy_lints/src/types.rs | 6 ++-- clippy_lints/src/unicode.rs | 4 +-- clippy_lints/src/unused_self.rs | 2 +- clippy_lints/src/upper_case_acronyms.rs | 2 +- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/utils/attrs.rs | 2 +- clippy_lints/src/utils/author.rs | 2 +- clippy_lints/src/utils/diagnostics.rs | 2 +- clippy_lints/src/utils/mod.rs | 2 +- clippy_lints/src/utils/sugg.rs | 2 +- clippy_lints/src/utils/usage.rs | 6 ++-- clippy_lints/src/utils/visitors.rs | 2 +- clippy_lints/src/verbose_file_reads.rs | 2 +- clippy_lints/src/write.rs | 2 +- tests/ui/semicolon_if_nothing_returned.rs | 7 ---- tests/ui/semicolon_if_nothing_returned.stderr | 10 +++--- 55 files changed, 148 insertions(+), 149 deletions(-) diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index b9de478017306..aa431f0596cca 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { &format!("`assert!(false, {})` should probably be replaced", panic_message), None, &format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message), - ); + ) }; if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") { diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 90463d7f026d3..652d1fa16b6de 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -277,7 +277,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if is_relevant_item(cx, item) { - check_attrs(cx, item.span, item.ident.name, &item.attrs); + check_attrs(cx, item.span, item.ident.name, &item.attrs) } match item.kind { ItemKind::ExternCrate(..) | ItemKind::Use(..) => { @@ -353,13 +353,13 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { if is_relevant_impl(cx, item) { - check_attrs(cx, item.span, item.ident.name, &item.attrs); + check_attrs(cx, item.span, item.ident.name, &item.attrs) } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if is_relevant_trait(cx, item) { - check_attrs(cx, item.span, item.ident.name, &item.attrs); + check_attrs(cx, item.span, item.ident.name, &item.attrs) } } } diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index 8d9fbcf4fd19e..a4ee54076ee98 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -115,9 +115,9 @@ impl<'tcx> LateLintPass<'tcx> for BitMask { if let ExprKind::Binary(cmp, left, right) = &e.kind { if cmp.node.is_comparison() { if let Some(cmp_opt) = fetch_int_literal(cx, right) { - check_compare(cx, left, cmp.node, cmp_opt, e.span); + check_compare(cx, left, cmp.node, cmp_opt, e.span) } else if let Some(cmp_val) = fetch_int_literal(cx, left) { - check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span); + check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span) } } } @@ -171,7 +171,7 @@ fn check_compare(cx: &LateContext<'_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp } fetch_int_literal(cx, right) .or_else(|| fetch_int_literal(cx, left)) - .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span)); + .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span)) } } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 75f011a7fa0bd..90bb0bd555f27 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool { _: Span, _: HirId, ) { - NonminimalBoolVisitor { cx }.visit_body(body); + NonminimalBoolVisitor { cx }.visit_body(body) } } @@ -184,7 +184,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { Term(n) => { let terminal = self.terminals[n as usize]; if let Some(str) = simplify_not(self.cx, terminal) { - self.output.push_str(&str); + self.output.push_str(&str) } else { self.output.push('!'); let snip = snippet_opt(self.cx, terminal.span)?; @@ -452,7 +452,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { } match &e.kind { ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => { - self.bool_expr(e); + self.bool_expr(e) }, ExprKind::Unary(UnOp::UnNot, inner) => { if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() { diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 4e7a6250add6f..93ccc76d0c9cd 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -92,7 +92,7 @@ declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]); impl EarlyLintPass for CollapsibleIf { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { if !expr.span.from_expansion() { - check_if(cx, expr); + check_if(cx, expr) } } } diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 59b1c806e23a6..90d31dece1311 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -118,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { "`if` chain can be rewritten with `match`", None, "Consider rewriting the `if` chain to use `cmp` and `match`.", - ); + ) } } diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index e2881315b5663..6308f6e2e7e9d 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { vec![(left.span, lsnip), (right.span, rsnip)], ); }, - ); + ) } else if lcpy && !rcpy && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()]) @@ -175,7 +175,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ); + ) } else if !lcpy && rcpy && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()]) @@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ); + ) } }, // &foo == bar @@ -218,7 +218,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ); + ) } }, // foo == &bar @@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { rsnip, Applicability::MaybeIncorrect, // FIXME #2597 ); - }); + }) } }, _ => {}, diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 91f9df4649bfc..1a722d39f730b 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { match expr.kind { ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => { for arg in args { - check_closure(cx, arg); + check_closure(cx, arg) } }, _ => (), diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 8df14d80026b6..bc2b2904698c7 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -116,7 +116,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { self.visit_expr(e); for arm in arms { if let Some(Guard::If(if_expr)) = arm.guard { - self.visit_expr(if_expr); + self.visit_expr(if_expr) } // make sure top level arm expressions aren't linted self.maybe_walk_expr(&*arm.body); diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 45973c8b0f7d5..8795425461033 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -270,7 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions { _, ) | intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => { - self.check_arg_number(cx, decl, span.with_hi(decl.output.span().hi())); + self.check_arg_number(cx, decl, span.with_hi(decl.output.span().hi())) }, _ => {}, } @@ -434,7 +434,7 @@ impl<'tcx> Functions { TOO_MANY_LINES, span, &format!("this function has too many lines ({}/{})", line_count, self.max_lines), - ); + ) } } @@ -707,7 +707,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { } }, Assign(ref target, ..) | AssignOp(_, ref target, _) | AddrOf(_, hir::Mutability::Mut, ref target) => { - self.mutates_static |= is_mutated_static(self.cx, target); + self.mutates_static |= is_mutated_static(self.cx, target) }, _ => {}, } diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 55bdda7138ede..7208e66ff7be1 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { )); } } - }); + }) }, ); } diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index dd0a3d1610b53..129abd7d89749 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter { return; }, }; - span_lint(cx, lint, expr.span, msg); + span_lint(cx, lint, expr.span, msg) } } diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 2c5e6f11216e5..ea26c84cde16a 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -85,8 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { |diag| { diag.span_note(*initial_span, "first implementation here"); }, - ); - }); + ) + }) } } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 599602c4a0bd1..e95caf6a35f90 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -256,9 +256,9 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> } } - check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to); + check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to) } else { - check_empty_expr(cx, span, method, lit, op); + check_empty_expr(cx, span, method, lit, op) } } diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 3362177574281..6a5a77f8690a9 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { None, "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" - ); + ) } else if implements_drop { span_lint_and_help( cx, @@ -153,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { None, "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" - ); + ) } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { span_lint_and_help( cx, @@ -162,7 +162,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "non-binding let on an expression with `#[must_use]` type", None, "consider explicitly using expression value" - ); + ) } else if is_must_use_func_call(cx, init) { span_lint_and_help( cx, @@ -171,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "non-binding let on a result of a `#[must_use]` function", None, "consider explicitly using function result" - ); + ) } } } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 740f207b214db..e84c8b4e5b3e0 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -205,7 +205,7 @@ fn could_use_elision<'tcx>( output_visitor.visit_ty(ty); } for lt in named_generics { - input_visitor.visit_generic_param(lt); + input_visitor.visit_generic_param(lt) } if input_visitor.abort() || output_visitor.abort() { @@ -460,7 +460,7 @@ impl<'tcx> Visitor<'tcx> for LifetimeChecker { // `'b` in `'a: 'b` is useless unless used elsewhere in // a non-lifetime bound if let GenericParamKind::Type { .. } = param.kind { - walk_generic_param(self, param); + walk_generic_param(self, param) } } fn nested_visit_map(&mut self) -> NestedVisitorMap { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 7b75ab89bb847..87a957a9bd241 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -229,7 +229,7 @@ impl EarlyLintPass for LiteralDigitGrouping { } if let ExprKind::Lit(ref lit) = expr.kind { - self.check_lit(cx, lit); + self.check_lit(cx, lit) } } } @@ -292,7 +292,7 @@ impl LiteralDigitGrouping { } }; if should_warn { - warning_type.display(num_lit.format(), cx, lit.span); + warning_type.display(num_lit.format(), cx, lit.span) } } } @@ -422,7 +422,7 @@ impl EarlyLintPass for DecimalLiteralRepresentation { } if let ExprKind::Lit(ref lit) = expr.kind { - self.check_lit(cx, lit); + self.check_lit(cx, lit) } } } @@ -444,7 +444,7 @@ impl DecimalLiteralRepresentation { let hex = format!("{:#X}", val); let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false); let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| { - warning_type.display(num_lit.format(), cx, lit.span); + warning_type.display(num_lit.format(), cx, lit.span) }); } } diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index c7e0d32ca2731..663c2df23e22b 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1426,7 +1426,7 @@ fn detect_same_item_push<'tcx>( "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", item_str, vec_str, item_str ), - ); + ) } if !matches!(pat.kind, PatKind::Wild) { @@ -1714,7 +1714,7 @@ fn lint_iter_method(cx: &LateContext<'_>, args: &[Expr<'_>], arg: &Expr<'_>, met "to write this more concisely, try", format!("&{}{}", muta, object), applicability, - ); + ) } fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: &Expr<'_>) { @@ -1753,7 +1753,7 @@ fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: }, ); if TyS::same_type(receiver_ty_adjusted, ref_receiver_ty) { - lint_iter_method(cx, args, arg, method_name); + lint_iter_method(cx, args, arg, method_name) } } } else if method_name == "next" && match_trait_method(cx, arg, &paths::ITERATOR) { @@ -2075,10 +2075,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { if let ty::BorrowKind::MutBorrow = bk { if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low { - self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)); + self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)) } if Some(id) == self.hir_id_high { - self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)); + self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)) } } } @@ -2087,10 +2087,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low { - self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)); + self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)) } if Some(id) == self.hir_id_high { - self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)); + self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)) } } } @@ -2543,10 +2543,10 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { } }, ExprKind::Assign(ref lhs, _, _) if lhs.hir_id == expr.hir_id => { - *state = IncrementVisitorVarState::DontWarn; + *state = IncrementVisitorVarState::DontWarn }, ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => { - *state = IncrementVisitorVarState::DontWarn; + *state = IncrementVisitorVarState::DontWarn }, _ => (), } @@ -2670,7 +2670,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } }, ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => { - self.state = InitializeVisitorState::DontWarn; + self.state = InitializeVisitorState::DontWarn }, _ => (), } @@ -2815,7 +2815,7 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { return; } } - walk_pat(self, pat); + walk_pat(self, pat) } fn nested_visit_map(&mut self) -> NestedVisitorMap { diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index f4ffe18994061..bb52888883af5 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -206,9 +206,9 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { let mut suggestions = vec![]; for ((root, span), path) in used { if path.len() == 1 { - suggestions.push((span, format!("{}::{}", root, path[0]))); + suggestions.push((span, format!("{}::{}", root, path[0]))) } else { - suggestions.push((span, format!("{}::{{{}}}", root, path.join(", ")))); + suggestions.push((span, format!("{}::{{{}}}", root, path.join(", ")))) } } @@ -225,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { "remove the attribute and import the macro directly, try", help, Applicability::MaybeIncorrect, - ); + ) } } } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 11d101c502522..42a92104a4919 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { kind_word, snippet(cx, pattern.span, "..")))] .into_iter().chain(strippings.into_iter().map(|span| (span, "".into()))), - ); + ) }); } } diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index b3be755d4884e..1818836d5d5e8 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -122,7 +122,7 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { "remove the `map` call", String::new(), Applicability::MachineApplicable, - ); + ) } fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { @@ -139,7 +139,7 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { snippet_with_applicability(cx, root, "..", &mut applicability) ), applicability, - ); + ) } else { span_lint_and_sugg( cx, @@ -152,6 +152,6 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { snippet_with_applicability(cx, root, "..", &mut applicability) ), applicability, - ); + ) } } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 74d3677777928..ba7b9bd04248d 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1046,7 +1046,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) "try this", suggestion[0].clone(), Applicability::MaybeIncorrect, - ); + ) }; span_lint_and_sugg( @@ -1057,7 +1057,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) "try this", suggestion.join(" | "), Applicability::MaybeIncorrect, - ); + ) } } @@ -1156,7 +1156,7 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp cast, ), applicability, - ); + ) } } } diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 897a3194ca181..540a1484a8558 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -151,7 +151,7 @@ pub(crate) trait BindInsteadOfMap { .into_iter() .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())), ), - ); + ) }); } can_sugg diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e02b640381996..a17c5996293e9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1582,10 +1582,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]), ["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0], method_spans[1]), ["is_some", "position"] => { - lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0], method_spans[1]); + lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0], method_spans[1]) }, ["is_some", "rposition"] => { - lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]); + lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) }, ["extend", ..] => lint_extend(cx, expr, arg_lists[0]), ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), @@ -1601,17 +1601,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["count", "map"] => lint_suspicious_map(cx, expr), ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr), ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => { - manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..]); + manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..]) }, ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => { - check_pointer_offset(cx, expr, arg_lists[0]); + 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, self.msrv.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()); + 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"), @@ -2446,16 +2446,16 @@ fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: if let hir::ExprKind::Lit(ref lit) = fold_args[1].kind { match lit.node { ast::LitKind::Bool(false) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Or, "any", true); + check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Or, "any", true) }, ast::LitKind::Bool(true) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::And, "all", true); + check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::And, "all", true) }, ast::LitKind::Int(0, _) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Add, "sum", false); + check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Add, "sum", false) }, ast::LitKind::Int(1, _) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Mul, "product", false); + check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Mul, "product", false) }, _ => (), } diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 7c21632c9d594..3f0b765df1561 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(e.hir_id); let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs); - check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method"); + check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method") }, _ => (), } diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index b99e9576f5e16..76417aa7ed09d 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -106,7 +106,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> { _ if !self.found => self.expr_span = Some(expr.span), _ => return, } - walk_expr(self, expr); + walk_expr(self, expr) } fn nested_visit_map(&mut self) -> NestedVisitorMap { diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 107d6a5796604..7687962bdd9bf 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -120,7 +120,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { match &p.ty.kind { TyKind::Path(None, path) => { if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind { - check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl); + check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl) } }, TyKind::Rptr(lifetime, mut_ty) => { diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 614a1e8980cd2..d795f12645794 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { } if parent_node_is_if_expr(&e, &cx) { - snip = snip.blockify(); + snip = snip.blockify() } span_lint_and_sugg( @@ -142,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison { |h: Sugg<'_>| !h, "equality checks against false can be replaced by a negation", )); - check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal); + check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal) }, BinOpKind::Ne => { let true_case = Some(( @@ -150,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison { "inequality checks against true can be replaced by a negation", )); let false_case = Some((|h| h, "inequality checks against false are unnecessary")); - check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal); + check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal) }, BinOpKind::Lt => check_comparison( cx, @@ -249,22 +249,22 @@ fn check_comparison<'a, 'tcx>( snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability) ), applicability, - ); + ) } } match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) { (Bool(true), Other) => left_true.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, right_side, applicability, m, h); + suggest_bool_comparison(cx, e, right_side, applicability, m, h) }), (Other, Bool(true)) => right_true.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, left_side, applicability, m, h); + suggest_bool_comparison(cx, e, left_side, applicability, m, h) }), (Bool(false), Other) => left_false.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, right_side, applicability, m, h); + suggest_bool_comparison(cx, e, right_side, applicability, m, h) }), (Other, Bool(false)) => right_false.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, left_side, applicability, m, h); + suggest_bool_comparison(cx, e, left_side, applicability, m, h) }), (Other, Other) => no_literal.map_or((), |(h, m)| { let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability); @@ -277,7 +277,7 @@ fn check_comparison<'a, 'tcx>( "try simplifying it as shown", h(left_side, right_side).to_string(), applicability, - ); + ) }), _ => (), } diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 6a20d5f139a43..4fb899125e8ad 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { types produces code that is hard to read and refactor, please \ consider using the `partial_cmp` method instead, to make it \ clear that the two values could be incomparable" - ); + ) } } } diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index 82143f7a28886..73a99a3a2f870 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -125,7 +125,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `create` is called more than once", ); } else { - create = true; + create = true } create_arg = create_arg || (arg == Argument::True); }, @@ -138,7 +138,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `append` is called more than once", ); } else { - append = true; + append = true } append_arg = append_arg || (arg == Argument::True); }, @@ -151,7 +151,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `truncate` is called more than once", ); } else { - truncate = true; + truncate = true } truncate_arg = truncate_arg || (arg == Argument::True); }, @@ -164,7 +164,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `read` is called more than once", ); } else { - read = true; + read = true } read_arg = read_arg || (arg == Argument::True); }, @@ -177,7 +177,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `write` is called more than once", ); } else { - write = true; + write = true } write_arg = write_arg || (arg == Argument::True); }, diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 63c904b7fb4c5..6c480d48c7561 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -88,7 +88,7 @@ impl QuestionMark { "replace it with", replacement_str, applicability, - ); + ) } } } diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index daea1592018d6..f398b3fff25a3 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -56,7 +56,7 @@ impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor { self.found_return = true; } - ast_visit::walk_expr(self, ex); + ast_visit::walk_expr(self, ex) } } diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 127f6078dabb6..acd9047ace617 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { Applicability::MachineApplicable, ); }, - ); + ) } } } diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index e7b66c5ebcf07..e438f92b136ac 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { } else { RetReplacement::Empty }; - check_final_expr(cx, &body.value, Some(body.value.span), replacement); + check_final_expr(cx, &body.value, Some(body.value.span), replacement) }, FnKind::ItemFn(..) | FnKind::Method(..) => { if let ExprKind::Block(ref block, _) = body.value.kind { @@ -239,7 +239,7 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option match replacement { RetReplacement::Empty => { diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index f47ca1b69b170..22cd10ced189f 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,7 +1,7 @@ -use crate::utils::{in_macro, span_lint_and_sugg, sugg}; +use crate::utils::{in_macro, span_lint_and_then, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Block, ExprKind}; +use rustc_hir::*; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -42,25 +42,31 @@ impl LateLintPass<'_> for SemicolonIfNothingReturned { if let Some(expr) = block.expr; let t_expr = cx.typeck_results().expr_ty(expr); if t_expr.is_unit(); - if let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(expr.span.source_callsite()); - if !snippet.ends_with('}'); then { - // filter out the desugared `for` loop - if let ExprKind::DropTemps(..) = &expr.kind { - return; + match expr.kind { + ExprKind::Loop(..) | + ExprKind::Match(..) | + ExprKind::Block(..) | + ExprKind::If(..) if !in_macro(expr.span) => return, + _ => (), } let sugg = sugg::Sugg::hir(cx, &expr, ".."); let suggestion = format!("{0};", sugg); - span_lint_and_sugg( + span_lint_and_then( cx, SEMICOLON_IF_NOTHING_RETURNED, expr.span, - "Consider adding a `;` to the last statement for consistent formatting", - "add a `;` here", - suggestion, - Applicability::MaybeIncorrect, - ); + "add `;` to terminate block", + | diag | { + diag.span_suggestion( + expr.span, + "add `;`", + suggestion, + Applicability::MaybeIncorrect, + ); + } + ) } } } diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 3af98632712f2..d5b1767e945b9 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -118,7 +118,7 @@ fn check_fn<'tcx>(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>, body: &'tcx Bo let mut bindings = Vec::with_capacity(decl.inputs.len()); for arg in iter_input_pats(decl, body) { if let PatKind::Binding(.., ident, _) = arg.pat.kind { - bindings.push((ident.name, ident.span)); + bindings.push((ident.name, ident.span)) } } check_expr(cx, &body.value, &mut bindings); @@ -154,7 +154,7 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: & .. } = *local; if let Some(ref t) = *ty { - check_ty(cx, t, bindings); + check_ty(cx, t, bindings) } if let Some(ref o) = *init { check_expr(cx, o, bindings); @@ -330,7 +330,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut // ExprKind::MethodCall ExprKind::Array(v) | ExprKind::Tup(v) => { for e in v { - check_expr(cx, e, bindings); + check_expr(cx, e, bindings) } }, ExprKind::If(ref cond, ref then, ref otherwise) => { @@ -371,11 +371,11 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<( check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings); }, TyKind::Ptr(MutTy { ty: ref mty, .. }) | TyKind::Rptr(_, MutTy { ty: ref mty, .. }) => { - check_ty(cx, mty, bindings); + check_ty(cx, mty, bindings) }, TyKind::Tup(tup) => { for t in tup { - check_ty(cx, t, bindings); + check_ty(cx, t, bindings) } }, TyKind::Typeof(ref anon_const) => check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings), diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 9ba9b4187d26e..96f6881556cf3 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -306,7 +306,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { fn visit_block(&mut self, block: &'tcx Block<'_>) { if self.initialization_found { if let Some(ref s) = block.stmts.get(0) { - self.visit_stmt(s); + self.visit_stmt(s) } self.initialization_found = false; diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index f245789d75dcf..cccd24ccf9401 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -265,7 +265,7 @@ fn emit_suggestion(cx: &EarlyContext<'_>, span: Span, sugg: String, applicabilit "I think you meant", sugg, applicability, - ); + ) } fn ident_swap_sugg( @@ -476,7 +476,7 @@ impl Add for IdentLocation { impl AddAssign for IdentLocation { fn add_assign(&mut self, other: Self) { - *self = *self + other; + *self = *self + other } } @@ -507,7 +507,7 @@ impl Add for IdentDifference { impl AddAssign for IdentDifference { fn add_assign(&mut self, other: Self) { - *self = *self + other; + *self = *self + other } } diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index e619a1a698a3c..d977cea4da50b 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -463,7 +463,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { Applicability::Unspecified, ); }, - ); + ) }, (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) => { if_chain! { @@ -519,7 +519,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { Applicability::Unspecified, ); }, - ); + ) } } } @@ -552,7 +552,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { Applicability::Unspecified, ); }, - ); + ) }, (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context => span_lint_and_then( cx, diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index dd3e934889aad..1b0f1e309aa2c 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -630,7 +630,7 @@ impl Types { TyKind::Rptr(ref lt, ref mut_ty) => self.check_ty_rptr(cx, hir_ty, is_local, lt, mut_ty), // recurse TyKind::Slice(ref ty) | TyKind::Array(ref ty, _) | TyKind::Ptr(MutTy { ref ty, .. }) => { - self.check_ty(cx, ty, is_local); + self.check_ty(cx, ty, is_local) }, TyKind::Tup(tys) => { for ty in tys { @@ -2436,7 +2436,7 @@ fn upcast_comparison_bounds_err<'tcx>( }, Rel::Eq | Rel::Ne => unreachable!(), } { - err_upcast_comparison(cx, span, lhs, true); + err_upcast_comparison(cx, span, lhs, true) } else if match rel { Rel::Lt => { if invert { @@ -2454,7 +2454,7 @@ fn upcast_comparison_bounds_err<'tcx>( }, Rel::Eq | Rel::Ne => unreachable!(), } { - err_upcast_comparison(cx, span, lhs, false); + err_upcast_comparison(cx, span, lhs, false) } } } diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index 9346e3c1d3bef..93d59cc7fcd17 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -69,7 +69,7 @@ impl LateLintPass<'_> for Unicode { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { if let ExprKind::Lit(ref lit) = expr.kind { if let LitKind::Str(_, _) = lit.node { - check_str(cx, lit.span, expr.hir_id); + check_str(cx, lit.span, expr.hir_id) } } } @@ -80,7 +80,7 @@ fn escape>(s: T) -> String { for c in s { if c as u32 > 0x7F { for d in c.escape_unicode() { - result.push(d); + result.push(d) } } else { result.push(c); diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 83ba9c897e0dc..5349c4f7eb8a7 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -94,7 +94,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnusedSelfVisitor<'a, 'tcx> { return; } if let Res::Local(hir_id) = &path.res { - self.uses_self = self.self_hir_id == hir_id; + self.uses_self = self.self_hir_id == hir_id } walk_path(self, path); } diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index 0f04a4a62ce14..61e7031716a9d 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -69,7 +69,7 @@ fn check_ident(cx: &EarlyContext<'_>, ident: &Ident) { "consider making the acronym lowercase, except the initial letter", corrected, Applicability::MaybeIncorrect, - ); + ) } } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 4bbfb3fbeb19a..72d1ca7392913 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -103,7 +103,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SemanticUseSelfVisitor<'a, 'tcx> { } } - walk_ty(self, hir_ty); + walk_ty(self, hir_ty) } fn nested_visit_map(&mut self) -> NestedVisitorMap { diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs index 588c31ea40f32..8d28421d70d70 100644 --- a/clippy_lints/src/utils/attrs.rs +++ b/clippy_lints/src/utils/attrs.rs @@ -115,7 +115,7 @@ fn parse_attrs(sess: &Session, attrs: &[ast::Attribute], name: &' for attr in get_attr(sess, attrs, name) { if let Some(ref value) = attr.value_str() { if let Ok(value) = FromStr::from_str(&value.as_str()) { - f(value); + f(value) } else { sess.span_err(attr.span, "not a number"); } diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index b8c5011249780..ca60d335262b3 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -293,7 +293,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { LitKind::Str(ref text, _) => { let str_pat = self.next("s"); println!(" if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat); - println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str()); + println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str()) }, } }, diff --git a/clippy_lints/src/utils/diagnostics.rs b/clippy_lints/src/utils/diagnostics.rs index f74ce999b5c7a..269be217c2d87 100644 --- a/clippy_lints/src/utils/diagnostics.rs +++ b/clippy_lints/src/utils/diagnostics.rs @@ -211,7 +211,7 @@ pub fn multispan_sugg(diag: &mut DiagnosticBuilder<'_>, help_msg: &str, sugg: where I: IntoIterator, { - multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg); + multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg) } pub fn multispan_sugg_with_applicability( diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index a519dce66d4af..cf93ee0a7a5c6 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -464,7 +464,7 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option DiagnosticBuilderExt for rustc_errors::DiagnosticBuilder if let Some(non_whitespace_offset) = non_whitespace_offset { remove_span = remove_span - .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large"))); + .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large"))) } } diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index 8bf169c0d06a8..fc0db7f64ec95 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -60,7 +60,7 @@ impl<'tcx> MutVarsDelegate { //FIXME: This causes false negatives. We can't get the `NodeId` from //`Categorization::Upvar(_)`. So we search for any `Upvar`s in the //`while`-body, not just the ones in the condition. - self.skip = true; + self.skip = true }, _ => {}, } @@ -72,12 +72,12 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) { if let ty::BorrowKind::MutBorrow = bk { - self.update(&cmt); + self.update(&cmt) } } fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) { - self.update(&cmt); + self.update(&cmt) } } diff --git a/clippy_lints/src/utils/visitors.rs b/clippy_lints/src/utils/visitors.rs index caaf636c89743..ebf69df31ca41 100644 --- a/clippy_lints/src/utils/visitors.rs +++ b/clippy_lints/src/utils/visitors.rs @@ -87,7 +87,7 @@ where } fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { - intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt); + intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) } fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index 92965e95cdaa3..32574d9d6c9a8 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for VerboseFileReads { "use of `File::read_to_string`", None, "consider using `fs::read_to_string` instead", - ); + ) } } } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index f9ccf322dda05..e40fdca6a9947 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -298,7 +298,7 @@ impl EarlyLintPass for Write { Applicability::MachineApplicable, ); }, - ); + ) } } } else if mac.path == sym!(writeln) { diff --git a/tests/ui/semicolon_if_nothing_returned.rs b/tests/ui/semicolon_if_nothing_returned.rs index 0abe2cca26757..2c07cc9df40d6 100644 --- a/tests/ui/semicolon_if_nothing_returned.rs +++ b/tests/ui/semicolon_if_nothing_returned.rs @@ -46,10 +46,3 @@ fn foobar(x: i32) { y = x + 1; } } - -fn loop_test(x: i32) { - let y: i32; - for &ext in &["stdout", "stderr", "fixed"] { - println!("{}", ext); - } -} diff --git a/tests/ui/semicolon_if_nothing_returned.stderr b/tests/ui/semicolon_if_nothing_returned.stderr index 2bc73342467d7..6026320f4b47d 100644 --- a/tests/ui/semicolon_if_nothing_returned.stderr +++ b/tests/ui/semicolon_if_nothing_returned.stderr @@ -1,4 +1,4 @@ -error: Consider adding a `;` to the last statement for consistent formatting +error: add `;` to terminate block --> $DIR/semicolon_if_nothing_returned.rs:8:5 | LL | println!("Hello") @@ -7,17 +7,17 @@ LL | println!("Hello") = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: Consider adding a `;` to the last statement for consistent formatting +error: add `;` to terminate block --> $DIR/semicolon_if_nothing_returned.rs:12:5 | LL | get_unit() - | ^^^^^^^^^^ help: add a `;` here: `get_unit();` + | ^^^^^^^^^^ help: add `;`: `get_unit();` -error: Consider adding a `;` to the last statement for consistent formatting +error: add `;` to terminate block --> $DIR/semicolon_if_nothing_returned.rs:17:5 | LL | y = x + 1 - | ^^^^^^^^^ help: add a `;` here: `y = x + 1;` + | ^^^^^^^^^ help: add `;`: `y = x + 1;` error: aborting due to 3 previous errors From 85c2b1e5f4cbe7d31ebbaf6b9620350020251c15 Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Sat, 6 Feb 2021 16:56:18 +0100 Subject: [PATCH 36/72] Switched to `snippet_with_macro_callsite` --- .../src/semicolon_if_nothing_returned.rs | 35 ++++++++----------- tests/ui/semicolon_if_nothing_returned.rs | 7 ++++ tests/ui/semicolon_if_nothing_returned.stderr | 10 +++--- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 22cd10ced189f..628725c52e94e 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,7 +1,7 @@ -use crate::utils::{in_macro, span_lint_and_then, sugg}; +use crate::utils::{in_macro, span_lint_and_sugg, sugg, snippet_with_macro_callsite}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -11,7 +11,6 @@ declare_clippy_lint! { /// /// **Why is this bad?** The semicolon might be optional but when /// extending the block with new code, it doesn't require a change in previous last line. - /// It's also more idiomatic. /// /// **Known problems:** None. /// @@ -29,7 +28,7 @@ declare_clippy_lint! { /// } /// ``` pub SEMICOLON_IF_NOTHING_RETURNED, - pedantic, + restriction, "add a semicolon if nothing is returned" } @@ -42,31 +41,25 @@ impl LateLintPass<'_> for SemicolonIfNothingReturned { if let Some(expr) = block.expr; let t_expr = cx.typeck_results().expr_ty(expr); if t_expr.is_unit(); + if let snippet = snippet_with_macro_callsite(cx, expr.span, "}"); + if !snippet.ends_with('}'); then { - match expr.kind { - ExprKind::Loop(..) | - ExprKind::Match(..) | - ExprKind::Block(..) | - ExprKind::If(..) if !in_macro(expr.span) => return, - _ => (), + // filter out the desugared `for` loop + if let ExprKind::DropTemps(..) = &expr.kind { + return; } let sugg = sugg::Sugg::hir(cx, &expr, ".."); let suggestion = format!("{0};", sugg); - span_lint_and_then( + span_lint_and_sugg( cx, SEMICOLON_IF_NOTHING_RETURNED, expr.span, - "add `;` to terminate block", - | diag | { - diag.span_suggestion( - expr.span, - "add `;`", - suggestion, - Applicability::MaybeIncorrect, - ); - } - ) + "consider adding a `;` to the last statement for consistent formatting", + "add a `;` here", + suggestion, + Applicability::MaybeIncorrect, + ); } } } diff --git a/tests/ui/semicolon_if_nothing_returned.rs b/tests/ui/semicolon_if_nothing_returned.rs index 2c07cc9df40d6..0abe2cca26757 100644 --- a/tests/ui/semicolon_if_nothing_returned.rs +++ b/tests/ui/semicolon_if_nothing_returned.rs @@ -46,3 +46,10 @@ fn foobar(x: i32) { y = x + 1; } } + +fn loop_test(x: i32) { + let y: i32; + for &ext in &["stdout", "stderr", "fixed"] { + println!("{}", ext); + } +} diff --git a/tests/ui/semicolon_if_nothing_returned.stderr b/tests/ui/semicolon_if_nothing_returned.stderr index 6026320f4b47d..56211ff7f773c 100644 --- a/tests/ui/semicolon_if_nothing_returned.stderr +++ b/tests/ui/semicolon_if_nothing_returned.stderr @@ -1,4 +1,4 @@ -error: add `;` to terminate block +error: consider adding a `;` to the last statement for consistent formatting --> $DIR/semicolon_if_nothing_returned.rs:8:5 | LL | println!("Hello") @@ -7,17 +7,17 @@ LL | println!("Hello") = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: add `;` to terminate block +error: consider adding a `;` to the last statement for consistent formatting --> $DIR/semicolon_if_nothing_returned.rs:12:5 | LL | get_unit() - | ^^^^^^^^^^ help: add `;`: `get_unit();` + | ^^^^^^^^^^ help: add a `;` here: `get_unit();` -error: add `;` to terminate block +error: consider adding a `;` to the last statement for consistent formatting --> $DIR/semicolon_if_nothing_returned.rs:17:5 | LL | y = x + 1 - | ^^^^^^^^^ help: add `;`: `y = x + 1;` + | ^^^^^^^^^ help: add a `;` here: `y = x + 1;` error: aborting due to 3 previous errors From f1c15840a2bbd953414a650d24ee22d3a1c710f5 Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Sat, 6 Feb 2021 17:06:06 +0100 Subject: [PATCH 37/72] Changed lint level to `restriction` --- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/semicolon_if_nothing_returned.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f6014c246d685..e2c325a76478b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1294,6 +1294,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&panic_unimplemented::UNIMPLEMENTED), LintId::of(&panic_unimplemented::UNREACHABLE), LintId::of(&pattern_type_mismatch::PATTERN_TYPE_MISMATCH), + LintId::of(&semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), LintId::of(&shadow::SHADOW_REUSE), LintId::of(&shadow::SHADOW_SAME), LintId::of(&strings::STRING_ADD), @@ -1367,7 +1368,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ranges::RANGE_PLUS_ONE), LintId::of(&redundant_else::REDUNDANT_ELSE), LintId::of(&ref_option_ref::REF_OPTION_REF), - LintId::of(&semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), LintId::of(&shadow::SHADOW_UNRELATED), LintId::of(&strings::STRING_ADD_ASSIGN), LintId::of(&trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS), diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 628725c52e94e..6133e86a26a27 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,4 +1,4 @@ -use crate::utils::{in_macro, span_lint_and_sugg, sugg, snippet_with_macro_callsite}; +use crate::utils::{in_macro, snippet_with_macro_callsite, span_lint_and_sugg, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; From 915e9b85a410a69542d147c3644d9e0548986034 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Fri, 29 Jan 2021 14:03:26 +0100 Subject: [PATCH 38/72] Fix cargo_common_metadata warning on `publish = false`. --- clippy_lints/src/cargo_common_metadata.rs | 54 ++++++++++--------- .../cargo_common_metadata/fail/Cargo.toml | 1 - .../fail_publish/Cargo.toml | 6 +++ .../fail_publish/src/main.rs | 4 ++ .../fail_publish/src/main.stderr | 18 +++++++ .../cargo_common_metadata/pass/Cargo.toml | 1 - .../pass_publish_empty/Cargo.toml | 6 +++ .../pass_publish_empty/src/main.rs | 4 ++ .../pass_publish_false/Cargo.toml | 6 +++ .../pass_publish_false/src/main.rs | 4 ++ 10 files changed, 76 insertions(+), 28 deletions(-) create mode 100644 tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml create mode 100644 tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs create mode 100644 tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr create mode 100644 tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml create mode 100644 tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs create mode 100644 tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml create mode 100644 tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index 0d294761af5ab..84c6eff79a1af 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -80,32 +80,34 @@ impl LateLintPass<'_> for CargoCommonMetadata { let metadata = unwrap_cargo_metadata!(cx, CARGO_COMMON_METADATA, false); for package in metadata.packages { - if is_empty_vec(&package.authors) { - missing_warning(cx, &package, "package.authors"); - } - - if is_empty_str(&package.description) { - missing_warning(cx, &package, "package.description"); - } - - if is_empty_str(&package.license) && is_empty_path(&package.license_file) { - missing_warning(cx, &package, "either package.license or package.license_file"); - } - - if is_empty_str(&package.repository) { - missing_warning(cx, &package, "package.repository"); - } - - if is_empty_path(&package.readme) { - missing_warning(cx, &package, "package.readme"); - } - - if is_empty_vec(&package.keywords) { - missing_warning(cx, &package, "package.keywords"); - } - - if is_empty_vec(&package.categories) { - missing_warning(cx, &package, "package.categories"); + if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() { + if is_empty_vec(&package.authors) { + missing_warning(cx, &package, "package.authors"); + } + + if is_empty_str(&package.description) { + missing_warning(cx, &package, "package.description"); + } + + if is_empty_str(&package.license) && is_empty_path(&package.license_file) { + missing_warning(cx, &package, "either package.license or package.license_file"); + } + + if is_empty_str(&package.repository) { + missing_warning(cx, &package, "package.repository"); + } + + if is_empty_path(&package.readme) { + missing_warning(cx, &package, "package.readme"); + } + + if is_empty_vec(&package.keywords) { + missing_warning(cx, &package, "package.keywords"); + } + + if is_empty_vec(&package.categories) { + missing_warning(cx, &package, "package.categories"); + } } } } diff --git a/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml index ae0a603299629..1645c975be17d 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml @@ -1,6 +1,5 @@ [package] name = "cargo_common_metadata" version = "0.1.0" -publish = false [workspace] diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml new file mode 100644 index 0000000000000..7595696353cd4 --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" +publish = ["some-registry-name"] + +[workspace] diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs b/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs new file mode 100644 index 0000000000000..27841e18aa9ef --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=cargo_common_metadata +#![warn(clippy::cargo_common_metadata)] + +fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr b/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr new file mode 100644 index 0000000000000..c8ae6c820df9d --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr @@ -0,0 +1,18 @@ +error: package `cargo_common_metadata` is missing `package.authors` metadata + | + = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` + +error: package `cargo_common_metadata` is missing `package.description` metadata + +error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata + +error: package `cargo_common_metadata` is missing `package.repository` metadata + +error: package `cargo_common_metadata` is missing `package.readme` metadata + +error: package `cargo_common_metadata` is missing `package.keywords` metadata + +error: package `cargo_common_metadata` is missing `package.categories` metadata + +error: aborting due to 7 previous errors + diff --git a/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml index 737e84e963c95..86abfd54d4d00 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "cargo_common_metadata" version = "0.1.0" -publish = false authors = ["Random person from the Internet "] description = "A test package for the cargo_common_metadata lint" repository = "https://github.com/someone/cargo_common_metadata" diff --git a/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml new file mode 100644 index 0000000000000..ae0a603299629 --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" +publish = false + +[workspace] diff --git a/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs b/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs new file mode 100644 index 0000000000000..27841e18aa9ef --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=cargo_common_metadata +#![warn(clippy::cargo_common_metadata)] + +fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml new file mode 100644 index 0000000000000..0a879c99b5bd8 --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" +publish = [] + +[workspace] diff --git a/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs b/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs new file mode 100644 index 0000000000000..27841e18aa9ef --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=cargo_common_metadata +#![warn(clippy::cargo_common_metadata)] + +fn main() {} From d4bc7d2c06dcfaf87fc88dd4e1fbc9ad8d289462 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Wed, 3 Feb 2021 18:01:18 +0100 Subject: [PATCH 39/72] Test names were flipped. --- .../cargo_common_metadata/pass_publish_empty/Cargo.toml | 2 +- .../cargo_common_metadata/pass_publish_false/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml index ae0a603299629..0a879c99b5bd8 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo_common_metadata" version = "0.1.0" -publish = false +publish = [] [workspace] diff --git a/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml index 0a879c99b5bd8..ae0a603299629 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo_common_metadata" version = "0.1.0" -publish = [] +publish = false [workspace] From f0d3fd72d7bacb60b1be554612ba19e87ca285cd Mon Sep 17 00:00:00 2001 From: daxpedda Date: Wed, 3 Feb 2021 19:19:30 +0100 Subject: [PATCH 40/72] Implement `_cargo_ignore_publish`. --- clippy_lints/src/cargo_common_metadata.rs | 21 +++++++++++++++---- clippy_lints/src/lib.rs | 3 ++- clippy_lints/src/utils/conf.rs | 2 ++ .../cargo_common_metadata/pass/Cargo.toml | 1 + .../cargo_common_metadata/pass/clippy.toml | 1 + 5 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 tests/ui-cargo/cargo_common_metadata/pass/clippy.toml diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index 84c6eff79a1af..f499345636c8b 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; use crate::utils::{run_lints, span_lint}; use rustc_hir::{hir_id::CRATE_HIR_ID, Crate}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::DUMMY_SP; declare_clippy_lint! { @@ -51,6 +51,21 @@ declare_clippy_lint! { "common metadata is defined in `Cargo.toml`" } +#[derive(Copy, Clone, Debug)] +pub struct CargoCommonMetadata { + ignore_publish: bool, +} + +impl CargoCommonMetadata { + pub fn new(ignore_publish: bool) -> Self { + Self { ignore_publish } + } +} + +impl_lint_pass!(CargoCommonMetadata => [ + CARGO_COMMON_METADATA +]); + fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) { let message = format!("package `{}` is missing `{}` metadata", package.name, field); span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message); @@ -69,8 +84,6 @@ fn is_empty_vec(value: &[String]) -> bool { value.iter().all(String::is_empty) } -declare_lint_pass!(CargoCommonMetadata => [CARGO_COMMON_METADATA]); - impl LateLintPass<'_> for CargoCommonMetadata { fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) { if !run_lints(cx, &[CARGO_COMMON_METADATA], CRATE_HIR_ID) { @@ -80,7 +93,7 @@ impl LateLintPass<'_> for CargoCommonMetadata { let metadata = unwrap_cargo_metadata!(cx, CARGO_COMMON_METADATA, false); for package in metadata.packages { - if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() { + if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || self.ignore_publish { if is_empty_vec(&package.authors) { missing_warning(cx, &package, "package.authors"); } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7f5c4f56f9e05..e8e8229915bc5 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1180,7 +1180,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box redundant_else::RedundantElse); store.register_late_pass(|| box create_dir::CreateDir); store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType); - store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata); + let cargo_ignore_publish = conf._cargo_ignore_publish; + store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish)); store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions); store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies); let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions; diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index b5a8300376c16..0b0d31c860365 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -173,6 +173,8 @@ define_Conf! { (disallowed_methods, "disallowed_methods": Vec, Vec::::new()), /// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators. (unreadable_literal_lint_fractions, "unreadable_literal_lint_fractions": bool, true), + /// Lint: CARGO_COMMON_METADATA. For internal testing only, ignores the current `publish` settings in the Cargo manifest. + (_cargo_ignore_publish, "_cargo_ignore_publish": bool, false), } impl Default for Conf { diff --git a/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml index 86abfd54d4d00..737e84e963c95 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "cargo_common_metadata" version = "0.1.0" +publish = false authors = ["Random person from the Internet "] description = "A test package for the cargo_common_metadata lint" repository = "https://github.com/someone/cargo_common_metadata" diff --git a/tests/ui-cargo/cargo_common_metadata/pass/clippy.toml b/tests/ui-cargo/cargo_common_metadata/pass/clippy.toml new file mode 100644 index 0000000000000..866c4f3c35e8a --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/pass/clippy.toml @@ -0,0 +1 @@ +_cargo_ignore_publish = true From 8805931ce35eeebb9c27c3efdf90245afecef20c Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sat, 6 Feb 2021 16:51:51 +0100 Subject: [PATCH 41/72] Hide clippy configuration option. Co-authored-by: Philipp Krones --- clippy_lints/src/utils/conf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 0b0d31c860365..e8a4236eeaa01 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -173,7 +173,7 @@ define_Conf! { (disallowed_methods, "disallowed_methods": Vec, Vec::::new()), /// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators. (unreadable_literal_lint_fractions, "unreadable_literal_lint_fractions": bool, true), - /// Lint: CARGO_COMMON_METADATA. For internal testing only, ignores the current `publish` settings in the Cargo manifest. + /// Lint: _CARGO_COMMON_METADATA. For internal testing only, ignores the current `publish` settings in the Cargo manifest. (_cargo_ignore_publish, "_cargo_ignore_publish": bool, false), } From f2391a5569a468e5c73cce3b312bb47b655da9d4 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sat, 6 Feb 2021 17:38:14 +0100 Subject: [PATCH 42/72] Change clippy configuration option. --- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/utils/conf.rs | 2 +- tests/ui-cargo/cargo_common_metadata/pass/clippy.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e8e8229915bc5..122523b0528ab 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1180,7 +1180,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box redundant_else::RedundantElse); store.register_late_pass(|| box create_dir::CreateDir); store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType); - let cargo_ignore_publish = conf._cargo_ignore_publish; + let cargo_ignore_publish = conf.cargo_ignore_publish; store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish)); store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions); store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies); diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index e8a4236eeaa01..b4498d13a24a5 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -174,7 +174,7 @@ define_Conf! { /// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators. (unreadable_literal_lint_fractions, "unreadable_literal_lint_fractions": bool, true), /// Lint: _CARGO_COMMON_METADATA. For internal testing only, ignores the current `publish` settings in the Cargo manifest. - (_cargo_ignore_publish, "_cargo_ignore_publish": bool, false), + (cargo_ignore_publish, "cargo_ignore_publish": bool, false), } impl Default for Conf { diff --git a/tests/ui-cargo/cargo_common_metadata/pass/clippy.toml b/tests/ui-cargo/cargo_common_metadata/pass/clippy.toml index 866c4f3c35e8a..de4f04b24fc89 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass/clippy.toml +++ b/tests/ui-cargo/cargo_common_metadata/pass/clippy.toml @@ -1 +1 @@ -_cargo_ignore_publish = true +cargo-ignore-publish = true From 8b89087409e9fef934aa3de28be74a5fcea5cf7f Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sat, 6 Feb 2021 17:38:30 +0100 Subject: [PATCH 43/72] Add test for `publish = true`. --- .../fail_publish_true/Cargo.toml | 6 ++++++ .../fail_publish_true/src/main.rs | 4 ++++ .../fail_publish_true/src/main.stderr | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml create mode 100644 tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs create mode 100644 tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml new file mode 100644 index 0000000000000..7e5b88383ccc3 --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" +publish = true + +[workspace] diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs new file mode 100644 index 0000000000000..27841e18aa9ef --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=cargo_common_metadata +#![warn(clippy::cargo_common_metadata)] + +fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr new file mode 100644 index 0000000000000..c8ae6c820df9d --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr @@ -0,0 +1,18 @@ +error: package `cargo_common_metadata` is missing `package.authors` metadata + | + = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` + +error: package `cargo_common_metadata` is missing `package.description` metadata + +error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata + +error: package `cargo_common_metadata` is missing `package.repository` metadata + +error: package `cargo_common_metadata` is missing `package.readme` metadata + +error: package `cargo_common_metadata` is missing `package.keywords` metadata + +error: package `cargo_common_metadata` is missing `package.categories` metadata + +error: aborting due to 7 previous errors + From cd361a5e64f3f1b5a1389701bc30f64538f8eb69 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sat, 6 Feb 2021 17:52:41 +0100 Subject: [PATCH 44/72] Add back `publish = false` to the old test. --- tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml | 1 + tests/ui-cargo/cargo_common_metadata/fail/clippy.toml | 1 + 2 files changed, 2 insertions(+) create mode 100644 tests/ui-cargo/cargo_common_metadata/fail/clippy.toml diff --git a/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml index 1645c975be17d..ae0a603299629 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "cargo_common_metadata" version = "0.1.0" +publish = false [workspace] diff --git a/tests/ui-cargo/cargo_common_metadata/fail/clippy.toml b/tests/ui-cargo/cargo_common_metadata/fail/clippy.toml new file mode 100644 index 0000000000000..de4f04b24fc89 --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/fail/clippy.toml @@ -0,0 +1 @@ +cargo-ignore-publish = true From e2e33b4d355cb77d716a9fb191d2453b5ab5d42b Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sat, 6 Feb 2021 17:57:31 +0100 Subject: [PATCH 45/72] Pick up `clippy.toml` in `ui-cargo` tests. --- tests/compile-test.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 94f5e616cace8..c0b40add1096d 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -214,6 +214,7 @@ fn run_ui_cargo(config: &mut compiletest::Config) { Some("main.rs") => {}, _ => continue, } + set_var("CLIPPY_CONF_DIR", case.path()); let paths = compiletest::common::TestPaths { file: file_path, base: config.src_base.clone(), @@ -241,9 +242,11 @@ fn run_ui_cargo(config: &mut compiletest::Config) { let tests = compiletest::make_tests(&config); let current_dir = env::current_dir().unwrap(); + let conf_dir = var("CLIPPY_CONF_DIR").unwrap_or_default(); let filter = env::var("TESTNAME").ok(); let res = run_tests(&config, &filter, tests); env::set_current_dir(current_dir).unwrap(); + set_var("CLIPPY_CONF_DIR", conf_dir); match res { Ok(true) => {}, From 3c8f7542f74316ec54657c02e78b9f653f4fe2ae Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sat, 6 Feb 2021 18:21:03 +0100 Subject: [PATCH 46/72] Fux `toml_unknown_key` test. --- tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 7b3c476461d50..7ccd0b54845d1 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `cargo-ignore-publish`, `third-party` at line 5 column 1 error: aborting due to previous error From ea0b8324d6457c4a380a6c30e41414f863ff7897 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sat, 6 Feb 2021 18:24:08 +0100 Subject: [PATCH 47/72] Document condition. --- clippy_lints/src/cargo_common_metadata.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index f499345636c8b..12cbaea26cd32 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -93,6 +93,7 @@ impl LateLintPass<'_> for CargoCommonMetadata { let metadata = unwrap_cargo_metadata!(cx, CARGO_COMMON_METADATA, false); for package in metadata.packages { + // we want to skip the lint if publish is `None` (`publish = false`) or if the vector is empty (`publish = []`) if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || self.ignore_publish { if is_empty_vec(&package.authors) { missing_warning(cx, &package, "package.authors"); From fd8b5fa1aa614dcfd21471ab5a9a56c7873ce14a Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sat, 6 Feb 2021 18:29:07 +0100 Subject: [PATCH 48/72] Confused about my own explanation. --- clippy_lints/src/cargo_common_metadata.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index 12cbaea26cd32..cc2869ab495c8 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -93,7 +93,8 @@ impl LateLintPass<'_> for CargoCommonMetadata { let metadata = unwrap_cargo_metadata!(cx, CARGO_COMMON_METADATA, false); for package in metadata.packages { - // we want to skip the lint if publish is `None` (`publish = false`) or if the vector is empty (`publish = []`) + // only run the lint if publish is `None` (`publish = true` or skipped entirely) + // or if the vector isn't empty (`publish = ["something"]`) if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || self.ignore_publish { if is_empty_vec(&package.authors) { missing_warning(cx, &package, "package.authors"); From 2bffbfccc1a8e6deba27e6b8753428d999fb0c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 6 Feb 2021 19:12:28 +0100 Subject: [PATCH 49/72] lintcheck: avoid dbg!() calls --- clippy_dev/src/lintcheck.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/clippy_dev/src/lintcheck.rs b/clippy_dev/src/lintcheck.rs index 35c2659952c42..d73405c933730 100644 --- a/clippy_dev/src/lintcheck.rs +++ b/clippy_dev/src/lintcheck.rs @@ -165,14 +165,15 @@ impl Crate { .current_dir(&self.path) .output() .unwrap_or_else(|error| { - dbg!(error); - dbg!(&cargo_clippy_path); - dbg!(&self.path); - panic!("something was not found?") + panic!( + "Encountered error:\n{:?}\ncargo_clippy_path: {}\ncrate path:{}\n", + error, + &cargo_clippy_path.display(), + &self.path.display() + ); }); let stdout = String::from_utf8_lossy(&all_output.stdout); let output_lines = stdout.lines(); - //dbg!(&output_lines); let warnings: Vec = output_lines .into_iter() // get all clippy warnings @@ -229,7 +230,7 @@ fn read_crates() -> Vec { if tk.versions.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some()) || tk.git_hash.is_some() != tk.git_url.is_some() { - dbg!(&tk); + eprintln!("tomlkrate: {:?}", tk); if tk.git_hash.is_some() != tk.git_url.is_some() { panic!("Encountered TomlCrate with only one of git_hash and git_url!") } From 0585c347401dce1e50cd742465b5cce9532d7e76 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 6 Feb 2021 10:38:27 -0800 Subject: [PATCH 50/72] Stabilize workspace wrapper. --- src/main.rs | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/main.rs b/src/main.rs index ea06743394d10..12bb909e15afb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,7 +59,6 @@ pub fn main() { } struct ClippyCmd { - unstable_options: bool, cargo_subcommand: &'static str, args: Vec, clippy_args: Vec, @@ -105,21 +104,12 @@ impl ClippyCmd { } ClippyCmd { - unstable_options, cargo_subcommand, args, clippy_args, } } - fn path_env(&self) -> &'static str { - if self.unstable_options { - "RUSTC_WORKSPACE_WRAPPER" - } else { - "RUSTC_WRAPPER" - } - } - fn path() -> PathBuf { let mut path = env::current_exe() .expect("current executable path invalid") @@ -156,7 +146,7 @@ impl ClippyCmd { .map(|arg| format!("{}__CLIPPY_HACKERY__", arg)) .collect(); - cmd.env(self.path_env(), Self::path()) + cmd.env("RUSTC_WORKSPACE_WRAPPER", Self::path()) .envs(ClippyCmd::target_dir()) .env("CLIPPY_ARGS", clippy_args) .arg(self.cargo_subcommand) @@ -205,7 +195,6 @@ mod tests { .map(ToString::to_string); let cmd = ClippyCmd::new(args); assert_eq!("fix", cmd.cargo_subcommand); - assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); assert!(cmd.args.iter().any(|arg| arg.ends_with("unstable-options"))); } @@ -232,16 +221,5 @@ mod tests { let args = "cargo clippy".split_whitespace().map(ToString::to_string); let cmd = ClippyCmd::new(args); assert_eq!("check", cmd.cargo_subcommand); - assert_eq!("RUSTC_WRAPPER", cmd.path_env()); - } - - #[test] - fn check_unstable() { - let args = "cargo clippy -Zunstable-options" - .split_whitespace() - .map(ToString::to_string); - let cmd = ClippyCmd::new(args); - assert_eq!("check", cmd.cargo_subcommand); - assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); } } From 6b4789d7cf8d4165398985ff89dfdbaa5548d39a Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Sat, 6 Feb 2021 20:05:51 +0100 Subject: [PATCH 51/72] Fixed suggestion in macro invocations --- clippy_lints/src/semicolon_if_nothing_returned.rs | 4 ++-- tests/ui/semicolon_if_nothing_returned.stderr | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 6133e86a26a27..839c995e52562 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -49,12 +49,12 @@ impl LateLintPass<'_> for SemicolonIfNothingReturned { return; } - let sugg = sugg::Sugg::hir(cx, &expr, ".."); + let sugg = sugg::Sugg::hir_with_macro_callsite(cx, &expr, ".."); let suggestion = format!("{0};", sugg); span_lint_and_sugg( cx, SEMICOLON_IF_NOTHING_RETURNED, - expr.span, + expr.span.source_callsite(), "consider adding a `;` to the last statement for consistent formatting", "add a `;` here", suggestion, diff --git a/tests/ui/semicolon_if_nothing_returned.stderr b/tests/ui/semicolon_if_nothing_returned.stderr index 56211ff7f773c..b73f89675383f 100644 --- a/tests/ui/semicolon_if_nothing_returned.stderr +++ b/tests/ui/semicolon_if_nothing_returned.stderr @@ -2,10 +2,9 @@ error: consider adding a `;` to the last statement for consistent formatting --> $DIR/semicolon_if_nothing_returned.rs:8:5 | LL | println!("Hello") - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ help: add a `;` here: `println!("Hello");` | = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: consider adding a `;` to the last statement for consistent formatting --> $DIR/semicolon_if_nothing_returned.rs:12:5 From 40ce05654be9f4f6fb80e295f3eb05bee211cfc7 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 5 Feb 2021 14:55:09 -0600 Subject: [PATCH 52/72] Eat dogfood --- clippy_dev/src/serve.rs | 2 +- clippy_lints/src/macro_use.rs | 2 +- src/main.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_dev/src/serve.rs b/clippy_dev/src/serve.rs index faa94859601e3..d13c27a1957d6 100644 --- a/clippy_dev/src/serve.rs +++ b/clippy_dev/src/serve.rs @@ -34,7 +34,7 @@ pub fn run(port: u16, lint: Option<&str>) -> ! { // Give some time for python to start thread::sleep(Duration::from_millis(500)); // Launch browser after first export.py has completed and http.server is up - let _ = opener::open(url); + let _result = opener::open(url); }); } thread::sleep(Duration::from_millis(1000)); diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index bb52888883af5..40f04bd677d52 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -160,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { let found_idx = self.mac_refs.iter().position(|mac| import.ends_with(&mac.name)); if let Some(idx) = found_idx { - let _ = self.mac_refs.remove(idx); + self.mac_refs.remove(idx); let seg = import.split("::").collect::>(); match seg.as_slice() { diff --git a/src/main.rs b/src/main.rs index ea06743394d10..b4423ce9ec7dc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -195,7 +195,7 @@ mod tests { #[should_panic] fn fix_without_unstable() { let args = "cargo clippy --fix".split_whitespace().map(ToString::to_string); - let _ = ClippyCmd::new(args); + ClippyCmd::new(args); } #[test] From dfe08f4e48861ef0dad88ca6a28a512f7f2eab87 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sat, 6 Feb 2021 23:56:08 +0100 Subject: [PATCH 53/72] Update triagebot.toml to new label names --- triagebot.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index b9549be3a8b63..e56c447c674dc 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,7 +1,7 @@ [relabel] allow-unauthenticated = [ - "A-*", "C-*", "E-*", "L-*", "M-*", "O-*", "P-*", "S-*", "T-*", - "good-first-issue" + "A-*", "C-*", "E-*", "I-*", "L-*", "P-*", "S-*", "T-*", + "good first issue" ] [assign] From 6f3eeac83c801434bd36e2435c9fafab8af5576c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 7 Feb 2021 16:12:21 +0100 Subject: [PATCH 54/72] lintcheck: add a cmdline option --crates-toml to override crate sources file to use. Fixes #6691 --- clippy_dev/src/lintcheck.rs | 6 +++--- clippy_dev/src/main.rs | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/clippy_dev/src/lintcheck.rs b/clippy_dev/src/lintcheck.rs index d73405c933730..3fc7dcb7d4b8b 100644 --- a/clippy_dev/src/lintcheck.rs +++ b/clippy_dev/src/lintcheck.rs @@ -192,8 +192,8 @@ fn build_clippy() { } // get a list of CrateSources we want to check from a "lintcheck_crates.toml" file. -fn read_crates() -> Vec { - let toml_path = PathBuf::from("clippy_dev/lintcheck_crates.toml"); +fn read_crates(toml_path: Option<&str>) -> Vec { + let toml_path = PathBuf::from(toml_path.unwrap_or("clippy_dev/lintcheck_crates.toml")); let toml_content: String = std::fs::read_to_string(&toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display())); let crate_list: CrateList = @@ -288,7 +288,7 @@ pub fn run(clap_config: &ArgMatches) { // download and extract the crates, then run clippy on them and collect clippys warnings // flatten into one big list of warnings - let crates = read_crates(); + let crates = read_crates(clap_config.value_of("crates-toml")); let clippy_warnings: Vec = if let Some(only_one_crate) = clap_config.value_of("only") { // if we don't have the specified crate in the .toml, throw an error diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index e7a298a37e17a..5dbd46935a59a 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -62,6 +62,13 @@ fn get_clap_config<'a>() -> ArgMatches<'a> { .value_name("CRATE") .long("only") .help("only process a single crate of the list"), + ) + .arg( + Arg::with_name("crates-toml") + .takes_value(true) + .value_name("CRATES-SOURCES-TOML-PATH") + .long("crates-toml") + .help("set the path for a crates.toml where lintcheck should read the sources from"), ); let app = App::new("Clippy developer tooling") From 1c3033d5cf903d19d8f3dcdfc01ba1dc55debf71 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 8 Feb 2021 01:34:59 +0900 Subject: [PATCH 55/72] add a new lint `bytes_nth` --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 +++ clippy_lints/src/methods/bytes_nth.rs | 39 +++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 25 +++++++++++++++++ tests/ui/bytes_nth.fixed | 9 +++++++ tests/ui/bytes_nth.rs | 9 +++++++ tests/ui/bytes_nth.stderr | 16 +++++++++++ 7 files changed, 102 insertions(+) create mode 100644 clippy_lints/src/methods/bytes_nth.rs create mode 100644 tests/ui/bytes_nth.fixed create mode 100644 tests/ui/bytes_nth.rs create mode 100644 tests/ui/bytes_nth.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index b74841c779405..7c79fe88816f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1877,6 +1877,7 @@ Released 2018-09-13 [`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local [`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow +[`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth [`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata [`case_sensitive_file_extension_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#case_sensitive_file_extension_comparisons [`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fe4aa584b1878..22d91c9d40d37 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -734,6 +734,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &mem_replace::MEM_REPLACE_WITH_DEFAULT, &mem_replace::MEM_REPLACE_WITH_UNINIT, &methods::BIND_INSTEAD_OF_MAP, + &methods::BYTES_NTH, &methods::CHARS_LAST_CMP, &methods::CHARS_NEXT_CMP, &methods::CLONE_DOUBLE_REF, @@ -1531,6 +1532,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(&methods::BIND_INSTEAD_OF_MAP), + LintId::of(&methods::BYTES_NTH), LintId::of(&methods::CHARS_LAST_CMP), LintId::of(&methods::CHARS_NEXT_CMP), LintId::of(&methods::CLONE_DOUBLE_REF), @@ -1749,6 +1751,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::SINGLE_MATCH), LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), + LintId::of(&methods::BYTES_NTH), LintId::of(&methods::CHARS_LAST_CMP), LintId::of(&methods::CHARS_NEXT_CMP), LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT), diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs new file mode 100644 index 0000000000000..4f38db06c0a37 --- /dev/null +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -0,0 +1,39 @@ +use crate::utils::{is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::BYTES_NTH; + +pub(super) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>]) { + if_chain! { + if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind; + let ty = cx.typeck_results().expr_ty(&iter_args[0]).peel_refs(); + let caller_type = if is_type_diagnostic_item(cx, ty, sym::string_type) { + Some("String") + } else if ty.is_str() { + Some("str") + } else { + None + }; + if let Some(caller_type) = caller_type; + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + BYTES_NTH, + expr.span, + &format!("called `.byte().nth()` on a `{}`", caller_type), + "try calling `.as_bytes().get()`", + format!( + "{}.as_bytes().get({})", + snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability), + snippet_with_applicability(cx, args[1].span, "..", &mut applicability) + ), + applicability, + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3e34fc1aed169..4cb3a85851150 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,4 +1,5 @@ mod bind_instead_of_map; +mod bytes_nth; mod filter_map_identity; mod inefficient_to_string; mod inspect_for_each; @@ -1490,6 +1491,28 @@ declare_clippy_lint! { "call to `filter_map` where `flatten` is sufficient" } +declare_clippy_lint! { + /// **What it does:** Checks for the use of `.bytes().nth()`. + /// + /// **Why is this bad?** `.as_bytes().get()` is more efficient and more + /// readable. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // Bad + /// let _ = "Hello".bytes().nth(3);; + /// + /// // Good + /// let _ = "Hello".as_bytes().get(3); + /// ``` + pub BYTES_NTH, + style, + "replace `.bytes().nth()` with `.as_bytes().get()`" +} + pub struct Methods { msrv: Option, } @@ -1537,6 +1560,7 @@ impl_lint_pass!(Methods => [ ITER_NEXT_SLICE, ITER_NTH, ITER_NTH_ZERO, + BYTES_NTH, ITER_SKIP_NEXT, GET_UNWRAP, STRING_EXTEND_CHARS, @@ -1614,6 +1638,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["extend", ..] => lint_extend(cx, expr, arg_lists[0]), ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true), + ["nth", "bytes"] => bytes_nth::lints(cx, expr, &arg_lists[1]), ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]), ["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]), ["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]), diff --git a/tests/ui/bytes_nth.fixed b/tests/ui/bytes_nth.fixed new file mode 100644 index 0000000000000..36bf8660a34c0 --- /dev/null +++ b/tests/ui/bytes_nth.fixed @@ -0,0 +1,9 @@ +// run-rustfix + +#![warn(clippy::bytes_nth)] + +fn main() { + let _ = "Hello".as_bytes().get(3); + + let _ = String::from("Hello").as_bytes().get(3); +} diff --git a/tests/ui/bytes_nth.rs b/tests/ui/bytes_nth.rs new file mode 100644 index 0000000000000..257344c2d3295 --- /dev/null +++ b/tests/ui/bytes_nth.rs @@ -0,0 +1,9 @@ +// run-rustfix + +#![warn(clippy::bytes_nth)] + +fn main() { + let _ = "Hello".bytes().nth(3); + + let _ = String::from("Hello").bytes().nth(3); +} diff --git a/tests/ui/bytes_nth.stderr b/tests/ui/bytes_nth.stderr new file mode 100644 index 0000000000000..b46a0736414b0 --- /dev/null +++ b/tests/ui/bytes_nth.stderr @@ -0,0 +1,16 @@ +error: called `.byte().nth()` on a `str` + --> $DIR/bytes_nth.rs:6:13 + | +LL | let _ = "Hello".bytes().nth(3); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try calling `.as_bytes().get()`: `"Hello".as_bytes().get(3)` + | + = note: `-D clippy::bytes-nth` implied by `-D warnings` + +error: called `.byte().nth()` on a `String` + --> $DIR/bytes_nth.rs:8:13 + | +LL | let _ = String::from("Hello").bytes().nth(3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try calling `.as_bytes().get()`: `String::from("Hello").as_bytes().get(3)` + +error: aborting due to 2 previous errors + From fd35517bd47372a4c9bbd436f3d6885cdc452e7f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 7 Feb 2021 16:54:09 -0800 Subject: [PATCH 56/72] Downgrade trivial_regex to nursery --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/regex.rs | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fe4aa584b1878..6e693ccd75ceb 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1628,7 +1628,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), LintId::of(®ex::INVALID_REGEX), - LintId::of(®ex::TRIVIAL_REGEX), LintId::of(&repeat_once::REPEAT_ONCE), LintId::of(&returns::LET_AND_RETURN), LintId::of(&returns::NEEDLESS_RETURN), @@ -1791,7 +1790,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ranges::MANUAL_RANGE_CONTAINS), LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), - LintId::of(®ex::TRIVIAL_REGEX), LintId::of(&returns::LET_AND_RETURN), LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), @@ -2021,6 +2019,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&needless_borrow::NEEDLESS_BORROW), LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE), + LintId::of(®ex::TRIVIAL_REGEX), LintId::of(&strings::STRING_LIT_AS_BYTES), LintId::of(&transmute::USELESS_TRANSMUTE), LintId::of(&use_self::USE_SELF), diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index d06ab14348237..1edea61314893 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -35,14 +35,16 @@ declare_clippy_lint! { /// `str::starts_with`, `str::ends_with` or `std::contains` or other `str` /// methods. /// - /// **Known problems:** None. + /// **Known problems:** If the same regex is going to be applied to multiple + /// inputs, the precomputations done by `Regex` construction can give + /// significantly better performance than any of the `str`-based methods. /// /// **Example:** /// ```ignore /// Regex::new("^foobar") /// ``` pub TRIVIAL_REGEX, - style, + nursery, "trivial regular expressions" } From 1d3042294503e6027759baadc92056403aa8c991 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Wed, 3 Feb 2021 11:35:16 -0600 Subject: [PATCH 57/72] Enhance LocalUsedVisitor to check closure bodies --- clippy_lints/src/collapsible_match.rs | 9 ++++----- clippy_lints/src/let_if_seq.rs | 17 +++++++++++------ clippy_lints/src/loops.rs | 10 +++++----- clippy_lints/src/matches.rs | 6 ++++-- clippy_lints/src/utils/visitors.rs | 21 +++++++++++++-------- tests/ui/collapsible_match.rs | 8 ++++++++ 6 files changed, 45 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/collapsible_match.rs index 834f294283e37..75a973fe37eb3 100644 --- a/clippy_lints/src/collapsible_match.rs +++ b/clippy_lints/src/collapsible_match.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleMatch { } } -fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) { +fn check_arm<'tcx>(arm: &Arm<'tcx>, wild_outer_arm: &Arm<'tcx>, cx: &LateContext<'tcx>) { if_chain! { let expr = strip_singleton_blocks(arm.body); if let ExprKind::Match(expr_in, arms_inner, _) = expr.kind; @@ -84,14 +84,13 @@ fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) { // the "wild-like" branches must be equal if SpanlessEq::new(cx).eq_expr(wild_inner_arm.body, wild_outer_arm.body); // the binding must not be used in the if guard + let mut used_visitor = LocalUsedVisitor::new(cx, binding_id); if match arm.guard { None => true, - Some(Guard::If(expr) | Guard::IfLet(_, expr)) => { - !LocalUsedVisitor::new(binding_id).check_expr(expr) - } + Some(Guard::If(expr) | Guard::IfLet(_, expr)) => !used_visitor.check_expr(expr), }; // ...or anywhere in the inner match - if !arms_inner.iter().any(|arm| LocalUsedVisitor::new(binding_id).check_arm(arm)); + if !arms_inner.iter().any(|arm| used_visitor.check_arm(arm)); then { span_lint_and_then( cx, diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 6beaa51729a02..5863eef8a26f8 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -63,10 +63,11 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind; if let hir::StmtKind::Expr(ref if_) = expr.kind; if let hir::ExprKind::If(ref cond, ref then, ref else_) = if_.kind; - if !LocalUsedVisitor::new(canonical_id).check_expr(cond); + let mut used_visitor = LocalUsedVisitor::new(cx, canonical_id); + if !used_visitor.check_expr(cond); if let hir::ExprKind::Block(ref then, _) = then.kind; - if let Some(value) = check_assign(canonical_id, &*then); - if !LocalUsedVisitor::new(canonical_id).check_expr(value); + if let Some(value) = check_assign(cx, canonical_id, &*then); + if !used_visitor.check_expr(value); then { let span = stmt.span.to(if_.span); @@ -78,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { let (default_multi_stmts, default) = if let Some(ref else_) = *else_ { if let hir::ExprKind::Block(ref else_, _) = else_.kind { - if let Some(default) = check_assign(canonical_id, else_) { + if let Some(default) = check_assign(cx, canonical_id, else_) { (else_.stmts.len() > 1, default) } else if let Some(ref default) = local.init { (true, &**default) @@ -133,7 +134,11 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { } } -fn check_assign<'tcx>(decl: hir::HirId, block: &'tcx hir::Block<'_>) -> Option<&'tcx hir::Expr<'tcx>> { +fn check_assign<'tcx>( + cx: &LateContext<'tcx>, + decl: hir::HirId, + block: &'tcx hir::Block<'_>, +) -> Option<&'tcx hir::Expr<'tcx>> { if_chain! { if block.expr.is_none(); if let Some(expr) = block.stmts.iter().last(); @@ -141,7 +146,7 @@ fn check_assign<'tcx>(decl: hir::HirId, block: &'tcx hir::Block<'_>) -> Option<& if let hir::ExprKind::Assign(ref var, ref value, _) = expr.kind; if path_to_local_id(var, decl); then { - let mut v = LocalUsedVisitor::new(decl); + let mut v = LocalUsedVisitor::new(cx, decl); if block.stmts.iter().take(block.stmts.len()-1).any(|stmt| v.check_stmt(stmt)) { return None; diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index b5a9632ee1986..eb185377e2094 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1893,8 +1893,8 @@ fn check_for_loop_over_map_kv<'tcx>( let arg_span = arg.span; let (new_pat_span, kind, ty, mutbl) = match *cx.typeck_results().expr_ty(arg).kind() { ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) { - (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", ty, mutbl), - (_, value) if pat_is_wild(value, body) => (pat[0].span, "key", ty, Mutability::Not), + (key, _) if pat_is_wild(cx, key, body) => (pat[1].span, "value", ty, mutbl), + (_, value) if pat_is_wild(cx, value, body) => (pat[0].span, "key", ty, Mutability::Not), _ => return, }, _ => return, @@ -2145,11 +2145,11 @@ fn check_for_mutation<'tcx>( } /// Returns `true` if the pattern is a `PatWild` or an ident prefixed with `_`. -fn pat_is_wild<'tcx>(pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { +fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { match *pat { PatKind::Wild => true, PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => { - !LocalUsedVisitor::new(id).check_expr(body) + !LocalUsedVisitor::new(cx, id).check_expr(body) }, _ => false, } @@ -2188,7 +2188,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { then { let index_used_directly = path_to_local_id(idx, self.var); let indexed_indirectly = { - let mut used_visitor = LocalUsedVisitor::new(self.var); + let mut used_visitor = LocalUsedVisitor::new(self.cx, self.var); walk_expr(&mut used_visitor, idx); used_visitor.used }; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index c4aa2b30e7b52..e33001b16bcde 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -911,7 +911,7 @@ fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms } } -fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { +fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) { let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs(); if is_type_diagnostic_item(cx, ex_ty, sym::result_type) { for arm in arms { @@ -924,7 +924,9 @@ fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { // Looking for unused bindings (i.e.: `_e`) inner.iter().for_each(|pat| { if let PatKind::Binding(_, id, ident, None) = pat.kind { - if ident.as_str().starts_with('_') && !LocalUsedVisitor::new(id).check_expr(arm.body) { + if ident.as_str().starts_with('_') + && !LocalUsedVisitor::new(cx, id).check_expr(arm.body) + { ident_bind_name = (&ident.name.as_str()).to_string(); matching_wild = true; } diff --git a/clippy_lints/src/utils/visitors.rs b/clippy_lints/src/utils/visitors.rs index a4064c3e705cd..24409346ca687 100644 --- a/clippy_lints/src/utils/visitors.rs +++ b/clippy_lints/src/utils/visitors.rs @@ -133,14 +133,16 @@ where } } -pub struct LocalUsedVisitor { +pub struct LocalUsedVisitor<'hir> { + hir: Map<'hir>, pub local_hir_id: HirId, pub used: bool, } -impl LocalUsedVisitor { - pub fn new(local_hir_id: HirId) -> Self { +impl<'hir> LocalUsedVisitor<'hir> { + pub fn new(cx: &LateContext<'hir>, local_hir_id: HirId) -> Self { Self { + hir: cx.tcx.hir(), local_hir_id, used: false, } @@ -151,23 +153,26 @@ impl LocalUsedVisitor { std::mem::replace(&mut self.used, false) } - pub fn check_arm(&mut self, arm: &Arm<'_>) -> bool { + pub fn check_arm(&mut self, arm: &'hir Arm<'_>) -> bool { self.check(arm, Self::visit_arm) } - pub fn check_expr(&mut self, expr: &Expr<'_>) -> bool { + pub fn check_expr(&mut self, expr: &'hir Expr<'_>) -> bool { self.check(expr, Self::visit_expr) } - pub fn check_stmt(&mut self, stmt: &Stmt<'_>) -> bool { + pub fn check_stmt(&mut self, stmt: &'hir Stmt<'_>) -> bool { self.check(stmt, Self::visit_stmt) } } -impl<'v> Visitor<'v> for LocalUsedVisitor { +impl<'v> Visitor<'v> for LocalUsedVisitor<'v> { type Map = Map<'v>; fn visit_expr(&mut self, expr: &'v Expr<'v>) { + if self.used { + return; + } if path_to_local_id(expr, self.local_hir_id) { self.used = true; } else { @@ -176,6 +181,6 @@ impl<'v> Visitor<'v> for LocalUsedVisitor { } fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None + NestedVisitorMap::OnlyBodies(self.hir) } } diff --git a/tests/ui/collapsible_match.rs b/tests/ui/collapsible_match.rs index a83e6c77b12e5..3294da7e8146f 100644 --- a/tests/ui/collapsible_match.rs +++ b/tests/ui/collapsible_match.rs @@ -224,6 +224,14 @@ fn negative_cases(res_opt: Result, String>, res_res: Result return, } + if let Ok(val) = res_opt { + if let Some(n) = val { + let _ = || { + // usage in closure + println!("{:?}", val); + }; + } + } } fn make() -> T { From 5db48a382a928969be301ee416df27f6508105c2 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Wed, 3 Feb 2021 11:45:16 -0600 Subject: [PATCH 58/72] Refactor out UnusedSelfVisitor --- clippy_lints/src/unused_self.rs | 39 +++--------------------------- clippy_lints/src/utils/visitors.rs | 6 ++++- 2 files changed, 8 insertions(+), 37 deletions(-) diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 5349c4f7eb8a7..9d61bd0cc2fe9 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -1,12 +1,10 @@ use if_chain::if_chain; -use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_path, NestedVisitorMap, Visitor}; -use rustc_hir::{HirId, Impl, ImplItem, ImplItemKind, ItemKind, Path}; +use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::span_lint_and_help; +use crate::utils::visitors::LocalUsedVisitor; declare_clippy_lint! { /// **What it does:** Checks methods that contain a `self` argument but don't use it @@ -57,13 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { then { let self_param = &body.params[0]; let self_hir_id = self_param.pat.hir_id; - let mut visitor = UnusedSelfVisitor { - cx, - uses_self: false, - self_hir_id: &self_hir_id, - }; - visitor.visit_body(body); - if !visitor.uses_self { + if !LocalUsedVisitor::new(cx, self_hir_id).check_body(body) { span_lint_and_help( cx, UNUSED_SELF, @@ -78,28 +70,3 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { } } } - -struct UnusedSelfVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - uses_self: bool, - self_hir_id: &'a HirId, -} - -impl<'a, 'tcx> Visitor<'tcx> for UnusedSelfVisitor<'a, 'tcx> { - type Map = Map<'tcx>; - - fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) { - if self.uses_self { - // This function already uses `self` - return; - } - if let Res::Local(hir_id) = &path.res { - self.uses_self = self.self_hir_id == hir_id - } - walk_path(self, path); - } - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) - } -} diff --git a/clippy_lints/src/utils/visitors.rs b/clippy_lints/src/utils/visitors.rs index 24409346ca687..085c1f9c0cb8d 100644 --- a/clippy_lints/src/utils/visitors.rs +++ b/clippy_lints/src/utils/visitors.rs @@ -1,7 +1,7 @@ use crate::utils::path_to_local_id; use rustc_hir as hir; use rustc_hir::intravisit::{self, walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{Arm, Expr, HirId, Stmt}; +use rustc_hir::{Arm, Body, Expr, HirId, Stmt}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; @@ -157,6 +157,10 @@ impl<'hir> LocalUsedVisitor<'hir> { self.check(arm, Self::visit_arm) } + pub fn check_body(&mut self, body: &'hir Body<'_>) -> bool { + self.check(body, Self::visit_body) + } + pub fn check_expr(&mut self, expr: &'hir Expr<'_>) -> bool { self.check(expr, Self::visit_expr) } From 37555f8f73baf82b7761db56e7440c79a956b9ec Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 8 Feb 2021 09:50:13 -0600 Subject: [PATCH 59/72] Use path_to_local_id --- clippy_lints/src/methods/filter_map_identity.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index d04e4be87ac29..9e646360a40c3 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_qpath, match_trait_method, paths, span_lint_and_sugg}; +use crate::utils::{match_qpath, match_trait_method, path_to_local_id, paths, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -32,12 +32,8 @@ pub(super) fn check( if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node; let body = cx.tcx.hir().body(*body_id); - if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind; - if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.kind; - - if path.segments.len() == 1; - if path.segments[0].ident.name == binding_ident.name; - + if let hir::PatKind::Binding(_, binding_id, ..) = body.params[0].pat.kind; + if path_to_local_id(&body.value, binding_id); then { apply_lint("called `filter_map(|x| x)` on an `Iterator`"); } From 34b373d309e05dec9d7409bc2481668778ebc600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Tue, 9 Feb 2021 11:15:53 +0300 Subject: [PATCH 60/72] Rename HIR UnOp variants This renames the variants in HIR UnOp from enum UnOp { UnDeref, UnNot, UnNeg, } to enum UnOp { Deref, Not, Neg, } Motivations: - This is more consistent with the rest of the code base where most enum variants don't have a prefix. - These variants are never used without the `UnOp` prefix so the extra `Un` prefix doesn't help with readability. E.g. we don't have any `UnDeref`s in the code, we only have `UnOp::UnDeref`. - MIR `UnOp` type variants don't have a prefix so this is more consistent with MIR types. - "un" prefix reads like "inverse" or "reverse", so as a beginner in rustc code base when I see "UnDeref" what comes to my mind is something like "&*" instead of just "*". --- clippy_lints/src/arithmetic.rs | 4 ++-- clippy_lints/src/assertions_on_constants.rs | 2 +- clippy_lints/src/booleans.rs | 6 +++--- clippy_lints/src/bytecount.rs | 2 +- clippy_lints/src/collapsible_match.rs | 2 +- clippy_lints/src/consts.rs | 6 +++--- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 6 +++--- clippy_lints/src/functions.rs | 2 +- clippy_lints/src/map_clone.rs | 2 +- .../src/methods/manual_saturating_arithmetic.rs | 4 ++-- clippy_lints/src/methods/mod.rs | 10 +++++----- clippy_lints/src/misc.rs | 4 ++-- clippy_lints/src/needless_bool.rs | 2 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 2 +- clippy_lints/src/neg_multiply.rs | 4 ++-- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 2 +- clippy_lints/src/shadow.rs | 2 +- clippy_lints/src/suspicious_trait_impl.rs | 2 +- clippy_lints/src/transmute.rs | 2 +- clippy_lints/src/types.rs | 6 +++--- clippy_lints/src/unwrap.rs | 2 +- clippy_lints/src/utils/higher.rs | 2 +- clippy_lints/src/utils/internal_lints.rs | 2 +- tests/ui/suspicious_arithmetic_impl.rs | 4 ++-- 26 files changed, 43 insertions(+), 43 deletions(-) diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index 9861d8cfc4e5f..61fdf9495b918 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for Arithmetic { match op.node { hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind { hir::ExprKind::Lit(_lit) => (), - hir::ExprKind::Unary(hir::UnOp::UnNeg, expr) => { + hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { if let hir::ExprKind::Lit(lit) = &expr.kind { if let rustc_ast::ast::LitKind::Int(1, _) = lit.node { span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); @@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for Arithmetic { self.expr_span = Some(expr.span); } }, - hir::ExprKind::Unary(hir::UnOp::UnNeg, arg) => { + hir::ExprKind::Unary(hir::UnOp::Neg, arg) => { let ty = cx.typeck_results().expr_ty(arg); if constant_simple(cx, cx.typeck_results(), expr).is_none() { if ty.is_integral() { diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index aa431f0596cca..77b26faaa586a 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -112,7 +112,7 @@ enum AssertKind { fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { if_chain! { if let ExprKind::If(ref cond, ref then, _) = expr.kind; - if let ExprKind::Unary(UnOp::UnNot, ref expr) = cond.kind; + if let ExprKind::Unary(UnOp::Not, ref expr) = cond.kind; // bind the first argument of the `assert!` macro if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr); // block diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 90bb0bd555f27..0713303ec4b67 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -110,7 +110,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { // prevent folding of `cfg!` macros and the like if !e.span.from_expansion() { match &e.kind { - ExprKind::Unary(UnOp::UnNot, inner) => return Ok(Bool::Not(box self.run(inner)?)), + ExprKind::Unary(UnOp::Not, inner) => return Ok(Bool::Not(box self.run(inner)?)), ExprKind::Binary(binop, lhs, rhs) => match &binop.node { BinOpKind::Or => { return Ok(Bool::Or(self.extract(BinOpKind::Or, &[lhs, rhs], Vec::new())?)); @@ -454,7 +454,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => { self.bool_expr(e) }, - ExprKind::Unary(UnOp::UnNot, inner) => { + ExprKind::Unary(UnOp::Not, inner) => { if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() { self.bool_expr(e); } else { @@ -482,7 +482,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if let ExprKind::Unary(UnOp::UnNot, inner) = &expr.kind { + if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind { if let Some(suggestion) = simplify_not(self.cx, inner) { span_lint_and_sugg( self.cx, diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index ac9098a7584d6..b8828719f627c 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -101,7 +101,7 @@ fn check_arg(name: Symbol, arg: Symbol, needle: &Expr<'_>) -> bool { fn get_path_name(expr: &Expr<'_>) -> Option { match expr.kind { - ExprKind::Box(ref e) | ExprKind::AddrOf(BorrowKind::Ref, _, ref e) | ExprKind::Unary(UnOp::UnDeref, ref e) => { + ExprKind::Box(ref e) | ExprKind::AddrOf(BorrowKind::Ref, _, ref e) | ExprKind::Unary(UnOp::Deref, ref e) => { get_path_name(e) }, ExprKind::Block(ref b, _) => { diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/collapsible_match.rs index 604ba10204697..b83aae0e5719c 100644 --- a/clippy_lints/src/collapsible_match.rs +++ b/clippy_lints/src/collapsible_match.rs @@ -186,7 +186,7 @@ fn addr_adjusted_binding(mut expr: &Expr<'_>, cx: &LateContext<'_>) -> Option break Some(binding_id), _ => break None, }, - ExprKind::Unary(UnOp::UnDeref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e, + ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e, _ => break None, } } diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 640cffd24a701..1b89d0bbe3862 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -242,9 +242,9 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { self.expr(value).map(|v| Constant::Repeat(Box::new(v), n)) }, ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op { - UnOp::UnNot => self.constant_not(&o, self.typeck_results.expr_ty(e)), - UnOp::UnNeg => self.constant_negate(&o, self.typeck_results.expr_ty(e)), - UnOp::UnDeref => Some(if let Constant::Ref(r) = o { *r } else { o }), + UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)), + UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)), + UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }), }), ExprKind::If(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, *otherwise), ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right), diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 37948e06869c3..6b9f9a5675481 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -55,7 +55,7 @@ declare_lint_pass!(HashMapPass => [MAP_ENTRY]); impl<'tcx> LateLintPass<'tcx> for HashMapPass { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::If(ref check, ref then_block, ref else_block) = expr.kind { - if let ExprKind::Unary(UnOp::UnNot, ref check) = check.kind { + if let ExprKind::Unary(UnOp::Not, ref check) = check.kind { if let Some((ty, map, key)) = check_cond(cx, check) { // in case of `if !m.contains_key(&k) { m.insert(k, v); }` // we can give a better error message diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index ffef78aac8067..086a791520fa8 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -129,7 +129,7 @@ fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>) -> Option<& fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Sugg<'a> { let mut suggestion = Sugg::hir(cx, expr, ".."); - if let ExprKind::Unary(UnOp::UnNeg, inner_expr) = &expr.kind { + if let ExprKind::Unary(UnOp::Neg, inner_expr) = &expr.kind { expr = &inner_expr; } @@ -541,12 +541,12 @@ fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// If the two expressions are not negations of each other, then it /// returns None. fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a>) -> Option<(bool, &'a Expr<'a>)> { - if let ExprKind::Unary(UnOp::UnNeg, expr1_negated) = &expr1.kind { + if let ExprKind::Unary(UnOp::Neg, expr1_negated) = &expr1.kind { if eq_expr_value(cx, expr1_negated, expr2) { return Some((false, expr2)); } } - if let ExprKind::Unary(UnOp::UnNeg, expr2_negated) = &expr2.kind { + if let ExprKind::Unary(UnOp::Neg, expr2_negated) = &expr2.kind { if eq_expr_value(cx, expr1, expr2_negated) { return Some((true, expr1)); } diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 8795425461033..71a146cc29805 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -644,7 +644,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { } } }, - hir::ExprKind::Unary(hir::UnOp::UnDeref, ref ptr) => self.check_arg(ptr), + hir::ExprKind::Unary(hir::UnOp::Deref, ref ptr) => self.check_arg(ptr), _ => (), } diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 1818836d5d5e8..bd0be88028904 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { }, hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => { match closure_expr.kind { - hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) => { + hir::ExprKind::Unary(hir::UnOp::Deref, ref inner) => { if ident_eq(name, inner) { if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { lint(cx, e.span, args[0].span, true); diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 44c974b9d9857..eaa604c2ae63e 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -148,7 +148,7 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option) -> Option { - if let hir::ExprKind::Unary(hir::UnOp::UnNeg, inner) = &expr.kind { + if let hir::ExprKind::Unary(hir::UnOp::Neg, inner) = &expr.kind { if let hir::ExprKind::Lit(..) = &inner.kind { return Some(Sign::Neg); } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4ee423b383b0f..0918843294d47 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2619,7 +2619,7 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: if_chain! { if needs_ref; if let Some(parent) = get_parent_expr(cx, expr); - if let hir::ExprKind::Unary(hir::UnOp::UnDeref, _) = parent.kind; + if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind; then { needs_ref = false; span = parent.span; @@ -3063,7 +3063,7 @@ fn lint_filter_map<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_f // in `filter(|x| ..)`, replace `*x` with `x` let a_path = if_chain! { if !is_filter_param_ref; - if let ExprKind::Unary(UnOp::UnDeref, expr_path) = a.kind; + if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; then { expr_path } else { a } }; // let the filter closure arg and the map closure arg be equal @@ -3708,8 +3708,8 @@ fn lint_option_as_ref_deref<'tcx>( }, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => { if_chain! { - if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner1) = inner.kind; - if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner2) = inner1.kind; + if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner1) = inner.kind; + if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner2) = inner1.kind; if let hir::ExprKind::Path(ref qpath) = inner2.kind; if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, inner2.hir_id); then { @@ -4065,7 +4065,7 @@ fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir if_chain! { if let Some(parent) = get_parent_expr(cx, expr); if let hir::ExprKind::Unary(op, _) = parent.kind; - if op == hir::UnOp::UnNot; + if op == hir::UnOp::Not; then { lint_unary = "!"; verb = "denies"; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 0512d74c7b1c8..2ef5c6aa2a4e2 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -502,7 +502,7 @@ fn is_allowed<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { // Return true if `expr` is the result of `signum()` invoked on a float value. fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { // The negation of a signum is still a signum - if let ExprKind::Unary(UnOp::UnNeg, ref child_expr) = expr.kind { + if let ExprKind::Unary(UnOp::Neg, ref child_expr) = expr.kind { return is_signum(cx, &child_expr); } @@ -586,7 +586,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: return; } - let other_gets_derefed = matches!(other.kind, ExprKind::Unary(UnOp::UnDeref, _)); + let other_gets_derefed = matches!(other.kind, ExprKind::Unary(UnOp::Deref, _)); let lint_span = if other_gets_derefed { expr.span.to(other.span) diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index d795f12645794..f283ff1715fb6 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -195,7 +195,7 @@ struct ExpressionInfoWithSpan { } fn is_unary_not(e: &Expr<'_>) -> (bool, Span) { - if let ExprKind::Unary(UnOp::UnNot, operand) = e.kind { + if let ExprKind::Unary(UnOp::Not, operand) = e.kind { return (true, operand.span); } (false, e.span) diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 4fb899125e8ad..ec0ad58ca9c3e 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -50,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { if_chain! { if !in_external_macro(cx.sess(), expr.span); - if let ExprKind::Unary(UnOp::UnNot, ref inner) = expr.kind; + if let ExprKind::Unary(UnOp::Not, ref inner) = expr.kind; if let ExprKind::Binary(ref op, ref left, _) = inner.kind; if let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node; diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index aa550510867f9..ef7cc65cfcf0a 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -32,8 +32,8 @@ impl<'tcx> LateLintPass<'tcx> for NegMultiply { if BinOpKind::Mul == op.node { match (&left.kind, &right.kind) { (&ExprKind::Unary(..), &ExprKind::Unary(..)) => {}, - (&ExprKind::Unary(UnOp::UnNeg, ref lit), _) => check_mul(cx, e.span, lit, right), - (_, &ExprKind::Unary(UnOp::UnNeg, ref lit)) => check_mul(cx, e.span, lit, left), + (&ExprKind::Unary(UnOp::Neg, ref lit), _) => check_mul(cx, e.span, lit, right), + (_, &ExprKind::Unary(UnOp::Neg, ref lit)) => check_mul(cx, e.span, lit, left), _ => {}, } } diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index f57d753631755..0b2262d849076 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -383,7 +383,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { needs_check_adjustment = false; break; }, - ExprKind::Unary(UnOp::UnDeref, _) => { + ExprKind::Unary(UnOp::Deref, _) => { // `*e` => desugared to `*Deref::deref(&e)`, // meaning `e` must be referenced. // no need to go further up since a method call is involved now. diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 7bdf975ffd446..9ef0d267b0b20 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -181,7 +181,7 @@ fn detect_option_if_let_else<'tcx>( }; let cond_expr = match &cond_expr.kind { // Pointer dereferencing happens automatically, so we can omit it in the suggestion - ExprKind::Unary(UnOp::UnDeref, expr) | ExprKind::AddrOf(_, _, expr) => expr, + ExprKind::Unary(UnOp::Deref, expr) | ExprKind::AddrOf(_, _, expr) => expr, _ => cond_expr, }; Some(OptionIfLetElseOccurence { diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index d5b1767e945b9..32f6bc74642ca 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -389,7 +389,7 @@ fn is_self_shadow(name: Symbol, expr: &Expr<'_>) -> bool { ExprKind::Block(ref block, _) => { block.stmts.is_empty() && block.expr.as_ref().map_or(false, |e| is_self_shadow(name, e)) }, - ExprKind::Unary(op, ref inner) => (UnOp::UnDeref == op) && is_self_shadow(name, inner), + ExprKind::Unary(op, ref inner) => (UnOp::Deref == op) && is_self_shadow(name, inner), ExprKind::Path(QPath::Resolved(_, ref path)) => path_eq_name(name, path), _ => false, } diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 3a688a7bbef32..0b7d08cb1645a 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -194,7 +194,7 @@ impl<'tcx> Visitor<'tcx> for BinaryExprVisitor { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { match expr.kind { hir::ExprKind::Binary(..) - | hir::ExprKind::Unary(hir::UnOp::UnNot | hir::UnOp::UnNeg, _) + | hir::ExprKind::Unary(hir::UnOp::Not | hir::UnOp::Neg, _) | hir::ExprKind::AssignOp(..) => self.nb_binops += 1, _ => {}, } diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index d977cea4da50b..dc938ed02383d 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -586,7 +586,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { let mut expr = &args[0]; let mut arg = sugg::Sugg::hir(cx, expr, ".."); - if let ExprKind::Unary(UnOp::UnNeg, inner_expr) = &expr.kind { + if let ExprKind::Unary(UnOp::Neg, inner_expr) = &expr.kind { expr = &inner_expr; } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 04c32ce9e8f2c..58af5b12c3735 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -1706,13 +1706,13 @@ impl<'tcx> LateLintPass<'tcx> for Casts { } fn is_unary_neg(expr: &Expr<'_>) -> bool { - matches!(expr.kind, ExprKind::Unary(UnOp::UnNeg, _)) + matches!(expr.kind, ExprKind::Unary(UnOp::Neg, _)) } fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> { match expr.kind { ExprKind::Lit(ref lit) => Some(lit), - ExprKind::Unary(UnOp::UnNeg, e) => { + ExprKind::Unary(UnOp::Neg, e) => { if let ExprKind::Lit(ref lit) = e.kind { Some(lit) } else { @@ -2868,7 +2868,7 @@ declare_lint_pass!(RefToMut => [CAST_REF_TO_MUT]); impl<'tcx> LateLintPass<'tcx> for RefToMut { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::Unary(UnOp::UnDeref, e) = &expr.kind; + if let ExprKind::Unary(UnOp::Deref, e) = &expr.kind; if let ExprKind::Cast(e, t) = &e.kind; if let TyKind::Ptr(MutTy { mutbl: Mutability::Mut, .. }) = t.kind; if let ExprKind::Cast(e, t) = &e.kind; diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index b82909eaea604..2fb0463c5a6c2 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -108,7 +108,7 @@ fn collect_unwrap_info<'tcx>( }, _ => (), } - } else if let ExprKind::Unary(UnOp::UnNot, expr) = &expr.kind { + } else if let ExprKind::Unary(UnOp::Not, expr) = &expr.kind { return collect_unwrap_info(cx, expr, branch, !invert); } else { if_chain! { diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 340d340d6d340..145703d1bdc3f 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -243,7 +243,7 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option Self { - Bar(self.0 & !other.0) // OK: UnNot part of BiExpr as child node + Bar(self.0 & !other.0) // OK: Not part of BiExpr as child node } } @@ -126,7 +126,7 @@ impl Sub for Bar { fn sub(self, other: Self) -> Self { if self.0 <= other.0 { - Bar(-(self.0 & other.0)) // OK: UnNeg part of BiExpr as parent node + Bar(-(self.0 & other.0)) // OK: Neg part of BiExpr as parent node } else { Bar(0) } From 775ce47b0658db3e076a0a3d4546b739bd24a582 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 9 Feb 2021 10:29:00 +0100 Subject: [PATCH 61/72] Rename "good first issue" back to "good-first-issue" --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index e56c447c674dc..b0a13f827d6cd 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,7 +1,7 @@ [relabel] allow-unauthenticated = [ "A-*", "C-*", "E-*", "I-*", "L-*", "P-*", "S-*", "T-*", - "good first issue" + "good-first-issue" ] [assign] From b932587c5d92bc7524ecd9d496f7081005299fa5 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 9 Feb 2021 17:38:16 +0100 Subject: [PATCH 62/72] Add better turbofish extractor --- clippy_lints/src/methods/mod.rs | 35 ++++++++++- tests/ui/from_iter_instead_of_collect.fixed | 30 ++++++--- tests/ui/from_iter_instead_of_collect.rs | 14 +++++ tests/ui/from_iter_instead_of_collect.stderr | 64 +++++++++++++++----- 4 files changed, 120 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3e356afa2a4d9..d9f906619a038 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4095,7 +4095,8 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< then { // `expr` implements `FromIterator` trait let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); - let sugg = format!("{}.collect::<{}>()", iter_expr, ty); + let turbofish = extract_turbofish(cx, expr, ty); + let sugg = format!("{}.collect::<{}>()", iter_expr, turbofish); span_lint_and_sugg( cx, FROM_ITER_INSTEAD_OF_COLLECT, @@ -4109,6 +4110,38 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< } } +fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String { + if_chain! { + let call_site = expr.span.source_callsite(); + if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site); + let snippet_split = snippet.split("::").collect::>(); + if let Some((_, elements)) = snippet_split.split_last(); + + then { + // is there a type specifier? (i.e.: like `` in `collections::BTreeSet::::`) + if let Some(type_specifier) = snippet_split.iter().find(|e| e.starts_with('<') && e.ends_with('>')) { + // remove the type specifier from the path elements + let without_ts = elements.iter().filter_map(|e| { + if e == type_specifier { None } else { Some((*e).to_string()) } + }).collect::>(); + // join and add the type specifier at the end (i.e.: `collections::BTreeSet`) + format!("{}{}", without_ts.join("::"), type_specifier) + } else { + // type is not explicitly specified so wildcards are needed + // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` + let ty_str = ty.to_string(); + let start = ty_str.find('<').unwrap_or(0); + let end = ty_str.find('>').unwrap_or_else(|| ty_str.len()); + let nb_wildcard = ty_str[start..end].split(',').count(); + let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); + format!("{}<{}>", elements.join("::"), wildcards) + } + } else { + ty.to_string() + } + } +} + fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool { expected.constness == actual.constness && expected.unsafety == actual.unsafety diff --git a/tests/ui/from_iter_instead_of_collect.fixed b/tests/ui/from_iter_instead_of_collect.fixed index 96701e8639562..b5f548810e65a 100644 --- a/tests/ui/from_iter_instead_of_collect.fixed +++ b/tests/ui/from_iter_instead_of_collect.fixed @@ -8,27 +8,41 @@ use std::iter::FromIterator; fn main() { let iter_expr = std::iter::repeat(5).take(5); - let _ = iter_expr.collect::>(); + let _ = iter_expr.collect::>(); - let _ = vec![5, 5, 5, 5].iter().enumerate().collect::>(); + let _ = vec![5, 5, 5, 5].iter().enumerate().collect::>(); Vec::from_iter(vec![42u32]); let a = vec![0, 1, 2]; - assert_eq!(a, (0..3).collect::>()); + assert_eq!(a, (0..3).collect::>()); + assert_eq!(a, (0..3).collect::>()); - let mut b = (0..3).collect::>(); + let mut b = (0..3).collect::>(); b.push_back(4); + let mut b = (0..3).collect::>(); + b.push_back(4); + + { + use std::collections; + let mut b = (0..3).collect::>(); + b.push_back(4); + } + let values = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]; - let bm = values.iter().cloned().collect::>(); - let mut bar = bm.range(0..2).collect::>(); + let bm = values.iter().cloned().collect::>(); + let mut bar = bm.range(0..2).collect::>(); bar.insert(&4, &'e'); - let mut bts = (0..3).collect::>(); + let mut bts = (0..3).collect::>(); bts.insert(2); { use std::collections; - let _ = (0..3).collect::>(); + let _ = (0..3).collect::>(); + let _ = (0..3).collect::>(); } + + for _i in [1, 2, 3].iter().collect::>() {} + for _i in [1, 2, 3].iter().collect::>() {} } diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index 211f57bc5374e..b842b5451d1c8 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -16,10 +16,20 @@ fn main() { let a = vec![0, 1, 2]; assert_eq!(a, Vec::from_iter(0..3)); + assert_eq!(a, Vec::::from_iter(0..3)); let mut b = VecDeque::from_iter(0..3); b.push_back(4); + let mut b = VecDeque::::from_iter(0..3); + b.push_back(4); + + { + use std::collections; + let mut b = collections::VecDeque::::from_iter(0..3); + b.push_back(4); + } + let values = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]; let bm = BTreeMap::from_iter(values.iter().cloned()); let mut bar = BTreeMap::from_iter(bm.range(0..2)); @@ -30,5 +40,9 @@ fn main() { { use std::collections; let _ = collections::BTreeSet::from_iter(0..3); + let _ = collections::BTreeSet::::from_iter(0..3); } + + for _i in Vec::from_iter([1, 2, 3].iter()) {} + for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} } diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index 336e25a8adf93..434734c9a213d 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -2,7 +2,7 @@ error: usage of `FromIterator::from_iter` --> $DIR/from_iter_instead_of_collect.rs:11:13 | LL | let _ = Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::>()` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` @@ -10,43 +10,79 @@ error: usage of `FromIterator::from_iter` --> $DIR/from_iter_instead_of_collect.rs:13:13 | LL | let _ = HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::>()` error: usage of `FromIterator::from_iter` --> $DIR/from_iter_instead_of_collect.rs:18:19 | LL | assert_eq!(a, Vec::from_iter(0..3)); - | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:20:17 + --> $DIR/from_iter_instead_of_collect.rs:19:19 + | +LL | assert_eq!(a, Vec::::from_iter(0..3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:21:17 | LL | let mut b = VecDeque::from_iter(0..3); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:24:17 + | +LL | let mut b = VecDeque::::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:29:21 + | +LL | let mut b = collections::VecDeque::::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:24:14 + --> $DIR/from_iter_instead_of_collect.rs:34:14 | LL | let bm = BTreeMap::from_iter(values.iter().cloned()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:25:19 + --> $DIR/from_iter_instead_of_collect.rs:35:19 | LL | let mut bar = BTreeMap::from_iter(bm.range(0..2)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:28:19 + --> $DIR/from_iter_instead_of_collect.rs:38:19 | LL | let mut bts = BTreeSet::from_iter(0..3); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:32:17 + --> $DIR/from_iter_instead_of_collect.rs:42:17 | LL | let _ = collections::BTreeSet::from_iter(0..3); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:43:17 + | +LL | let _ = collections::BTreeSet::::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:46:15 + | +LL | for _i in Vec::from_iter([1, 2, 3].iter()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:47:15 + | +LL | for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` -error: aborting due to 8 previous errors +error: aborting due to 14 previous errors From 03737e22478cf175d5943ae168d91f085d7de441 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 9 Feb 2021 17:44:36 +0100 Subject: [PATCH 63/72] Remove rustfmt from rust-toolchain file We use latest nightly rustfmt in our tests anyway --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index b617203bef6d8..d42fb5a68bca3 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] channel = "nightly-2021-02-03" -components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"] +components = ["llvm-tools-preview", "rustc-dev", "rust-src"] From 932cc085e6ac277d58fbb6bebe05252b75d5dc54 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda <41065217+TaKO8Ki@users.noreply.github.com> Date: Wed, 10 Feb 2021 15:49:07 +0900 Subject: [PATCH 64/72] Update clippy_lints/src/methods/bytes_nth.rs Co-authored-by: Phil Hansch --- clippy_lints/src/methods/bytes_nth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index 4f38db06c0a37..defc50ede2243 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -26,7 +26,7 @@ pub(super) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &' BYTES_NTH, expr.span, &format!("called `.byte().nth()` on a `{}`", caller_type), - "try calling `.as_bytes().get()`", + "try", format!( "{}.as_bytes().get({})", snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability), From 5996ae1cfca619145ffb5e041592efdd097e6391 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 10 Feb 2021 16:15:29 +0900 Subject: [PATCH 65/72] add some test cases --- tests/ui/bytes_nth.fixed | 8 +++++--- tests/ui/bytes_nth.rs | 8 +++++--- tests/ui/bytes_nth.stderr | 22 ++++++++++++++-------- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/tests/ui/bytes_nth.fixed b/tests/ui/bytes_nth.fixed index 36bf8660a34c0..bf68a7bbbf1d4 100644 --- a/tests/ui/bytes_nth.fixed +++ b/tests/ui/bytes_nth.fixed @@ -1,9 +1,11 @@ // run-rustfix +#![allow(clippy::unnecessary_operation)] #![warn(clippy::bytes_nth)] fn main() { - let _ = "Hello".as_bytes().get(3); - - let _ = String::from("Hello").as_bytes().get(3); + let s = String::from("String"); + s.as_bytes().get(3); + &s.as_bytes().get(3); + s[..].as_bytes().get(3); } diff --git a/tests/ui/bytes_nth.rs b/tests/ui/bytes_nth.rs index 257344c2d3295..629812cc02cb8 100644 --- a/tests/ui/bytes_nth.rs +++ b/tests/ui/bytes_nth.rs @@ -1,9 +1,11 @@ // run-rustfix +#![allow(clippy::unnecessary_operation)] #![warn(clippy::bytes_nth)] fn main() { - let _ = "Hello".bytes().nth(3); - - let _ = String::from("Hello").bytes().nth(3); + let s = String::from("String"); + s.bytes().nth(3); + &s.bytes().nth(3); + s[..].bytes().nth(3); } diff --git a/tests/ui/bytes_nth.stderr b/tests/ui/bytes_nth.stderr index b46a0736414b0..9a5742928cd61 100644 --- a/tests/ui/bytes_nth.stderr +++ b/tests/ui/bytes_nth.stderr @@ -1,16 +1,22 @@ -error: called `.byte().nth()` on a `str` - --> $DIR/bytes_nth.rs:6:13 +error: called `.byte().nth()` on a `String` + --> $DIR/bytes_nth.rs:8:5 | -LL | let _ = "Hello".bytes().nth(3); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try calling `.as_bytes().get()`: `"Hello".as_bytes().get(3)` +LL | s.bytes().nth(3); + | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)` | = note: `-D clippy::bytes-nth` implied by `-D warnings` error: called `.byte().nth()` on a `String` - --> $DIR/bytes_nth.rs:8:13 + --> $DIR/bytes_nth.rs:9:6 + | +LL | &s.bytes().nth(3); + | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)` + +error: called `.byte().nth()` on a `str` + --> $DIR/bytes_nth.rs:10:5 | -LL | let _ = String::from("Hello").bytes().nth(3); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try calling `.as_bytes().get()`: `String::from("Hello").as_bytes().get(3)` +LL | s[..].bytes().nth(3); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3)` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors From 94b8f23baf045b16e2a8b2e2cdd7436724bbf8d5 Mon Sep 17 00:00:00 2001 From: alpaca-tc Date: Thu, 11 Feb 2021 00:45:28 +0900 Subject: [PATCH 66/72] Fix typo --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4cb3a85851150..d3db9c666dfad 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1503,7 +1503,7 @@ declare_clippy_lint! { /// /// ```rust /// // Bad - /// let _ = "Hello".bytes().nth(3);; + /// let _ = "Hello".bytes().nth(3); /// /// // Good /// let _ = "Hello".as_bytes().get(3); From 1025cd349d1c1727e37f0d2835b34f6f48d91986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 9 Feb 2021 16:10:07 +0100 Subject: [PATCH 67/72] lintcheck toml: explain why tokei is commented out --- clippy_dev/lintcheck_crates.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_dev/lintcheck_crates.toml b/clippy_dev/lintcheck_crates.toml index c83b4b2ba4224..2cddd3e6ee709 100644 --- a/clippy_dev/lintcheck_crates.toml +++ b/clippy_dev/lintcheck_crates.toml @@ -4,6 +4,7 @@ cargo = {name = "cargo", versions = ['0.49.0']} iron = {name = "iron", versions = ['0.6.1']} ripgrep = {name = "ripgrep", versions = ['12.1.1']} xsv = {name = "xsv", versions = ['0.13.0']} +# commented out because of 173K clippy::match_same_arms msgs in language_type.rs #tokei = { name = "tokei", versions = ['12.0.4']} rayon = {name = "rayon", versions = ['1.5.0']} serde = {name = "serde", versions = ['1.0.118']} From c7241b6e5e0666a03ac10f4b48440db10dc748dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 9 Feb 2021 16:27:56 +0100 Subject: [PATCH 68/72] lintcheck: make the log file be ${source-file}-logs.txt this allows us to check multiple source.tomls and not worry about overriding our logfiles accidentally --- clippy_dev/src/lintcheck.rs | 11 +++++++---- .../{logs.txt => lintcheck_crates_logs.txt} | 0 2 files changed, 7 insertions(+), 4 deletions(-) rename lintcheck-logs/{logs.txt => lintcheck_crates_logs.txt} (100%) diff --git a/clippy_dev/src/lintcheck.rs b/clippy_dev/src/lintcheck.rs index 3fc7dcb7d4b8b..faf13543f188f 100644 --- a/clippy_dev/src/lintcheck.rs +++ b/clippy_dev/src/lintcheck.rs @@ -192,8 +192,10 @@ fn build_clippy() { } // get a list of CrateSources we want to check from a "lintcheck_crates.toml" file. -fn read_crates(toml_path: Option<&str>) -> Vec { +fn read_crates(toml_path: Option<&str>) -> (String, Vec) { let toml_path = PathBuf::from(toml_path.unwrap_or("clippy_dev/lintcheck_crates.toml")); + // save it so that we can use the name of the sources.toml as name for the logfile later. + let toml_filename = toml_path.file_stem().unwrap().to_str().unwrap().to_string(); let toml_content: String = std::fs::read_to_string(&toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display())); let crate_list: CrateList = @@ -237,7 +239,7 @@ fn read_crates(toml_path: Option<&str>) -> Vec { unreachable!("Failed to translate TomlCrate into CrateSource!"); } }); - crate_sources + (toml_filename, crate_sources) } // extract interesting data from a json lint message @@ -288,7 +290,7 @@ pub fn run(clap_config: &ArgMatches) { // download and extract the crates, then run clippy on them and collect clippys warnings // flatten into one big list of warnings - let crates = read_crates(clap_config.value_of("crates-toml")); + let (filename, crates) = read_crates(clap_config.value_of("crates-toml")); let clippy_warnings: Vec = if let Some(only_one_crate) = clap_config.value_of("only") { // if we don't have the specified crate in the .toml, throw an error @@ -351,5 +353,6 @@ pub fn run(clap_config: &ArgMatches) { // save the text into lintcheck-logs/logs.txt let mut text = clippy_ver; // clippy version number on top text.push_str(&format!("\n{}", all_msgs.join(""))); - write("lintcheck-logs/logs.txt", text).unwrap(); + let file = format!("lintcheck-logs/{}_logs.txt", filename); + write(file, text).unwrap(); } diff --git a/lintcheck-logs/logs.txt b/lintcheck-logs/lintcheck_crates_logs.txt similarity index 100% rename from lintcheck-logs/logs.txt rename to lintcheck-logs/lintcheck_crates_logs.txt From cfe154be8cce39b7c2bbe69a61d1ceb818d2a8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 9 Feb 2021 16:58:39 +0100 Subject: [PATCH 69/72] start a clippy-dev readme and some rough info on how to use lintcheck --- clippy_dev/README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 clippy_dev/README.md diff --git a/clippy_dev/README.md b/clippy_dev/README.md new file mode 100644 index 0000000000000..6ab8ecbdbcacb --- /dev/null +++ b/clippy_dev/README.md @@ -0,0 +1,26 @@ +## Clippy-dev is a tool to ease clippys development, similar to `rustc`s `x.py`. + +Functionalities (incomplete): + +# lintcheck +Runs clippy on a fixed set of crates read from `clippy_dev/lintcheck_crates.toml` +and saves logs of the lint warnings into the repo. +We can then check the diff and spot new or disappearing warnings. + +From the repo root, run: +```` +cargo run --target-dir clippy_dev/target --package clippy_dev \ +--bin clippy_dev --manifest-path clippy_dev/Cargo.toml --features lintcheck -- lintcheck +```` +or +```` +cargo dev-lintcheck +```` + +By default the logs will be saved into `lintcheck-logs/lintcheck_crates_logs.txt`. + +You can set a custom sources.toml by adding `--crates-toml custom.toml` +where `custom.toml` must be a relative path from the repo root. + +The results will then be saved to `lintcheck-logs/custom_logs.toml`. + From 5e29aa6fdf4c8729ffd01c40aa17ad9bd501d1df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 10 Feb 2021 11:32:10 +0100 Subject: [PATCH 70/72] lintcheck: add support for path sources --- clippy_dev/Cargo.toml | 3 +- clippy_dev/README.md | 6 ++-- clippy_dev/lintcheck_crates.toml | 1 + clippy_dev/src/lintcheck.rs | 50 ++++++++++++++++++++++++++++++-- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index f48c1ee5ea265..5ac96e2210c89 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" bytecount = "0.6" clap = "2.33" flate2 = { version = "1.0.19", optional = true } +fs_extra = { version = "1.2.0", optional = true } itertools = "0.9" opener = "0.4" regex = "1" @@ -21,5 +22,5 @@ ureq = { version = "2.0.0-rc3", optional = true } walkdir = "2" [features] -lintcheck = ["flate2", "serde_json", "tar", "toml", "ureq", "serde"] +lintcheck = ["flate2", "serde_json", "tar", "toml", "ureq", "serde", "fs_extra"] deny-warnings = [] diff --git a/clippy_dev/README.md b/clippy_dev/README.md index 6ab8ecbdbcacb..3846e8bd4ccb7 100644 --- a/clippy_dev/README.md +++ b/clippy_dev/README.md @@ -1,8 +1,10 @@ -## Clippy-dev is a tool to ease clippys development, similar to `rustc`s `x.py`. +# Clippy Dev Tool + +The Clippy Dev Tool is a tool to ease Clippy development, similar to `rustc`s `x.py`. Functionalities (incomplete): -# lintcheck +## `lintcheck` Runs clippy on a fixed set of crates read from `clippy_dev/lintcheck_crates.toml` and saves logs of the lint warnings into the repo. We can then check the diff and spot new or disappearing warnings. diff --git a/clippy_dev/lintcheck_crates.toml b/clippy_dev/lintcheck_crates.toml index 2cddd3e6ee709..60e70ca4eb22b 100644 --- a/clippy_dev/lintcheck_crates.toml +++ b/clippy_dev/lintcheck_crates.toml @@ -10,6 +10,7 @@ rayon = {name = "rayon", versions = ['1.5.0']} serde = {name = "serde", versions = ['1.0.118']} # top 10 crates.io dls bitflags = {name = "bitflags", versions = ['1.2.1']} +# crash = {name = "clippy_crash", path = "/tmp/clippy_crash"} libc = {name = "libc", versions = ['0.2.81']} log = {name = "log", versions = ['0.4.11']} proc-macro2 = {name = "proc-macro2", versions = ['1.0.24']} diff --git a/clippy_dev/src/lintcheck.rs b/clippy_dev/src/lintcheck.rs index faf13543f188f..e9d0b420c3bb5 100644 --- a/clippy_dev/src/lintcheck.rs +++ b/clippy_dev/src/lintcheck.rs @@ -31,13 +31,15 @@ struct TomlCrate { versions: Option>, git_url: Option, git_hash: Option, + path: Option, } -// represents an archive we download from crates.io +// represents an archive we download from crates.io, or a git repo, or a local repo #[derive(Debug, Serialize, Deserialize, Eq, Hash, PartialEq)] enum CrateSource { CratesIo { name: String, version: String }, Git { name: String, url: String, commit: String }, + Path { name: String, path: PathBuf }, } // represents the extracted sourcecode of a crate @@ -111,7 +113,7 @@ impl CrateSource { }, CrateSource::Git { name, url, commit } => { let repo_path = { - let mut repo_path = PathBuf::from("target/lintcheck/downloads"); + let mut repo_path = PathBuf::from("target/lintcheck/crates"); // add a -git suffix in case we have the same crate from crates.io and a git repo repo_path.push(format!("{}-git", name)); repo_path @@ -139,6 +141,37 @@ impl CrateSource { path: repo_path, } }, + CrateSource::Path { name, path } => { + use fs_extra::dir; + + // simply copy the entire directory into our target dir + let copy_dest = PathBuf::from("target/lintcheck/crates/"); + + // the source path of the crate we copied, ${copy_dest}/crate_name + let crate_root = copy_dest.join(name); // .../crates/local_crate + + if !crate_root.exists() { + println!("Copying {} to {}", path.display(), copy_dest.display()); + + dir::copy(path, ©_dest, &dir::CopyOptions::new()).expect(&format!( + "Failed to copy from {}, to {}", + path.display(), + crate_root.display() + )); + } else { + println!( + "Not copying {} to {}, destination already exists", + path.display(), + crate_root.display() + ); + } + + Crate { + version: String::from("local"), + name: name.clone(), + path: crate_root, + } + }, } } } @@ -211,6 +244,13 @@ fn read_crates(toml_path: Option<&str>) -> (String, Vec) { // multiple Cratesources) let mut crate_sources = Vec::new(); tomlcrates.into_iter().for_each(|tk| { + if let Some(ref path) = tk.path { + crate_sources.push(CrateSource::Path { + name: tk.name.clone(), + path: PathBuf::from(path), + }); + } + // if we have multiple versions, save each one if let Some(ref versions) = tk.versions { versions.iter().for_each(|ver| { @@ -234,7 +274,10 @@ fn read_crates(toml_path: Option<&str>) -> (String, Vec) { { eprintln!("tomlkrate: {:?}", tk); if tk.git_hash.is_some() != tk.git_url.is_some() { - panic!("Encountered TomlCrate with only one of git_hash and git_url!") + panic!("Error: Encountered TomlCrate with only one of git_hash and git_url!"); + } + if tk.path.is_some() && (tk.git_hash.is_some() || tk.versions.is_some()) { + panic!("Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields"); } unreachable!("Failed to translate TomlCrate into CrateSource!"); } @@ -298,6 +341,7 @@ pub fn run(clap_config: &ArgMatches) { let name = match krate { CrateSource::CratesIo { name, .. } => name, CrateSource::Git { name, .. } => name, + CrateSource::Path { name, .. } => name, }; name == only_one_crate }) { From a6d493d52af32a347550ca7dd3fba77b50412128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 10 Feb 2021 12:50:36 +0100 Subject: [PATCH 71/72] lintcheck: collect ICEs --- clippy_dev/src/lintcheck.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/clippy_dev/src/lintcheck.rs b/clippy_dev/src/lintcheck.rs index e9d0b420c3bb5..749a791b280e2 100644 --- a/clippy_dev/src/lintcheck.rs +++ b/clippy_dev/src/lintcheck.rs @@ -62,6 +62,7 @@ struct ClippyWarning { column: String, linttype: String, message: String, + ice: bool, } impl std::fmt::Display for ClippyWarning { @@ -209,8 +210,8 @@ impl Crate { let output_lines = stdout.lines(); let warnings: Vec = output_lines .into_iter() - // get all clippy warnings - .filter(|line| line.contains("clippy::")) + // get all clippy warnings and ICEs + .filter(|line| line.contains("clippy::") || line.contains("internal compiler error: ")) .map(|json_msg| parse_json_message(json_msg, &self)) .collect(); warnings @@ -306,6 +307,7 @@ fn parse_json_message(json_message: &str, krate: &Crate) -> ClippyWarning { .into(), linttype: jmsg["message"]["code"]["code"].to_string().trim_matches('"').into(), message: jmsg["message"]["message"].to_string().trim_matches('"').into(), + ice: json_message.contains("internal compiler error: "), } } @@ -372,6 +374,13 @@ pub fn run(clap_config: &ArgMatches) { // generate some stats: + // grab crashes/ICEs, save the crate name and the ice message + let ices: Vec<(&String, &String)> = clippy_warnings + .iter() + .filter(|warning| warning.ice) + .map(|w| (&w.crate_name, &w.message)) + .collect(); + // count lint type occurrences let mut counter: HashMap<&String, usize> = HashMap::new(); clippy_warnings @@ -397,6 +406,10 @@ pub fn run(clap_config: &ArgMatches) { // save the text into lintcheck-logs/logs.txt let mut text = clippy_ver; // clippy version number on top text.push_str(&format!("\n{}", all_msgs.join(""))); + text.push_str("ICEs:\n"); + ices.iter() + .for_each(|(cratename, msg)| text.push_str(&format!("{}: '{}'", cratename, msg))); + let file = format!("lintcheck-logs/{}_logs.txt", filename); write(file, text).unwrap(); } From 4efc4541d2c7247fa5f9c34653f7fa70eb73846c Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 11 Feb 2021 14:37:13 +0100 Subject: [PATCH 72/72] Bump nightly version -> 2021-02-11 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index d42fb5a68bca3..e73da595e19df 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-02-03" +channel = "nightly-2021-02-11" components = ["llvm-tools-preview", "rustc-dev", "rust-src"]