From d00ca112020680928aadb221aad13bd52634823b Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 12 Dec 2020 13:46:25 -0800 Subject: [PATCH 001/103] Add 'consider using' message to overflowing_literals Ironically, the overflowing_literals handler for binary or hex already had this message! You would think it would be the other way around :) --- compiler/rustc_lint/src/types.rs | 29 +++++++++++-------- .../ui/enum/enum-discrim-too-small2.stderr | 4 +++ src/test/ui/issues/issue-79744.rs | 13 +++++++++ src/test/ui/issues/issue-79744.stderr | 12 ++++++++ src/test/ui/lint/lint-type-limits2.stderr | 1 + src/test/ui/lint/lint-type-limits3.stderr | 1 + src/test/ui/lint/lint-type-overflow.stderr | 16 ++++++++++ src/test/ui/lint/lint-type-overflow2.stderr | 1 + src/test/ui/lint/type-overflow.stderr | 1 + 9 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/issues/issue-79744.rs create mode 100644 src/test/ui/issues/issue-79744.stderr diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9ad9d53cd0db3..d9f4da23d2f86 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -331,18 +331,23 @@ fn lint_int_literal<'tcx>( } cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { - lint.build(&format!("literal out of range for `{}`", t.name_str())) - .note(&format!( - "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`", - cx.sess() - .source_map() - .span_to_snippet(lit.span) - .expect("must get snippet from literal"), - t.name_str(), - min, - max, - )) - .emit(); + let mut err = lint.build(&format!("literal out of range for `{}`", t.name_str())); + err.note(&format!( + "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`", + cx.sess() + .source_map() + .span_to_snippet(lit.span) + .expect("must get snippet from literal"), + t.name_str(), + min, + max, + )); + if let Some(sugg_ty) = + get_type_suggestion(&cx.typeck_results().node_type(e.hir_id), v, negative) + { + err.help(&format!("consider using `{}` instead", sugg_ty)); + } + err.emit(); }); } } diff --git a/src/test/ui/enum/enum-discrim-too-small2.stderr b/src/test/ui/enum/enum-discrim-too-small2.stderr index fadf6ab86b43e..f0deb26e96db4 100644 --- a/src/test/ui/enum/enum-discrim-too-small2.stderr +++ b/src/test/ui/enum/enum-discrim-too-small2.stderr @@ -10,6 +10,7 @@ note: the lint level is defined here LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ = note: the literal `223` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using `u8` instead error: literal out of range for `i16` --> $DIR/enum-discrim-too-small2.rs:15:12 @@ -18,6 +19,7 @@ LL | Ci16 = 55555, | ^^^^^ | = note: the literal `55555` does not fit into the type `i16` whose range is `-32768..=32767` + = help: consider using `u16` instead error: literal out of range for `i32` --> $DIR/enum-discrim-too-small2.rs:22:12 @@ -26,6 +28,7 @@ LL | Ci32 = 3_000_000_000, | ^^^^^^^^^^^^^ | = note: the literal `3_000_000_000` does not fit into the type `i32` whose range is `-2147483648..=2147483647` + = help: consider using `u32` instead error: literal out of range for `i64` --> $DIR/enum-discrim-too-small2.rs:29:12 @@ -34,6 +37,7 @@ LL | Ci64 = 9223372036854775809, | ^^^^^^^^^^^^^^^^^^^ | = note: the literal `9223372036854775809` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` + = help: consider using `u64` instead error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-79744.rs b/src/test/ui/issues/issue-79744.rs new file mode 100644 index 0000000000000..49051f2cee655 --- /dev/null +++ b/src/test/ui/issues/issue-79744.rs @@ -0,0 +1,13 @@ +fn main() { + let elem = 6i8; + let e2 = 230; + //~^ ERROR literal out of range for `i8` + //~| HELP consider using `u8` instead + + let mut vec = Vec::new(); + + vec.push(e2); + vec.push(elem); + + println!("{:?}", vec); +} diff --git a/src/test/ui/issues/issue-79744.stderr b/src/test/ui/issues/issue-79744.stderr new file mode 100644 index 0000000000000..b35700cd47268 --- /dev/null +++ b/src/test/ui/issues/issue-79744.stderr @@ -0,0 +1,12 @@ +error: literal out of range for `i8` + --> $DIR/issue-79744.rs:3:14 + | +LL | let e2 = 230; + | ^^^ + | + = note: `#[deny(overflowing_literals)]` on by default + = note: the literal `230` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using `u8` instead + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-type-limits2.stderr b/src/test/ui/lint/lint-type-limits2.stderr index e8746ce980a96..357fde7151ca2 100644 --- a/src/test/ui/lint/lint-type-limits2.stderr +++ b/src/test/ui/lint/lint-type-limits2.stderr @@ -18,6 +18,7 @@ note: the lint level is defined here LL | #![warn(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ = note: the literal `128` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using `u8` instead error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/lint/lint-type-limits3.stderr b/src/test/ui/lint/lint-type-limits3.stderr index 0e8a64510695a..c8558cfc2143c 100644 --- a/src/test/ui/lint/lint-type-limits3.stderr +++ b/src/test/ui/lint/lint-type-limits3.stderr @@ -18,6 +18,7 @@ note: the lint level is defined here LL | #![warn(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ = note: the literal `200` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using `u8` instead error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/lint/lint-type-overflow.stderr b/src/test/ui/lint/lint-type-overflow.stderr index 7715c0d3a4db9..f0a8f507d5723 100644 --- a/src/test/ui/lint/lint-type-overflow.stderr +++ b/src/test/ui/lint/lint-type-overflow.stderr @@ -26,6 +26,7 @@ LL | let x1: i8 = 128; | ^^^ | = note: the literal `128` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using `u8` instead error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:18:19 @@ -34,6 +35,7 @@ LL | let x3: i8 = -129; | ^^^ | = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using `i16` instead error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:19:19 @@ -42,6 +44,7 @@ LL | let x3: i8 = -(129); | ^^^^^ | = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using `i16` instead error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:20:20 @@ -50,6 +53,7 @@ LL | let x3: i8 = -{129}; | ^^^ | = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using `u8` instead error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:22:10 @@ -58,6 +62,7 @@ LL | test(1000); | ^^^^ | = note: the literal `1000` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using `i16` instead error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:24:13 @@ -66,6 +71,7 @@ LL | let x = 128_i8; | ^^^^^^ | = note: the literal `128_i8` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using `u8` instead error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:28:14 @@ -74,6 +80,7 @@ LL | let x = -129_i8; | ^^^^^^ | = note: the literal `129_i8` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using `i16` instead error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:32:18 @@ -82,6 +89,7 @@ LL | let x: i32 = 2147483648; | ^^^^^^^^^^ | = note: the literal `2147483648` does not fit into the type `i32` whose range is `-2147483648..=2147483647` + = help: consider using `u32` instead error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:33:13 @@ -90,6 +98,7 @@ LL | let x = 2147483648_i32; | ^^^^^^^^^^^^^^ | = note: the literal `2147483648_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647` + = help: consider using `u32` instead error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:36:19 @@ -98,6 +107,7 @@ LL | let x: i32 = -2147483649; | ^^^^^^^^^^ | = note: the literal `2147483649` does not fit into the type `i32` whose range is `-2147483648..=2147483647` + = help: consider using `i64` instead error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:37:14 @@ -106,6 +116,7 @@ LL | let x = -2147483649_i32; | ^^^^^^^^^^^^^^ | = note: the literal `2147483649_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647` + = help: consider using `i64` instead error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:38:13 @@ -114,6 +125,7 @@ LL | let x = 2147483648; | ^^^^^^^^^^ | = note: the literal `2147483648` does not fit into the type `i32` whose range is `-2147483648..=2147483647` + = help: consider using `u32` instead error: literal out of range for `i64` --> $DIR/lint-type-overflow.rs:40:13 @@ -122,6 +134,7 @@ LL | let x = 9223372036854775808_i64; | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: the literal `9223372036854775808_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` + = help: consider using `u64` instead error: literal out of range for `i64` --> $DIR/lint-type-overflow.rs:42:13 @@ -130,6 +143,7 @@ LL | let x = 18446744073709551615_i64; | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the literal `18446744073709551615_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` + = help: consider using `u64` instead error: literal out of range for `i64` --> $DIR/lint-type-overflow.rs:43:19 @@ -138,6 +152,7 @@ LL | let x: i64 = -9223372036854775809; | ^^^^^^^^^^^^^^^^^^^ | = note: the literal `9223372036854775809` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` + = help: consider using `i128` instead error: literal out of range for `i64` --> $DIR/lint-type-overflow.rs:44:14 @@ -146,6 +161,7 @@ LL | let x = -9223372036854775809_i64; | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: the literal `9223372036854775809_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` + = help: consider using `i128` instead error: aborting due to 18 previous errors diff --git a/src/test/ui/lint/lint-type-overflow2.stderr b/src/test/ui/lint/lint-type-overflow2.stderr index 0f16229a29178..ab28c4aaf477b 100644 --- a/src/test/ui/lint/lint-type-overflow2.stderr +++ b/src/test/ui/lint/lint-type-overflow2.stderr @@ -10,6 +10,7 @@ note: the lint level is defined here LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ = note: the literal `128` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using `u8` instead error: literal out of range for `f32` --> $DIR/lint-type-overflow2.rs:9:14 diff --git a/src/test/ui/lint/type-overflow.stderr b/src/test/ui/lint/type-overflow.stderr index 6ba8b43954d3e..dafce414d2fdf 100644 --- a/src/test/ui/lint/type-overflow.stderr +++ b/src/test/ui/lint/type-overflow.stderr @@ -10,6 +10,7 @@ note: the lint level is defined here LL | #![warn(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ = note: the literal `255i8` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using `u8` instead warning: literal out of range for i8 --> $DIR/type-overflow.rs:10:16 From 949b12589112cecad9566305444527ec0738d521 Mon Sep 17 00:00:00 2001 From: nahuakang Date: Wed, 27 Jan 2021 09:34:36 +0100 Subject: [PATCH 002/103] 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 003/103] 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 004/103] 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 005/103] 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 006/103] 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 007/103] 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 008/103] 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 009/103] 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 010/103] 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 011/103] 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 012/103] 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 013/103] 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 014/103] 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 015/103] 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 016/103] 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 017/103] 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 018/103] 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 019/103] 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 020/103] 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 021/103] 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 022/103] 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 023/103] 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 024/103] 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 025/103] 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 026/103] 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 027/103] 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 028/103] 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 029/103] 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 030/103] 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 031/103] 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 032/103] 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 033/103] 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 034/103] 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 035/103] 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 036/103] 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 037/103] 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 038/103] 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 039/103] 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 040/103] 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 041/103] 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 042/103] 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 043/103] 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 044/103] 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 045/103] 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 046/103] 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 047/103] 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 048/103] 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 049/103] 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 050/103] 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 051/103] 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 052/103] 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 053/103] 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 054/103] 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 055/103] 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 056/103] 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 7e94641ee956989d57492975a1214fc79dcd1fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Sun, 7 Feb 2021 23:13:36 +0300 Subject: [PATCH 057/103] Fix SourceMap::start_point `start_point` needs to return the *first* character's span, but it would previously call `find_width_of_character_at_span` which returns the span of the *last* character. The implementation is now fixed. Other changes: - Docs for start_point, end_point, find_width_of_character_at_span updated - Minor simplification in find_width_of_character_at_span code Fixes #81800 --- compiler/rustc_span/src/source_map.rs | 42 +++++++++++++++++++-------- src/test/ui/span/issue-81800.rs | 2 ++ src/test/ui/span/issue-81800.stderr | 19 ++++++++++++ 3 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/span/issue-81800.rs create mode 100644 src/test/ui/span/issue-81800.stderr diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 2b429372dcffb..8bcd468d41276 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -777,16 +777,35 @@ impl SourceMap { self.span_until_char(sp, '{') } - /// Returns a new span representing just the start point of this span. + /// Returns a new span representing just the first character of the given span. pub fn start_point(&self, sp: Span) -> Span { - let pos = sp.lo().0; - let width = self.find_width_of_character_at_span(sp, false); - let corrected_start_position = pos.checked_add(width).unwrap_or(pos); - let end_point = BytePos(cmp::max(corrected_start_position, sp.lo().0)); - sp.with_hi(end_point) + let width = { + let sp = sp.data(); + let local_begin = self.lookup_byte_offset(sp.lo); + let start_index = local_begin.pos.to_usize(); + let src = local_begin.sf.external_src.borrow(); + + let snippet = if let Some(ref src) = local_begin.sf.src { + Some(&src[start_index..]) + } else if let Some(src) = src.get_source() { + Some(&src[start_index..]) + } else { + None + }; + + match snippet { + None => 1, + Some(snippet) => match snippet.chars().next() { + None => 1, + Some(c) => c.len_utf8(), + }, + } + }; + + sp.with_hi(BytePos(sp.lo().0 + width as u32)) } - /// Returns a new span representing just the end point of this span. + /// Returns a new span representing just the last character of this span. pub fn end_point(&self, sp: Span) -> Span { let pos = sp.hi().0; @@ -815,7 +834,8 @@ impl SourceMap { Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt()) } - /// Finds the width of a character, either before or after the provided span. + /// Finds the width of the character, either before or after the end of provided span, + /// depending on the `forwards` parameter. fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 { let sp = sp.data(); if sp.lo == sp.hi { @@ -862,11 +882,9 @@ impl SourceMap { // We need to extend the snippet to the end of the src rather than to end_index so when // searching forwards for boundaries we've got somewhere to search. let snippet = if let Some(ref src) = local_begin.sf.src { - let len = src.len(); - &src[start_index..len] + &src[start_index..] } else if let Some(src) = src.get_source() { - let len = src.len(); - &src[start_index..len] + &src[start_index..] } else { return 1; }; diff --git a/src/test/ui/span/issue-81800.rs b/src/test/ui/span/issue-81800.rs new file mode 100644 index 0000000000000..6ac66fdcb65ad --- /dev/null +++ b/src/test/ui/span/issue-81800.rs @@ -0,0 +1,2 @@ +fn x˂- //~ ERROR: unknown start of token + //~^ ERROR: expected one of `#`, `>`, `const`, identifier, or lifetime, found `-` diff --git a/src/test/ui/span/issue-81800.stderr b/src/test/ui/span/issue-81800.stderr new file mode 100644 index 0000000000000..d37f13a6683b0 --- /dev/null +++ b/src/test/ui/span/issue-81800.stderr @@ -0,0 +1,19 @@ +error: unknown start of token: \u{2c2} + --> $DIR/issue-81800.rs:1:5 + | +LL | fn x˂- + | ^ + | +help: Unicode character '˂' (Modifier Letter Left Arrowhead) looks like '<' (Less-Than Sign), but it is not + | +LL | fn x<- + | ^ + +error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `-` + --> $DIR/issue-81800.rs:1:6 + | +LL | fn x˂- + | ^ expected one of `#`, `>`, `const`, identifier, or lifetime + +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 058/103] 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 059/103] 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 060/103] 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 061/103] 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 062/103] 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 063/103] 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 064/103] 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 065/103] 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 1eb79f3c375f4d7834a30b40c20a9c8ec1c31b4c Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 9 Feb 2021 20:56:45 +0000 Subject: [PATCH 066/103] Use longer lifetime in `try_report_from_nll` return type --- .../src/infer/error_reporting/nice_region_error/mod.rs | 2 +- .../error_reporting/nice_region_error/named_anon_conflict.rs | 2 +- .../error_reporting/nice_region_error/placeholder_error.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index cc8f1816bc3f4..0599c78ebfd07 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -43,7 +43,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { self.infcx.tcx } - pub fn try_report_from_nll(&self) -> Option> { + pub fn try_report_from_nll(&self) -> Option> { // Due to the improved diagnostics returned by the MIR borrow checker, only a subset of // the nice region errors are required when running under the MIR borrow checker. self.try_report_named_anon_conflict().or_else(|| self.try_report_placeholder_conflict()) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index e3c613b1d6a12..2f622231a081e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -9,7 +9,7 @@ use rustc_middle::ty; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// When given a `ConcreteFailure` for a function with parameters containing a named region and /// an anonymous region, emit an descriptive diagnostic error. - pub(super) fn try_report_named_anon_conflict(&self) -> Option> { + pub(super) fn try_report_named_anon_conflict(&self) -> Option> { let (span, sub, sup) = self.regions()?; debug!( diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index e8e0326d97865..fc211a15afc05 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -16,7 +16,7 @@ use std::fmt::{self, Write}; impl NiceRegionError<'me, 'tcx> { /// When given a `ConcreteFailure` for a function with arguments containing a named region and /// an anonymous region, emit a descriptive diagnostic error. - pub(super) fn try_report_placeholder_conflict(&self) -> Option> { + pub(super) fn try_report_placeholder_conflict(&self) -> Option> { match &self.error { /////////////////////////////////////////////////////////////////////////// // NB. The ordering of cases in this match is very @@ -199,7 +199,7 @@ impl NiceRegionError<'me, 'tcx> { trait_def_id: DefId, expected_substs: SubstsRef<'tcx>, actual_substs: SubstsRef<'tcx>, - ) -> DiagnosticBuilder<'me> { + ) -> DiagnosticBuilder<'tcx> { debug!( "try_report_placeholders_trait(\ vid={:?}, \ From 638980a07f72e20fcbcdab12b74b2a1a8663741d Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 9 Feb 2021 21:03:00 +0000 Subject: [PATCH 067/103] Using tracing macros in placeholder_error.rs --- .../nice_region_error/placeholder_error.rs | 28 +++++-------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index fc211a15afc05..8c933df8ca00d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -190,6 +190,7 @@ impl NiceRegionError<'me, 'tcx> { // = note: Due to a where-clause on the function `all`, // = note: `T` must implement `...` for any two lifetimes `'1` and `'2`. // = note: However, the type `T` only implements `...` for some specific lifetime `'2`. + #[instrument(level = "debug", skip(self))] fn try_report_placeholders_trait( &self, vid: Option>, @@ -200,17 +201,6 @@ impl NiceRegionError<'me, 'tcx> { expected_substs: SubstsRef<'tcx>, actual_substs: SubstsRef<'tcx>, ) -> DiagnosticBuilder<'tcx> { - debug!( - "try_report_placeholders_trait(\ - vid={:?}, \ - sub_placeholder={:?}, \ - sup_placeholder={:?}, \ - trait_def_id={:?}, \ - expected_substs={:?}, \ - actual_substs={:?})", - vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs - ); - let span = cause.span(self.tcx()); let msg = format!( "implementation of `{}` is not general enough", @@ -285,17 +275,13 @@ impl NiceRegionError<'me, 'tcx> { let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid; - debug!("try_report_placeholders_trait: actual_has_vid={:?}", actual_has_vid); - debug!("try_report_placeholders_trait: expected_has_vid={:?}", expected_has_vid); - debug!("try_report_placeholders_trait: has_sub={:?}", has_sub); - debug!("try_report_placeholders_trait: has_sup={:?}", has_sup); - debug!( - "try_report_placeholders_trait: actual_self_ty_has_vid={:?}", - actual_self_ty_has_vid - ); debug!( - "try_report_placeholders_trait: expected_self_ty_has_vid={:?}", - expected_self_ty_has_vid + ?actual_has_vid, + ?expected_has_vid, + ?has_sub, + ?has_sup, + ?actual_self_ty_has_vid, + ?expected_self_ty_has_vid, ); self.explain_actual_impl_that_was_found( From c2066cf0694c304c0fc43f17bebefb518b066619 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 9 Feb 2021 21:16:00 +0000 Subject: [PATCH 068/103] Remove unnecessary note on errors Seeing the trait definition doesn't help with implementation not general enough errors, so don't make the error message larger to show it. --- .../nice_region_error/placeholder_error.rs | 4 -- .../associated-types-eq-hr.stderr | 55 ++++--------------- .../ui/generator/auto-trait-regions.stderr | 12 ---- src/test/ui/hrtb/due-to-where-clause.stderr | 3 - .../ui/hrtb/hrtb-cache-issue-54302.stderr | 3 - src/test/ui/hrtb/hrtb-conflate-regions.stderr | 9 +-- ...b-exists-forall-trait-contravariant.stderr | 3 - .../hrtb-exists-forall-trait-invariant.stderr | 3 - src/test/ui/hrtb/hrtb-just-for-static.stderr | 18 ++---- src/test/ui/hrtb/issue-46989.stderr | 3 - src/test/ui/issues/issue-54302-cases.stderr | 36 +++--------- src/test/ui/issues/issue-54302.stderr | 3 - src/test/ui/issues/issue-55731.stderr | 9 +-- .../ui/where-clauses/where-for-self-2.stderr | 9 +-- 14 files changed, 28 insertions(+), 142 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 8c933df8ca00d..d99e79005fbb8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -207,10 +207,6 @@ impl NiceRegionError<'me, 'tcx> { self.tcx().def_path_str(trait_def_id), ); let mut err = self.tcx().sess.struct_span_err(span, &msg); - err.span_label( - self.tcx().def_span(trait_def_id), - format!("trait `{}` defined here", self.tcx().def_path_str(trait_def_id)), - ); let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = cause.code { err.span_label(span, "doesn't satisfy where-clause"); diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr index 127ab8673556d..6188d9ca979cf 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.stderr +++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr @@ -31,15 +31,8 @@ LL | bar::(); error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:96:5 | -LL | / pub trait TheTrait { -LL | | type A; -LL | | -LL | | fn get(&self, t: T) -> Self::A; -LL | | } - | |_- trait `TheTrait` defined here -... -LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough +LL | tuple_one::(); + | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough | = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` @@ -47,15 +40,8 @@ LL | tuple_one::(); error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:96:5 | -LL | / pub trait TheTrait { -LL | | type A; -LL | | -LL | | fn get(&self, t: T) -> Self::A; -LL | | } - | |_- trait `TheTrait` defined here -... -LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough +LL | tuple_one::(); + | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough | = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` @@ -63,15 +49,8 @@ LL | tuple_one::(); error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:102:5 | -LL | / pub trait TheTrait { -LL | | type A; -LL | | -LL | | fn get(&self, t: T) -> Self::A; -LL | | } - | |_- trait `TheTrait` defined here -... -LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough +LL | tuple_two::(); + | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough | = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` @@ -79,15 +58,8 @@ LL | tuple_two::(); error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:102:5 | -LL | / pub trait TheTrait { -LL | | type A; -LL | | -LL | | fn get(&self, t: T) -> Self::A; -LL | | } - | |_- trait `TheTrait` defined here -... -LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough +LL | tuple_two::(); + | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough | = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` @@ -95,15 +67,8 @@ LL | tuple_two::(); error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:112:5 | -LL | / pub trait TheTrait { -LL | | type A; -LL | | -LL | | fn get(&self, t: T) -> Self::A; -LL | | } - | |_- trait `TheTrait` defined here -... -LL | tuple_four::(); - | ^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough +LL | tuple_four::(); + | ^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough | = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` diff --git a/src/test/ui/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr index 5ec462e10465f..5fe4193905c72 100644 --- a/src/test/ui/generator/auto-trait-regions.stderr +++ b/src/test/ui/generator/auto-trait-regions.stderr @@ -1,9 +1,6 @@ error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:31:5 | -LL | auto trait Foo {} - | ----------------- trait `Foo` defined here -... LL | assert_foo(gen); | ^^^^^^^^^^ implementation of `Foo` is not general enough | @@ -13,9 +10,6 @@ LL | assert_foo(gen); error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:31:5 | -LL | auto trait Foo {} - | ----------------- trait `Foo` defined here -... LL | assert_foo(gen); | ^^^^^^^^^^ implementation of `Foo` is not general enough | @@ -25,9 +19,6 @@ LL | assert_foo(gen); error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:50:5 | -LL | auto trait Foo {} - | ----------------- trait `Foo` defined here -... LL | assert_foo(gen); | ^^^^^^^^^^ implementation of `Foo` is not general enough | @@ -37,9 +28,6 @@ LL | assert_foo(gen); error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:50:5 | -LL | auto trait Foo {} - | ----------------- trait `Foo` defined here -... LL | assert_foo(gen); | ^^^^^^^^^^ implementation of `Foo` is not general enough | diff --git a/src/test/ui/hrtb/due-to-where-clause.stderr b/src/test/ui/hrtb/due-to-where-clause.stderr index e4096ec059a6e..520938a633514 100644 --- a/src/test/ui/hrtb/due-to-where-clause.stderr +++ b/src/test/ui/hrtb/due-to-where-clause.stderr @@ -3,9 +3,6 @@ error: implementation of `Foo` is not general enough | LL | test::(&mut 42); | ^^^^^^^^^^^^ implementation of `Foo` is not general enough -... -LL | trait Foo<'a> {} - | ---------------- trait `Foo` defined here | = note: `FooS<'_>` must implement `Foo<'0>`, for any lifetime `'0`... = note: ...but `FooS<'_>` actually implements `Foo<'1>`, for some specific lifetime `'1` diff --git a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr index 003f32659351f..f014eab8601fa 100644 --- a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr +++ b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr @@ -1,9 +1,6 @@ error: implementation of `Deserialize` is not general enough --> $DIR/hrtb-cache-issue-54302.rs:19:5 | -LL | trait Deserialize<'de> {} - | ------------------------- trait `Deserialize` defined here -... LL | assert_deserialize_owned::<&'static str>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough | diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.stderr index 45573814d13c0..7a0ede5af201c 100644 --- a/src/test/ui/hrtb/hrtb-conflate-regions.stderr +++ b/src/test/ui/hrtb/hrtb-conflate-regions.stderr @@ -1,13 +1,8 @@ error: implementation of `Foo` is not general enough --> $DIR/hrtb-conflate-regions.rs:27:10 | -LL | / trait Foo { -LL | | fn foo(&self, x: X) { } -LL | | } - | |_- trait `Foo` defined here -... -LL | fn b() { want_foo2::(); } - | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough +LL | fn b() { want_foo2::(); } + | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but `SomeStruct` actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr index fe8209d054c8a..2f946c7d9bfe8 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr @@ -1,9 +1,6 @@ error: implementation of `Trait` is not general enough --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5 | -LL | trait Trait {} - | ----------------- trait `Trait` defined here -... LL | foo::<()>(); | ^^^^^^^^^ implementation of `Trait` is not general enough | diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr index 8bd23aa9018df..ba244e0f2ebc7 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr @@ -1,9 +1,6 @@ error: implementation of `Trait` is not general enough --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5 | -LL | trait Trait {} - | ----------------- trait `Trait` defined here -... LL | foo::<()>(); | ^^^^^^^^^ implementation of `Trait` is not general enough | diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr index 5e3014317f5bc..0d46a130e093e 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr @@ -1,13 +1,8 @@ error: implementation of `Foo` is not general enough --> $DIR/hrtb-just-for-static.rs:24:5 | -LL | / trait Foo { -LL | | fn foo(&self, x: X) { } -LL | | } - | |_- trait `Foo` defined here -... -LL | want_hrtb::() - | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough +LL | want_hrtb::() + | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`... = note: ...but `StaticInt` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1` @@ -15,13 +10,8 @@ LL | want_hrtb::() error: implementation of `Foo` is not general enough --> $DIR/hrtb-just-for-static.rs:30:5 | -LL | / trait Foo { -LL | | fn foo(&self, x: X) { } -LL | | } - | |_- trait `Foo` defined here -... -LL | want_hrtb::<&'a u32>() - | ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough +LL | want_hrtb::<&'a u32>() + | ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | = note: `Foo<&'0 isize>` would have to be implemented for the type `&'a u32`, for any lifetime `'0`... = note: ...but `Foo<&'1 isize>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` diff --git a/src/test/ui/hrtb/issue-46989.stderr b/src/test/ui/hrtb/issue-46989.stderr index c85c37ff9239e..f3d906cae4cc3 100644 --- a/src/test/ui/hrtb/issue-46989.stderr +++ b/src/test/ui/hrtb/issue-46989.stderr @@ -1,9 +1,6 @@ error: implementation of `Foo` is not general enough --> $DIR/issue-46989.rs:38:5 | -LL | trait Foo {} - | ------------ trait `Foo` defined here -... LL | assert_foo::(); | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | diff --git a/src/test/ui/issues/issue-54302-cases.stderr b/src/test/ui/issues/issue-54302-cases.stderr index 3ed2779164301..baa75f28d37f3 100644 --- a/src/test/ui/issues/issue-54302-cases.stderr +++ b/src/test/ui/issues/issue-54302-cases.stderr @@ -1,13 +1,8 @@ error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:63:5 | -LL | / trait Foo<'x, T> { -LL | | fn foo(self) -> &'x T; -LL | | } - | |_- trait `Foo` defined here -... -LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | = note: `Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Foo<'_, u32>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` @@ -15,13 +10,8 @@ LL | >::ref_foo(a) error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:69:5 | -LL | / trait Foo<'x, T> { -LL | | fn foo(self) -> &'x T; -LL | | } - | |_- trait `Foo` defined here -... -LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | = note: `Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`... = note: ...but `Foo<'_, i32>` is actually implemented for the type `&'1 i32`, for some specific lifetime `'1` @@ -29,13 +19,8 @@ LL | >::ref_foo(a) error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:75:5 | -LL | / trait Foo<'x, T> { -LL | | fn foo(self) -> &'x T; -LL | | } - | |_- trait `Foo` defined here -... -LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | = note: `Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`... = note: ...but `Foo<'_, u64>` is actually implemented for the type `&'1 u64`, for some specific lifetime `'1` @@ -43,13 +28,8 @@ LL | >::ref_foo(a) error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:81:5 | -LL | / trait Foo<'x, T> { -LL | | fn foo(self) -> &'x T; -LL | | } - | |_- trait `Foo` defined here -... -LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | = note: `Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`... = note: ...but `Foo<'_, i64>` is actually implemented for the type `&'1 i64`, for some specific lifetime `'1` diff --git a/src/test/ui/issues/issue-54302.stderr b/src/test/ui/issues/issue-54302.stderr index 1b3f57ba188a3..26c46571f9cb2 100644 --- a/src/test/ui/issues/issue-54302.stderr +++ b/src/test/ui/issues/issue-54302.stderr @@ -1,9 +1,6 @@ error: implementation of `Deserialize` is not general enough --> $DIR/issue-54302.rs:13:5 | -LL | trait Deserialize<'de> {} - | ------------------------- trait `Deserialize` defined here -... LL | assert_deserialize_owned::<&'static str>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough | diff --git a/src/test/ui/issues/issue-55731.stderr b/src/test/ui/issues/issue-55731.stderr index f44c842187cc2..de327cd3cc23c 100644 --- a/src/test/ui/issues/issue-55731.stderr +++ b/src/test/ui/issues/issue-55731.stderr @@ -1,13 +1,8 @@ error: implementation of `DistributedIteratorMulti` is not general enough --> $DIR/issue-55731.rs:48:5 | -LL | / trait DistributedIteratorMulti { -LL | | type Item; -LL | | } - | |_- trait `DistributedIteratorMulti` defined here -... -LL | multi(Map { - | ^^^^^ implementation of `DistributedIteratorMulti` is not general enough +LL | multi(Map { + | ^^^^^ implementation of `DistributedIteratorMulti` is not general enough | = note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`... = note: ...but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1` diff --git a/src/test/ui/where-clauses/where-for-self-2.stderr b/src/test/ui/where-clauses/where-for-self-2.stderr index 30eb78b2da4f7..4f8b19291db40 100644 --- a/src/test/ui/where-clauses/where-for-self-2.stderr +++ b/src/test/ui/where-clauses/where-for-self-2.stderr @@ -1,13 +1,8 @@ error: implementation of `Bar` is not general enough --> $DIR/where-for-self-2.rs:23:5 | -LL | / trait Bar { -LL | | fn bar(&self); -LL | | } - | |_- trait `Bar` defined here -... -LL | foo(&X); - | ^^^ implementation of `Bar` is not general enough +LL | foo(&X); + | ^^^ implementation of `Bar` is not general enough | = note: `Bar` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Bar` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` From daab6db1a02b680a71976fcbeed577ff102b31e4 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 9 Feb 2021 22:28:09 +0000 Subject: [PATCH 069/103] Avoid repeating self type in placeholder error --- .../nice_region_error/placeholder_error.rs | 20 +++++++++++++++++-- .../associated-types-eq-hr.stderr | 10 +++++----- src/test/ui/hrtb/hrtb-conflate-regions.stderr | 2 +- ...b-exists-forall-trait-contravariant.stderr | 2 +- .../hrtb-exists-forall-trait-invariant.stderr | 2 +- src/test/ui/hrtb/hrtb-just-for-static.stderr | 2 +- 6 files changed, 27 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index d99e79005fbb8..09be0b076705c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -370,6 +370,8 @@ impl NiceRegionError<'me, 'tcx> { value: trait_ref, }; + let same_self_type = actual_trait_ref.self_ty() == expected_trait_ref.self_ty(); + let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref); expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub); expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup); @@ -385,7 +387,16 @@ impl NiceRegionError<'me, 'tcx> { } }; - let mut note = if passive_voice { + let mut note = if same_self_type { + let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty()); + self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid); + format!( + "{}`{}` must implement `{}`", + if leading_ellipsis { "..." } else { "" }, + self_ty, + expected_trait_ref.map(|tr| tr.print_only_trait_path()), + ) + } else if passive_voice { format!( "{}`{}` would have to be implemented for the type `{}`", if leading_ellipsis { "..." } else { "" }, @@ -431,7 +442,12 @@ impl NiceRegionError<'me, 'tcx> { None => true, }; - let mut note = if passive_voice { + let mut note = if same_self_type { + format!( + "...but it actually implements `{}`", + actual_trait_ref.map(|tr| tr.print_only_trait_path()), + ) + } else if passive_voice { format!( "...but `{}` is actually implemented for the type `{}`", actual_trait_ref.map(|tr| tr.print_only_trait_path()), diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr index 6188d9ca979cf..6897b31fe4685 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.stderr +++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr @@ -35,7 +35,7 @@ LL | tuple_one::(); | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough | = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... - = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` + = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:96:5 @@ -44,7 +44,7 @@ LL | tuple_one::(); | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough | = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... - = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` + = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:102:5 @@ -53,7 +53,7 @@ LL | tuple_two::(); | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough | = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... - = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` + = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:102:5 @@ -62,7 +62,7 @@ LL | tuple_two::(); | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough | = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... - = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` + = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:112:5 @@ -71,7 +71,7 @@ LL | tuple_four::(); | ^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough | = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... - = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` + = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: aborting due to 7 previous errors diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.stderr index 7a0ede5af201c..b1d4c0bf37505 100644 --- a/src/test/ui/hrtb/hrtb-conflate-regions.stderr +++ b/src/test/ui/hrtb/hrtb-conflate-regions.stderr @@ -5,7 +5,7 @@ LL | fn b() { want_foo2::(); } | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... - = note: ...but `SomeStruct` actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` + = note: ...but it actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: aborting due to previous error diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr index 2f946c7d9bfe8..613f4dc4951ec 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr @@ -5,7 +5,7 @@ LL | foo::<()>(); | ^^^^^^^^^ implementation of `Trait` is not general enough | = note: `()` must implement `Trait fn(&'b u32)>` - = note: ...but `()` actually implements `Trait`, for some specific lifetime `'0` + = note: ...but it actually implements `Trait`, for some specific lifetime `'0` error: aborting due to previous error diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr index ba244e0f2ebc7..b487ce3e0ffa1 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr @@ -5,7 +5,7 @@ LL | foo::<()>(); | ^^^^^^^^^ implementation of `Trait` is not general enough | = note: `()` must implement `Trait fn(Cell<&'b u32>)>` - = note: ...but `()` actually implements `Trait)>`, for some specific lifetime `'0` + = note: ...but it actually implements `Trait)>`, for some specific lifetime `'0` error: aborting due to previous error diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr index 0d46a130e093e..38d7c12d4ec03 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr @@ -5,7 +5,7 @@ LL | want_hrtb::() | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`... - = note: ...but `StaticInt` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1` + = note: ...but it actually implements `Foo<&'1 isize>`, for some specific lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/hrtb-just-for-static.rs:30:5 From 94c11dfe78c9c2e81ababe51b04231db4c90d07f Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 9 Feb 2021 22:59:32 +0000 Subject: [PATCH 070/103] Report "nice" placeholder errors more often If we have a cause containing `ValuePairs::PolyTraitRefs` but neither TraitRef has any escaping bound regions then we report the same error as for `ValuePairs::TraitRefs`. --- .../nice_region_error/placeholder_error.rs | 142 +++++++++--------- .../hrtb/hrtb-perfect-forwarding.nll.stderr | 38 ++--- src/test/ui/hrtb/hrtb-perfect-forwarding.rs | 39 +++-- .../ui/hrtb/hrtb-perfect-forwarding.stderr | 41 ++--- src/test/ui/issues/issue-57843.nll.stderr | 2 +- src/test/ui/issues/issue-57843.rs | 6 +- src/test/ui/issues/issue-57843.stderr | 16 +- src/test/ui/lifetimes/issue-79187.rs | 2 +- src/test/ui/lifetimes/issue-79187.stderr | 19 +-- .../closure-arg-type-mismatch.rs | 4 +- .../closure-arg-type-mismatch.stderr | 36 +---- src/test/ui/rfc1623.rs | 2 +- src/test/ui/rfc1623.stderr | 9 +- .../issue-57611-trait-alias.nll.stderr | 13 +- .../issue-57611-trait-alias.rs | 6 +- .../issue-57611-trait-alias.stderr | 39 ++--- .../unboxed-closures/issue-30906.nll.stderr | 2 +- src/test/ui/unboxed-closures/issue-30906.rs | 12 +- .../ui/unboxed-closures/issue-30906.stderr | 16 +- 19 files changed, 181 insertions(+), 263 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 09be0b076705c..285666b7acb99 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -30,157 +30,153 @@ impl NiceRegionError<'me, 'tcx> { Some(RegionResolutionError::SubSupConflict( vid, _, - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), + SubregionOrigin::Subtype(box TypeTrace { cause, values }), sub_placeholder @ ty::RePlaceholder(_), _, sup_placeholder @ ty::RePlaceholder(_), - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( + )) => self.try_report_trait_placeholder_mismatch( Some(self.tcx().mk_region(ty::ReVar(*vid))), cause, Some(sub_placeholder), Some(sup_placeholder), - expected.def_id, - expected.substs, - found.substs, - )), + values, + ), Some(RegionResolutionError::SubSupConflict( vid, _, - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), + SubregionOrigin::Subtype(box TypeTrace { cause, values }), sub_placeholder @ ty::RePlaceholder(_), _, _, - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( + )) => self.try_report_trait_placeholder_mismatch( Some(self.tcx().mk_region(ty::ReVar(*vid))), cause, Some(sub_placeholder), None, - expected.def_id, - expected.substs, - found.substs, - )), + values, + ), Some(RegionResolutionError::SubSupConflict( vid, _, - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), + SubregionOrigin::Subtype(box TypeTrace { cause, values }), _, _, sup_placeholder @ ty::RePlaceholder(_), - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( + )) => self.try_report_trait_placeholder_mismatch( Some(self.tcx().mk_region(ty::ReVar(*vid))), cause, None, Some(*sup_placeholder), - expected.def_id, - expected.substs, - found.substs, - )), + values, + ), Some(RegionResolutionError::SubSupConflict( vid, _, _, _, - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), + SubregionOrigin::Subtype(box TypeTrace { cause, values }), sup_placeholder @ ty::RePlaceholder(_), - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( + )) => self.try_report_trait_placeholder_mismatch( Some(self.tcx().mk_region(ty::ReVar(*vid))), cause, None, Some(*sup_placeholder), - expected.def_id, - expected.substs, - found.substs, - )), + values, + ), Some(RegionResolutionError::UpperBoundUniverseConflict( vid, _, _, - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), + SubregionOrigin::Subtype(box TypeTrace { cause, values }), sup_placeholder @ ty::RePlaceholder(_), - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( + )) => self.try_report_trait_placeholder_mismatch( Some(self.tcx().mk_region(ty::ReVar(*vid))), cause, None, Some(*sup_placeholder), - expected.def_id, - expected.substs, - found.substs, - )), + values, + ), Some(RegionResolutionError::ConcreteFailure( - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), + SubregionOrigin::Subtype(box TypeTrace { cause, values }), sub_region @ ty::RePlaceholder(_), sup_region @ ty::RePlaceholder(_), - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( + )) => self.try_report_trait_placeholder_mismatch( None, cause, Some(*sub_region), Some(*sup_region), - expected.def_id, - expected.substs, - found.substs, - )), + values, + ), Some(RegionResolutionError::ConcreteFailure( - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), + SubregionOrigin::Subtype(box TypeTrace { cause, values }), sub_region @ ty::RePlaceholder(_), sup_region, - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( + )) => self.try_report_trait_placeholder_mismatch( Some(sup_region), cause, Some(*sub_region), None, - expected.def_id, - expected.substs, - found.substs, - )), + values, + ), Some(RegionResolutionError::ConcreteFailure( - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), + SubregionOrigin::Subtype(box TypeTrace { cause, values }), sub_region, sup_region @ ty::RePlaceholder(_), - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( + )) => self.try_report_trait_placeholder_mismatch( Some(sub_region), cause, None, Some(*sup_region), - expected.def_id, - expected.substs, - found.substs, - )), + values, + ), _ => None, } } + fn try_report_trait_placeholder_mismatch( + &self, + vid: Option>, + cause: &ObligationCause<'tcx>, + sub_placeholder: Option>, + sup_placeholder: Option>, + value_pairs: &ValuePairs<'tcx>, + ) -> Option> { + let (expected_substs, found_substs, trait_def_id) = match value_pairs { + ValuePairs::TraitRefs(ExpectedFound { expected, found }) + if expected.def_id == found.def_id => + { + (expected.substs, found.substs, expected.def_id) + } + ValuePairs::PolyTraitRefs(ExpectedFound { expected, found }) + if expected.def_id() == found.def_id() => + { + // It's possible that the placeholders come from a binder + // outside of this value pair. Use `no_bound_vars` as a + // simple heuristic for that. + (expected.no_bound_vars()?.substs, found.no_bound_vars()?.substs, expected.def_id()) + } + _ => return None, + }; + + Some(self.report_trait_placeholder_mismatch( + vid, + cause, + sub_placeholder, + sup_placeholder, + trait_def_id, + expected_substs, + found_substs, + )) + } + // error[E0308]: implementation of `Foo` does not apply to enough lifetimes // --> /home/nmatsakis/tmp/foo.rs:12:5 // | @@ -191,7 +187,7 @@ impl NiceRegionError<'me, 'tcx> { // = note: `T` must implement `...` for any two lifetimes `'1` and `'2`. // = note: However, the type `T` only implements `...` for some specific lifetime `'2`. #[instrument(level = "debug", skip(self))] - fn try_report_placeholders_trait( + fn report_trait_placeholder_mismatch( &self, vid: Option>, cause: &ObligationCause<'tcx>, diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr index edce0e6702ee1..c3dd794957540 100644 --- a/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr +++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr @@ -1,11 +1,11 @@ warning: function cannot return without recursing - --> $DIR/hrtb-perfect-forwarding.rs:22:1 + --> $DIR/hrtb-perfect-forwarding.rs:16:1 | -LL | / fn no_hrtb<'b,T>(mut t: T) -LL | | where T : Bar<&'b isize> +LL | / fn no_hrtb<'b, T>(mut t: T) +LL | | where +LL | | T: Bar<&'b isize>, LL | | { -LL | | // OK -- `T : Bar<&'b isize>`, and thus the impl above ensures that -LL | | // `&mut T : Bar<&'b isize>`. +... | LL | | no_hrtb(&mut t); | | --------------- recursive call site LL | | } @@ -15,12 +15,12 @@ LL | | } = help: a `loop` may express intention better if this is on purpose warning: function cannot return without recursing - --> $DIR/hrtb-perfect-forwarding.rs:30:1 + --> $DIR/hrtb-perfect-forwarding.rs:25:1 | LL | / fn bar_hrtb(mut t: T) -LL | | where T : for<'b> Bar<&'b isize> +LL | | where +LL | | T: for<'b> Bar<&'b isize>, LL | | { -LL | | // OK -- `T : for<'b> Bar<&'b isize>`, and thus the impl above ... | LL | | bar_hrtb(&mut t); | | ---------------- recursive call site @@ -30,25 +30,26 @@ LL | | } = help: a `loop` may express intention better if this is on purpose warning: function cannot return without recursing - --> $DIR/hrtb-perfect-forwarding.rs:39:1 + --> $DIR/hrtb-perfect-forwarding.rs:35:1 | -LL | / fn foo_hrtb_bar_not<'b,T>(mut t: T) -LL | | where T : for<'a> Foo<&'a isize> + Bar<&'b isize> +LL | / fn foo_hrtb_bar_not<'b, T>(mut t: T) +LL | | where +LL | | T: for<'a> Foo<&'a isize> + Bar<&'b isize>, LL | | { -LL | | // Not OK -- The forwarding impl for `Foo` requires that `Bar` also ... | LL | | foo_hrtb_bar_not(&mut t); | | ------------------------ recursive call site LL | | +LL | | LL | | } | |_^ cannot return without recursing | = help: a `loop` may express intention better if this is on purpose error: lifetime may not live long enough - --> $DIR/hrtb-perfect-forwarding.rs:46:5 + --> $DIR/hrtb-perfect-forwarding.rs:43:5 | -LL | fn foo_hrtb_bar_not<'b,T>(mut t: T) +LL | fn foo_hrtb_bar_not<'b, T>(mut t: T) | -- lifetime `'b` defined here ... LL | foo_hrtb_bar_not(&mut t); @@ -57,18 +58,19 @@ LL | foo_hrtb_bar_not(&mut t); = help: consider replacing `'b` with `'static` error: higher-ranked subtype error - --> $DIR/hrtb-perfect-forwarding.rs:46:5 + --> $DIR/hrtb-perfect-forwarding.rs:43:5 | LL | foo_hrtb_bar_not(&mut t); | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: function cannot return without recursing - --> $DIR/hrtb-perfect-forwarding.rs:50:1 + --> $DIR/hrtb-perfect-forwarding.rs:48:1 | LL | / fn foo_hrtb_bar_hrtb(mut t: T) -LL | | where T : for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize> +LL | | where +LL | | T: for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>, LL | | { -LL | | // OK -- now we have `T : for<'b> Bar&'b isize>`. +LL | | // OK -- now we have `T : for<'b> Bar<&'b isize>`. LL | | foo_hrtb_bar_hrtb(&mut t); | | ------------------------- recursive call site LL | | } diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.rs b/src/test/ui/hrtb/hrtb-perfect-forwarding.rs index 0303a764c12de..441a788359e03 100644 --- a/src/test/ui/hrtb/hrtb-perfect-forwarding.rs +++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.rs @@ -2,25 +2,20 @@ // is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730. trait Foo { - fn foo(&mut self, x: X) { } + fn foo(&mut self, x: X) {} } trait Bar { - fn bar(&mut self, x: X) { } + fn bar(&mut self, x: X) {} } -impl<'a,X,F> Foo for &'a mut F - where F : Foo + Bar -{ -} +impl<'a, X, F> Foo for &'a mut F where F: Foo + Bar {} -impl<'a,X,F> Bar for &'a mut F - where F : Bar -{ -} +impl<'a, X, F> Bar for &'a mut F where F: Bar {} -fn no_hrtb<'b,T>(mut t: T) - where T : Bar<&'b isize> +fn no_hrtb<'b, T>(mut t: T) +where + T: Bar<&'b isize>, { // OK -- `T : Bar<&'b isize>`, and thus the impl above ensures that // `&mut T : Bar<&'b isize>`. @@ -28,7 +23,8 @@ fn no_hrtb<'b,T>(mut t: T) } fn bar_hrtb(mut t: T) - where T : for<'b> Bar<&'b isize> +where + T: for<'b> Bar<&'b isize>, { // OK -- `T : for<'b> Bar<&'b isize>`, and thus the impl above // ensures that `&mut T : for<'b> Bar<&'b isize>`. This is an @@ -36,22 +32,25 @@ fn bar_hrtb(mut t: T) bar_hrtb(&mut t); } -fn foo_hrtb_bar_not<'b,T>(mut t: T) - where T : for<'a> Foo<&'a isize> + Bar<&'b isize> +fn foo_hrtb_bar_not<'b, T>(mut t: T) +where + T: for<'a> Foo<&'a isize> + Bar<&'b isize>, { // Not OK -- The forwarding impl for `Foo` requires that `Bar` also // be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a // isize>`, we require `T : for<'a> Bar<&'a isize>`, but the where // clause only specifies `T : Bar<&'b isize>`. - foo_hrtb_bar_not(&mut t); //~ ERROR mismatched types - //~| ERROR mismatched types + foo_hrtb_bar_not(&mut t); + //~^ ERROR implementation of `Bar` is not general enough + //~| ERROR implementation of `Bar` is not general enough } fn foo_hrtb_bar_hrtb(mut t: T) - where T : for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize> +where + T: for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>, { - // OK -- now we have `T : for<'b> Bar&'b isize>`. + // OK -- now we have `T : for<'b> Bar<&'b isize>`. foo_hrtb_bar_hrtb(&mut t); } -fn main() { } +fn main() {} diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr index ed810d443bef7..e265f53cd2a7f 100644 --- a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr +++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr @@ -1,41 +1,20 @@ -error[E0308]: mismatched types - --> $DIR/hrtb-perfect-forwarding.rs:46:5 +error: implementation of `Bar` is not general enough + --> $DIR/hrtb-perfect-forwarding.rs:43:5 | LL | foo_hrtb_bar_not(&mut t); - | ^^^^^^^^^^^^^^^^ lifetime mismatch + | ^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough | - = note: expected type `Bar<&'a isize>` - found type `Bar<&'b isize>` -note: the required lifetime does not necessarily outlive the lifetime `'b` as defined on the function body at 39:21 - --> $DIR/hrtb-perfect-forwarding.rs:39:21 - | -LL | fn foo_hrtb_bar_not<'b,T>(mut t: T) - | ^^ -note: the lifetime requirement is introduced here - --> $DIR/hrtb-perfect-forwarding.rs:40:15 - | -LL | where T : for<'a> Foo<&'a isize> + Bar<&'b isize> - | ^^^^^^^^^^^^^^^^^^^^^^ + = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`... + = note: ...but it actually implements `Bar<&'1 isize>`, for some specific lifetime `'1` -error[E0308]: mismatched types - --> $DIR/hrtb-perfect-forwarding.rs:46:5 +error: implementation of `Bar` is not general enough + --> $DIR/hrtb-perfect-forwarding.rs:43:5 | LL | foo_hrtb_bar_not(&mut t); - | ^^^^^^^^^^^^^^^^ lifetime mismatch - | - = note: expected type `Bar<&'a isize>` - found type `Bar<&'b isize>` -note: the lifetime `'b` as defined on the function body at 39:21 doesn't meet the lifetime requirements - --> $DIR/hrtb-perfect-forwarding.rs:39:21 - | -LL | fn foo_hrtb_bar_not<'b,T>(mut t: T) - | ^^ -note: the lifetime requirement is introduced here - --> $DIR/hrtb-perfect-forwarding.rs:40:15 + | ^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough | -LL | where T : for<'a> Foo<&'a isize> + Bar<&'b isize> - | ^^^^^^^^^^^^^^^^^^^^^^ + = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`... + = note: ...but it actually implements `Bar<&'1 isize>`, for some specific lifetime `'1` error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-57843.nll.stderr b/src/test/ui/issues/issue-57843.nll.stderr index 70310780b4330..70d16cc9a1da6 100644 --- a/src/test/ui/issues/issue-57843.nll.stderr +++ b/src/test/ui/issues/issue-57843.nll.stderr @@ -1,5 +1,5 @@ error: higher-ranked subtype error - --> $DIR/issue-57843.rs:23:9 + --> $DIR/issue-57843.rs:25:9 | LL | Foo(Box::new(|_| ())); | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-57843.rs b/src/test/ui/issues/issue-57843.rs index 466082552667b..11629690ecc5e 100644 --- a/src/test/ui/issues/issue-57843.rs +++ b/src/test/ui/issues/issue-57843.rs @@ -11,7 +11,9 @@ trait ClonableFn { } impl ClonableFn for F -where F: Fn(T) + Clone { +where + F: Fn(T) + Clone, +{ fn clone(&self) -> Box { Box::new(self.clone()) } @@ -20,5 +22,5 @@ where F: Fn(T) + Clone { struct Foo(Box ClonableFn<&'a bool>>); fn main() { - Foo(Box::new(|_| ())); //~ ERROR mismatched types + Foo(Box::new(|_| ())); //~ ERROR implementation of `FnOnce` is not general enough } diff --git a/src/test/ui/issues/issue-57843.stderr b/src/test/ui/issues/issue-57843.stderr index 7699e97da99ad..acd48b6c7e5ba 100644 --- a/src/test/ui/issues/issue-57843.stderr +++ b/src/test/ui/issues/issue-57843.stderr @@ -1,17 +1,11 @@ -error[E0308]: mismatched types - --> $DIR/issue-57843.rs:23:9 +error: implementation of `FnOnce` is not general enough + --> $DIR/issue-57843.rs:25:9 | LL | Foo(Box::new(|_| ())); - | ^^^^^^^^^^^^^^^^ one type is more general than the other + | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: expected type `FnOnce<(&'a bool,)>` - found type `FnOnce<(&bool,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57843.rs:23:18 - | -LL | Foo(Box::new(|_| ())); - | ^^^^^^ + = note: `[closure@$DIR/issue-57843.rs:25:18: 25:24]` must implement `FnOnce<(&'1 bool,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 bool,)>`, for some specific lifetime `'2` error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/lifetimes/issue-79187.rs b/src/test/ui/lifetimes/issue-79187.rs index bf331d8a6068e..2ee69ee2234ee 100644 --- a/src/test/ui/lifetimes/issue-79187.rs +++ b/src/test/ui/lifetimes/issue-79187.rs @@ -2,5 +2,5 @@ fn thing(x: impl FnOnce(&u32)) {} fn main() { let f = |_| (); - thing(f); //~ERROR mismatched types + thing(f); //~ERROR implementation of `FnOnce` is not general enough } diff --git a/src/test/ui/lifetimes/issue-79187.stderr b/src/test/ui/lifetimes/issue-79187.stderr index 63f501e08fce4..3627ab5ed1e97 100644 --- a/src/test/ui/lifetimes/issue-79187.stderr +++ b/src/test/ui/lifetimes/issue-79187.stderr @@ -1,22 +1,11 @@ -error[E0308]: mismatched types +error: implementation of `FnOnce` is not general enough --> $DIR/issue-79187.rs:5:5 | LL | thing(f); - | ^^^^^ lifetime mismatch + | ^^^^^ implementation of `FnOnce` is not general enough | - = note: expected type `FnOnce<(&u32,)>` - found type `FnOnce<(&u32,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-79187.rs:4:13 - | -LL | let f = |_| (); - | ^^^^^^ -note: the lifetime requirement is introduced here - --> $DIR/issue-79187.rs:1:18 - | -LL | fn thing(x: impl FnOnce(&u32)) {} - | ^^^^^^^^^^^^ + = note: `[closure@$DIR/issue-79187.rs:4:13: 4:19]` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2` error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs index e278049c8cc42..2d485d14a8d6b 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs @@ -8,8 +8,8 @@ fn main() { fn baz(_: F) {} fn _test<'a>(f: fn(*mut &'a u32)) { baz(f); - //~^ ERROR mismatched types - //~| ERROR mismatched types + //~^ ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough //~| ERROR mismatched types //~| ERROR mismatched types } diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr index 02ba60f7f4b73..67c5a68ed83c6 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -41,24 +41,14 @@ note: the lifetime requirement is introduced here LL | fn baz(_: F) {} | ^^^^^^^^^^^^^ -error[E0308]: mismatched types +error: implementation of `FnOnce` is not general enough --> $DIR/closure-arg-type-mismatch.rs:10:5 | LL | baz(f); - | ^^^ lifetime mismatch - | - = note: expected type `FnOnce<(*mut &u32,)>` - found type `FnOnce<(*mut &'a u32,)>` -note: the required lifetime does not necessarily outlive the lifetime `'a` as defined on the function body at 9:10 - --> $DIR/closure-arg-type-mismatch.rs:9:10 - | -LL | fn _test<'a>(f: fn(*mut &'a u32)) { - | ^^ -note: the lifetime requirement is introduced here - --> $DIR/closure-arg-type-mismatch.rs:8:11 + | ^^^ implementation of `FnOnce` is not general enough | -LL | fn baz(_: F) {} - | ^^^^^^^^^^^^^ + = note: `fn(*mut &'2 u32)` must implement `FnOnce<(*mut &'1 u32,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(*mut &'2 u32,)>`, for some specific lifetime `'2` error[E0308]: mismatched types --> $DIR/closure-arg-type-mismatch.rs:10:5 @@ -79,24 +69,14 @@ note: the lifetime requirement is introduced here LL | fn baz(_: F) {} | ^^^^^^^^^^^^^ -error[E0308]: mismatched types +error: implementation of `FnOnce` is not general enough --> $DIR/closure-arg-type-mismatch.rs:10:5 | LL | baz(f); - | ^^^ lifetime mismatch - | - = note: expected type `FnOnce<(*mut &u32,)>` - found type `FnOnce<(*mut &'a u32,)>` -note: the lifetime `'a` as defined on the function body at 9:10 doesn't meet the lifetime requirements - --> $DIR/closure-arg-type-mismatch.rs:9:10 - | -LL | fn _test<'a>(f: fn(*mut &'a u32)) { - | ^^ -note: the lifetime requirement is introduced here - --> $DIR/closure-arg-type-mismatch.rs:8:11 + | ^^^ implementation of `FnOnce` is not general enough | -LL | fn baz(_: F) {} - | ^^^^^^^^^^^^^ + = note: `fn(*mut &'2 u32)` must implement `FnOnce<(*mut &'1 u32,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(*mut &'2 u32,)>`, for some specific lifetime `'2` error: aborting due to 7 previous errors diff --git a/src/test/ui/rfc1623.rs b/src/test/ui/rfc1623.rs index aa6b1c0012c93..9ff4813d11286 100644 --- a/src/test/ui/rfc1623.rs +++ b/src/test/ui/rfc1623.rs @@ -22,7 +22,7 @@ static SOME_STRUCT: &SomeStruct = &SomeStruct { foo: &Foo { bools: &[false, true] }, bar: &Bar { bools: &[true, true] }, f: &id, - //~^ ERROR mismatched types + //~^ ERROR implementation of `FnOnce` is not general enough }; // very simple test for a 'static static with default lifetime diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index 2835e47fa4515..e95e68c8e6d26 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -1,12 +1,11 @@ -error[E0308]: mismatched types +error: implementation of `FnOnce` is not general enough --> $DIR/rfc1623.rs:24:8 | LL | f: &id, - | ^^^ one type is more general than the other + | ^^^ implementation of `FnOnce` is not general enough | - = note: expected type `FnOnce<(&'a Foo<'b>,)>` - found type `FnOnce<(&Foo<'_>,)>` + = note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2` error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr index be1dd1a8524c8..59b14eedc24ba 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr @@ -24,19 +24,14 @@ note: this closure does not fulfill the lifetime requirements LL | |x| x | ^^^^^ -error[E0308]: mismatched types +error: implementation of `FnOnce` is not general enough --> $DIR/issue-57611-trait-alias.rs:17:16 | LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: expected type `FnOnce<(&X,)>` - found type `FnOnce<(&'static X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:25:9 - | -LL | |x| x - | ^^^^^ + = note: `[closure@$DIR/issue-57611-trait-alias.rs:25:9: 25:14]` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` error: aborting due to 4 previous errors diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs index 3372b81404ecb..561528c2abbd5 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs @@ -15,9 +15,9 @@ struct X; impl Foo for X { type Bar = impl Baz; - //~^ ERROR mismatched types - //~| ERROR mismatched types - //~| ERROR mismatched types + //~^ ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough //~| ERROR mismatched types //~| ERROR mismatched types diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr index 9d9293e958eeb..59c91d52cca98 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr @@ -1,16 +1,11 @@ -error[E0308]: mismatched types +error: implementation of `FnOnce` is not general enough --> $DIR/issue-57611-trait-alias.rs:17:16 | LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected type `FnOnce<(&X,)>` - found type `FnOnce<(&X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:25:9 + | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | -LL | |x| x - | ^^^^^ + = note: `[closure@$DIR/issue-57611-trait-alias.rs:25:9: 25:14]` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` error[E0308]: mismatched types --> $DIR/issue-57611-trait-alias.rs:17:16 @@ -26,19 +21,14 @@ note: this closure does not fulfill the lifetime requirements LL | |x| x | ^^^^^ -error[E0308]: mismatched types +error: implementation of `FnOnce` is not general enough --> $DIR/issue-57611-trait-alias.rs:17:16 | LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: expected type `FnOnce<(&X,)>` - found type `FnOnce<(&' X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:25:9 - | -LL | |x| x - | ^^^^^ + = note: `[closure@$DIR/issue-57611-trait-alias.rs:25:9: 25:14]` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` error[E0308]: mismatched types --> $DIR/issue-57611-trait-alias.rs:17:16 @@ -54,19 +44,14 @@ note: this closure does not fulfill the lifetime requirements LL | |x| x | ^^^^^ -error[E0308]: mismatched types +error: implementation of `FnOnce` is not general enough --> $DIR/issue-57611-trait-alias.rs:17:16 | LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: expected type `FnOnce<(&X,)>` - found type `FnOnce<(&' X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:25:9 - | -LL | |x| x - | ^^^^^ + = note: `[closure@$DIR/issue-57611-trait-alias.rs:25:9: 25:14]` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` error: aborting due to 5 previous errors diff --git a/src/test/ui/unboxed-closures/issue-30906.nll.stderr b/src/test/ui/unboxed-closures/issue-30906.nll.stderr index 5a2cbab9a1500..2db392e8b8b9f 100644 --- a/src/test/ui/unboxed-closures/issue-30906.nll.stderr +++ b/src/test/ui/unboxed-closures/issue-30906.nll.stderr @@ -1,5 +1,5 @@ error: higher-ranked subtype error - --> $DIR/issue-30906.rs:15:5 + --> $DIR/issue-30906.rs:18:5 | LL | test(Compose(f, |_| {})); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/unboxed-closures/issue-30906.rs b/src/test/ui/unboxed-closures/issue-30906.rs index 03cce83277515..e2d219e470384 100644 --- a/src/test/ui/unboxed-closures/issue-30906.rs +++ b/src/test/ui/unboxed-closures/issue-30906.rs @@ -2,9 +2,12 @@ fn test FnOnce<(&'x str,)>>(_: F) {} -struct Compose(F,G); -impl FnOnce<(T,)> for Compose -where F: FnOnce<(T,)>, G: FnOnce<(F::Output,)> { +struct Compose(F, G); +impl FnOnce<(T,)> for Compose +where + F: FnOnce<(T,)>, + G: FnOnce<(F::Output,)>, +{ type Output = G::Output; extern "rust-call" fn call_once(self, (x,): (T,)) -> G::Output { (self.1)((self.0)(x)) @@ -12,7 +15,8 @@ where F: FnOnce<(T,)>, G: FnOnce<(F::Output,)> { } fn bad(f: fn(&'static str) -> T) { - test(Compose(f, |_| {})); //~ ERROR: mismatched types + test(Compose(f, |_| {})); + //~^ ERROR: implementation of `FnOnce` is not general enough } fn main() {} diff --git a/src/test/ui/unboxed-closures/issue-30906.stderr b/src/test/ui/unboxed-closures/issue-30906.stderr index ecf3a96b5a8dc..35b1e454c02b4 100644 --- a/src/test/ui/unboxed-closures/issue-30906.stderr +++ b/src/test/ui/unboxed-closures/issue-30906.stderr @@ -1,17 +1,11 @@ -error[E0308]: mismatched types - --> $DIR/issue-30906.rs:15:5 +error: implementation of `FnOnce` is not general enough + --> $DIR/issue-30906.rs:18:5 | LL | test(Compose(f, |_| {})); - | ^^^^ lifetime mismatch + | ^^^^ implementation of `FnOnce` is not general enough | - = note: expected type `FnOnce<(&'x str,)>` - found type `FnOnce<(&str,)>` -note: the lifetime requirement is introduced here - --> $DIR/issue-30906.rs:3:12 - | -LL | fn test FnOnce<(&'x str,)>>(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `fn(&'2 str) -> T` must implement `FnOnce<(&'1 str,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 str,)>`, for some specific lifetime `'2` error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. From 9337d4fde89ded13243d67bec0b03f7fc553cbf9 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 9 Feb 2021 23:00:33 +0000 Subject: [PATCH 071/103] Print closure signatures when reporting placeholder errors --- .../nice_region_error/placeholder_error.rs | 38 ++++++++++++++++--- src/test/ui/issues/issue-57843.stderr | 2 +- src/test/ui/lifetimes/issue-79187.stderr | 2 +- .../issue-57611-trait-alias.nll.stderr | 2 +- .../issue-57611-trait-alias.stderr | 6 +-- 5 files changed, 38 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 285666b7acb99..46986d8d58b64 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -386,12 +386,38 @@ impl NiceRegionError<'me, 'tcx> { let mut note = if same_self_type { let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty()); self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid); - format!( - "{}`{}` must implement `{}`", - if leading_ellipsis { "..." } else { "" }, - self_ty, - expected_trait_ref.map(|tr| tr.print_only_trait_path()), - ) + + if self_ty.value.is_closure() + && self + .tcx() + .fn_trait_kind_from_lang_item(expected_trait_ref.value.def_id) + .is_some() + { + let closure_sig = self_ty.map(|closure| { + if let ty::Closure(_, substs) = closure.kind() { + self.tcx().signature_unclosure( + substs.as_closure().sig(), + rustc_hir::Unsafety::Normal, + ) + } else { + bug!("type is not longer closure"); + } + }); + + format!( + "{}closure with signature `{}` must implement `{}`", + if leading_ellipsis { "..." } else { "" }, + closure_sig, + expected_trait_ref.map(|tr| tr.print_only_trait_path()), + ) + } else { + format!( + "{}`{}` must implement `{}`", + if leading_ellipsis { "..." } else { "" }, + self_ty, + expected_trait_ref.map(|tr| tr.print_only_trait_path()), + ) + } } else if passive_voice { format!( "{}`{}` would have to be implemented for the type `{}`", diff --git a/src/test/ui/issues/issue-57843.stderr b/src/test/ui/issues/issue-57843.stderr index acd48b6c7e5ba..2ab49ec61cf59 100644 --- a/src/test/ui/issues/issue-57843.stderr +++ b/src/test/ui/issues/issue-57843.stderr @@ -4,7 +4,7 @@ error: implementation of `FnOnce` is not general enough LL | Foo(Box::new(|_| ())); | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: `[closure@$DIR/issue-57843.rs:25:18: 25:24]` must implement `FnOnce<(&'1 bool,)>`, for any lifetime `'1`... + = note: closure with signature `fn(&'2 bool)` must implement `FnOnce<(&'1 bool,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 bool,)>`, for some specific lifetime `'2` error: aborting due to previous error diff --git a/src/test/ui/lifetimes/issue-79187.stderr b/src/test/ui/lifetimes/issue-79187.stderr index 3627ab5ed1e97..3c0439fb660e5 100644 --- a/src/test/ui/lifetimes/issue-79187.stderr +++ b/src/test/ui/lifetimes/issue-79187.stderr @@ -4,7 +4,7 @@ error: implementation of `FnOnce` is not general enough LL | thing(f); | ^^^^^ implementation of `FnOnce` is not general enough | - = note: `[closure@$DIR/issue-79187.rs:4:13: 4:19]` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... + = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2` error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr index 59b14eedc24ba..a5409582288f2 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr @@ -30,7 +30,7 @@ error: implementation of `FnOnce` is not general enough LL | type Bar = impl Baz; | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: `[closure@$DIR/issue-57611-trait-alias.rs:25:9: 25:14]` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... + = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` error: aborting due to 4 previous errors diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr index 59c91d52cca98..91c9d459ad8ce 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr @@ -4,7 +4,7 @@ error: implementation of `FnOnce` is not general enough LL | type Bar = impl Baz; | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: `[closure@$DIR/issue-57611-trait-alias.rs:25:9: 25:14]` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... + = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` error[E0308]: mismatched types @@ -27,7 +27,7 @@ error: implementation of `FnOnce` is not general enough LL | type Bar = impl Baz; | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: `[closure@$DIR/issue-57611-trait-alias.rs:25:9: 25:14]` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... + = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` error[E0308]: mismatched types @@ -50,7 +50,7 @@ error: implementation of `FnOnce` is not general enough LL | type Bar = impl Baz; | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: `[closure@$DIR/issue-57611-trait-alias.rs:25:9: 25:14]` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... + = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` error: aborting due to 5 previous errors 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 072/103] 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 073/103] 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 074/103] 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 f852160a99721f89a6bc206bae337291c485069e Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 10 Feb 2021 20:00:36 +0000 Subject: [PATCH 075/103] Keep existing names of regions in placeholder_error --- .../nice_region_error/placeholder_error.rs | 8 ++++---- src/test/ui/generator/auto-trait-regions.stderr | 8 ++++---- src/test/ui/hrtb/hrtb-just-for-static.stderr | 2 +- src/test/ui/hrtb/hrtb-perfect-forwarding.stderr | 4 ++-- .../ui/mismatched_types/closure-arg-type-mismatch.stderr | 8 ++++---- .../issue-57611-trait-alias.nll.stderr | 4 ++-- src/test/ui/where-clauses/where-for-self-2.stderr | 4 ++-- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 46986d8d58b64..4aecc2f40b874 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -118,9 +118,9 @@ impl NiceRegionError<'me, 'tcx> { sub_region @ ty::RePlaceholder(_), sup_region, )) => self.try_report_trait_placeholder_mismatch( - Some(sup_region), + (!sup_region.has_name()).then_some(sup_region), cause, - Some(*sub_region), + Some(sub_region), None, values, ), @@ -130,10 +130,10 @@ impl NiceRegionError<'me, 'tcx> { sub_region, sup_region @ ty::RePlaceholder(_), )) => self.try_report_trait_placeholder_mismatch( - Some(sub_region), + (!sub_region.has_name()).then_some(sub_region), cause, None, - Some(*sup_region), + Some(sup_region), values, ), diff --git a/src/test/ui/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr index 5fe4193905c72..da3d3249f0e7e 100644 --- a/src/test/ui/generator/auto-trait-regions.stderr +++ b/src/test/ui/generator/auto-trait-regions.stderr @@ -4,8 +4,8 @@ error: implementation of `Foo` is not general enough LL | assert_foo(gen); | ^^^^^^^^^^ implementation of `Foo` is not general enough | - = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`... - = note: ...but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1` + = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... + = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef` error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:31:5 @@ -13,8 +13,8 @@ error: implementation of `Foo` is not general enough LL | assert_foo(gen); | ^^^^^^^^^^ implementation of `Foo` is not general enough | - = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`... - = note: ...but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1` + = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... + = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef` error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:50:5 diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr index 38d7c12d4ec03..ffc83aab4af4d 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr @@ -5,7 +5,7 @@ LL | want_hrtb::() | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`... - = note: ...but it actually implements `Foo<&'1 isize>`, for some specific lifetime `'1` + = note: ...but it actually implements `Foo<&'static isize>` error: implementation of `Foo` is not general enough --> $DIR/hrtb-just-for-static.rs:30:5 diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr index e265f53cd2a7f..07ff9b96e44ff 100644 --- a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr +++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr @@ -5,7 +5,7 @@ LL | foo_hrtb_bar_not(&mut t); | ^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough | = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`... - = note: ...but it actually implements `Bar<&'1 isize>`, for some specific lifetime `'1` + = note: ...but it actually implements `Bar<&'b isize>` error: implementation of `Bar` is not general enough --> $DIR/hrtb-perfect-forwarding.rs:43:5 @@ -14,7 +14,7 @@ LL | foo_hrtb_bar_not(&mut t); | ^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough | = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`... - = note: ...but it actually implements `Bar<&'1 isize>`, for some specific lifetime `'1` + = note: ...but it actually implements `Bar<&'b isize>` error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr index 67c5a68ed83c6..521de3742b03f 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -47,8 +47,8 @@ error: implementation of `FnOnce` is not general enough LL | baz(f); | ^^^ implementation of `FnOnce` is not general enough | - = note: `fn(*mut &'2 u32)` must implement `FnOnce<(*mut &'1 u32,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(*mut &'2 u32,)>`, for some specific lifetime `'2` + = note: `fn(*mut &'a u32)` must implement `FnOnce<(*mut &'0 u32,)>`, for any lifetime `'0`... + = note: ...but it actually implements `FnOnce<(*mut &'a u32,)>` error[E0308]: mismatched types --> $DIR/closure-arg-type-mismatch.rs:10:5 @@ -75,8 +75,8 @@ error: implementation of `FnOnce` is not general enough LL | baz(f); | ^^^ implementation of `FnOnce` is not general enough | - = note: `fn(*mut &'2 u32)` must implement `FnOnce<(*mut &'1 u32,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(*mut &'2 u32,)>`, for some specific lifetime `'2` + = note: `fn(*mut &'a u32)` must implement `FnOnce<(*mut &'0 u32,)>`, for any lifetime `'0`... + = note: ...but it actually implements `FnOnce<(*mut &'a u32,)>` error: aborting due to 7 previous errors diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr index a5409582288f2..998e178966a22 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr @@ -30,8 +30,8 @@ error: implementation of `FnOnce` is not general enough LL | type Bar = impl Baz; | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` + = note: closure with signature `fn(&'static X) -> &'static X` must implement `FnOnce<(&'0 X,)>`, for any lifetime `'0`... + = note: ...but it actually implements `FnOnce<(&'static X,)>` error: aborting due to 4 previous errors diff --git a/src/test/ui/where-clauses/where-for-self-2.stderr b/src/test/ui/where-clauses/where-for-self-2.stderr index 4f8b19291db40..6da46e20c09c0 100644 --- a/src/test/ui/where-clauses/where-for-self-2.stderr +++ b/src/test/ui/where-clauses/where-for-self-2.stderr @@ -4,8 +4,8 @@ error: implementation of `Bar` is not general enough LL | foo(&X); | ^^^ implementation of `Bar` is not general enough | - = note: `Bar` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... - = note: ...but `Bar` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` + = note: `&'0 u32` must implement `Bar`, for any lifetime `'0`... + = note: ...but `Bar` is actually implemented for the type `&'static u32` error: aborting due to previous error 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 076/103] 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 077/103] 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 078/103] 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 079/103] 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 080/103] 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 081/103] 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"] From dfa581ff8747c1d5804a08e8201031a37c2ea14a Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 11 Feb 2021 20:46:58 +0000 Subject: [PATCH 082/103] Fix pretty printing of generic associated type constraints --- compiler/rustc_ast_pretty/src/pprust/state.rs | 1 + src/test/pretty/gat-bounds.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 01e234c9be972..cbeaa6018d149 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -914,6 +914,7 @@ impl<'a> State<'a> { pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) { self.print_ident(constraint.ident); + constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false)); self.s.space(); match &constraint.kind { ast::AssocTyConstraintKind::Equality { ty } => { diff --git a/src/test/pretty/gat-bounds.rs b/src/test/pretty/gat-bounds.rs index 789e4bc80ace9..8877c6cc9927b 100644 --- a/src/test/pretty/gat-bounds.rs +++ b/src/test/pretty/gat-bounds.rs @@ -13,4 +13,6 @@ impl X for () { type Y where Self: Sized = u32; } +fn f = i32>>() {} + fn main() { } From 9bbd3e0f8e51beb4c3ea6674327b17cd9d38d9da Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 11 Feb 2021 21:02:27 +0000 Subject: [PATCH 083/103] Remove ProjectionTy::from_ref_and_name --- compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_middle/src/ty/sty.rs | 16 ---------------- compiler/rustc_trait_selection/src/autoderef.rs | 10 ++++------ library/core/src/ops/deref.rs | 1 + 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 26ce30cb51177..a5222e5c70237 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -238,6 +238,7 @@ language_item_table! { Deref, sym::deref, deref_trait, Target::Trait; DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait; + DerefTarget, sym::deref_target, deref_target, Target::AssocTy; Receiver, sym::receiver, receiver_trait, Target::Trait; Fn, kw::Fn, fn_trait, Target::Trait; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 04cc4db0bcf64..8a8e70f76ced3 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1112,22 +1112,6 @@ pub struct ProjectionTy<'tcx> { } impl<'tcx> ProjectionTy<'tcx> { - /// Construct a `ProjectionTy` by searching the trait from `trait_ref` for the - /// associated item named `item_name`. - pub fn from_ref_and_name( - tcx: TyCtxt<'_>, - trait_ref: ty::TraitRef<'tcx>, - item_name: Ident, - ) -> ProjectionTy<'tcx> { - let item_def_id = tcx - .associated_items(trait_ref.def_id) - .find_by_name_and_kind(tcx, item_name, ty::AssocKind::Type, trait_ref.def_id) - .unwrap() - .def_id; - - ProjectionTy { substs: trait_ref.substs, item_def_id } - } - /// Extracts the underlying trait reference from this projection. /// For example, if this is a projection of `::Item`, /// then this function would return a `T: Iterator` trait reference. diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 05b6c4a48de1e..3f24a33f7d570 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -6,7 +6,6 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; use rustc_middle::ty::{ToPredicate, TypeFoldable}; use rustc_session::DiagnosticMessageId; -use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; #[derive(Copy, Clone, Debug)] @@ -146,11 +145,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { let normalized_ty = fulfillcx.normalize_projection_type( &self.infcx, self.param_env, - ty::ProjectionTy::from_ref_and_name( - tcx, - trait_ref, - Ident::with_dummy_span(sym::Target), - ), + ty::ProjectionTy { + item_def_id: tcx.lang_items().deref_target()?, + substs: trait_ref.substs, + }, cause, ); if let Err(e) = fulfillcx.select_where_possible(&self.infcx) { diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 245152e5490d8..2419771eae212 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -64,6 +64,7 @@ pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "deref_target"] + #[cfg_attr(not(bootstrap), lang = "deref_target")] type Target: ?Sized; /// Dereferences the value. From 0bf1d73d229fdd0c22ef87b1c764c88cf35dd616 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 12 Feb 2021 22:07:46 +0000 Subject: [PATCH 084/103] Don't go through TraitRef to relate projections --- compiler/rustc_infer/src/infer/at.rs | 25 ++++++++++++++++++- .../src/traits/project.rs | 15 ++++++----- .../src/traits/select/mod.rs | 20 ++++++++------- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index a7749d33b7c13..11ee8fb17ad1b 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -55,6 +55,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { fn to_trace( + tcx: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -178,7 +179,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b); + let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b); Trace { at: self, trace, a_is_expected } } } @@ -251,6 +252,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { fn to_trace( + _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -262,6 +264,7 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { fn to_trace( + _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -273,6 +276,7 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> { fn to_trace( + _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -284,6 +288,7 @@ impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { fn to_trace( + _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -298,6 +303,7 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> { fn to_trace( + _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -309,3 +315,20 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> { } } } + +impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> { + fn to_trace( + tcx: TyCtxt<'tcx>, + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self, + ) -> TypeTrace<'tcx> { + let a_ty = tcx.mk_projection(a.item_def_id, a.substs); + let b_ty = tcx.mk_projection(b.item_def_id, b.substs); + TypeTrace { + cause: cause.clone(), + values: Types(ExpectedFound::new(a_is_expected, a_ty, b_ty)), + } + } +} diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 6908480f431e6..a38e3817a95e5 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -921,8 +921,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( && infcx.probe(|_| { selcx.match_projection_projections( obligation, - obligation_trait_ref, - &data, + data, potentially_unnormalized_candidates, ) }); @@ -1344,25 +1343,25 @@ fn confirm_param_env_candidate<'cx, 'tcx>( poly_cache_entry, ); - let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx); - let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx); + let cache_projection = cache_entry.projection_ty; + let obligation_projection = obligation.predicate; let mut nested_obligations = Vec::new(); - let cache_trait_ref = if potentially_unnormalized_candidate { + let cache_projection = if potentially_unnormalized_candidate { ensure_sufficient_stack(|| { normalize_with_depth_to( selcx, obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - cache_trait_ref, + cache_projection, &mut nested_obligations, ) }) } else { - cache_trait_ref + cache_projection }; - match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) { + match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) { Ok(InferOk { value: _, obligations }) => { nested_obligations.extend(obligations); assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 87c8099dc3a51..f0970a48808ad 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -32,6 +32,7 @@ use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::Constness; +use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fast_reject; @@ -1254,32 +1255,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub(super) fn match_projection_projections( &mut self, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - data: &PolyProjectionPredicate<'tcx>, + env_predicate: PolyProjectionPredicate<'tcx>, potentially_unnormalized_candidates: bool, ) -> bool { let mut nested_obligations = Vec::new(); - let projection_ty = if potentially_unnormalized_candidates { + let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars( + obligation.cause.span, + LateBoundRegionConversionTime::HigherRankedType, + env_predicate, + ); + let infer_projection = if potentially_unnormalized_candidates { ensure_sufficient_stack(|| { project::normalize_with_depth_to( self, obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - data.map_bound(|data| data.projection_ty), + infer_predicate.projection_ty, &mut nested_obligations, ) }) } else { - data.map_bound(|data| data.projection_ty) + infer_predicate.projection_ty }; - // FIXME(generic_associated_types): Compare the whole projections - let data_poly_trait_ref = projection_ty.map_bound(|proj| proj.trait_ref(self.tcx())); - let obligation_poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref); self.infcx .at(&obligation.cause, obligation.param_env) - .sup(obligation_poly_trait_ref, data_poly_trait_ref) + .sup(obligation.predicate, infer_projection) .map_or(false, |InferOk { obligations, value: () }| { self.evaluate_predicates_recursively( TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), From 9526c0c6e83f37deb1d48e9761ee9bee2ae94f60 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 12 Feb 2021 22:32:46 +0000 Subject: [PATCH 085/103] Avoid `trait_ref` when lowering ExistentialProjections --- compiler/rustc_middle/src/ty/sty.rs | 23 +++++++--- compiler/rustc_typeck/src/astconv/mod.rs | 57 +++++++++++------------- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8a8e70f76ced3..388a576787055 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1477,12 +1477,11 @@ impl<'tcx> ExistentialProjection<'tcx> { /// For example, if this is a projection of `exists T. ::Item == X`, /// then this function would return a `exists T. T: Iterator` existential trait /// reference. - pub fn trait_ref(&self, tcx: TyCtxt<'_>) -> ty::ExistentialTraitRef<'tcx> { - // FIXME(generic_associated_types): substs is the substs of the - // associated type, which should be truncated to get the correct substs - // for the trait. + pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> { let def_id = tcx.associated_item(self.item_def_id).container.id(); - ty::ExistentialTraitRef { def_id, substs: self.substs } + let subst_count = tcx.generics_of(def_id).count() - 1; + let substs = tcx.intern_substs(&self.substs[..subst_count]); + ty::ExistentialTraitRef { def_id, substs } } pub fn with_self_ty( @@ -1501,6 +1500,20 @@ impl<'tcx> ExistentialProjection<'tcx> { ty: self.ty, } } + + pub fn erase_self_ty( + tcx: TyCtxt<'tcx>, + projection_predicate: ty::ProjectionPredicate<'tcx>, + ) -> Self { + // Assert there is a Self. + projection_predicate.projection_ty.substs.type_at(0); + + Self { + item_def_id: projection_predicate.projection_ty.item_def_id, + substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]), + ty: projection_predicate.ty, + } + } } impl<'tcx> PolyExistentialProjection<'tcx> { diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 244eba8ad5e02..aa496f8722e95 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -985,10 +985,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // // We want to produce `>::T == foo`. - debug!( - "add_predicates_for_ast_type_binding(hir_ref_id {:?}, trait_ref {:?}, binding {:?}, bounds {:?}", - hir_ref_id, trait_ref, binding, bounds - ); + debug!(?hir_ref_id, ?trait_ref, ?binding, ?bounds, "add_predicates_for_ast_type_binding",); let tcx = self.tcx(); let candidate = @@ -1326,37 +1323,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("regular_traits: {:?}", regular_traits); debug!("auto_traits: {:?}", auto_traits); - // Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by - // removing the dummy `Self` type (`trait_object_dummy_self`). - let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| { - if trait_ref.self_ty() != dummy_self { - // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, - // which picks up non-supertraits where clauses - but also, the object safety - // completely ignores trait aliases, which could be object safety hazards. We - // `delay_span_bug` here to avoid an ICE in stable even when the feature is - // disabled. (#66420) - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "trait_ref_to_existential called on {:?} with non-dummy Self", - trait_ref, - ), - ); - } - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) - }; - // Erase the `dummy_self` (`trait_object_dummy_self`) used above. - let existential_trait_refs = - regular_traits.iter().map(|i| i.trait_ref().map_bound(trait_ref_to_existential)); + let existential_trait_refs = regular_traits.iter().map(|i| { + i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| { + if trait_ref.self_ty() != dummy_self { + // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, + // which picks up non-supertraits where clauses - but also, the object safety + // completely ignores trait aliases, which could be object safety hazards. We + // `delay_span_bug` here to avoid an ICE in stable even when the feature is + // disabled. (#66420) + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "trait_ref_to_existential called on {:?} with non-dummy Self", + trait_ref, + ), + ); + } + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + }) + }); let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { bound.map_bound(|b| { - let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx)); - ty::ExistentialProjection { - ty: b.ty, - item_def_id: b.projection_ty.item_def_id, - substs: trait_ref.substs, + if b.projection_ty.self_ty() != dummy_self { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!("trait_ref_to_existential called on {:?} with non-dummy Self", b), + ); } + ty::ExistentialProjection::erase_self_ty(tcx, b) }) }); From 79f6f11816cbef2bba6f5da6d4a4f0aa10535b88 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 12 Feb 2021 22:41:00 +0000 Subject: [PATCH 086/103] Remove some unnecessary `trait_ref` calls --- compiler/rustc_privacy/src/lib.rs | 27 ++++++++++++++++--- .../src/traits/fulfill.rs | 20 +++++++------- .../src/traits/object_safety.rs | 6 +---- .../src/constrained_generic_params.rs | 2 +- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 631dcb60594f1..0c340b2faaa47 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -77,6 +77,12 @@ trait DefIdVisitor<'tcx> { fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow { self.skeleton().visit_trait(trait_ref) } + fn visit_projection_ty( + &mut self, + projection: ty::ProjectionTy<'tcx>, + ) -> ControlFlow { + self.skeleton().visit_projection_ty(projection) + } fn visit_predicates( &mut self, predicates: ty::GenericPredicates<'tcx>, @@ -101,6 +107,20 @@ where if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) } } + fn visit_projection_ty( + &mut self, + projection: ty::ProjectionTy<'tcx>, + ) -> ControlFlow { + let (trait_ref, assoc_substs) = + projection.trait_ref_and_own_substs(self.def_id_visitor.tcx()); + self.visit_trait(trait_ref)?; + if self.def_id_visitor.shallow() { + ControlFlow::CONTINUE + } else { + assoc_substs.iter().try_for_each(|subst| subst.visit_with(self)) + } + } + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { match predicate.kind().skip_binder() { ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref }, _) => { @@ -108,7 +128,7 @@ where } ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => { ty.visit_with(self)?; - self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx())) + self.visit_projection_ty(projection_ty) } ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => { ty.visit_with(self) @@ -197,7 +217,7 @@ where return ControlFlow::CONTINUE; } // This will also visit substs if necessary, so we don't need to recurse. - return self.visit_trait(proj.trait_ref(tcx)); + return self.visit_projection_ty(proj); } ty::Dynamic(predicates, ..) => { // All traits in the list are considered the "primary" part of the type @@ -1204,10 +1224,9 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { } for (poly_predicate, _) in bounds.projection_bounds { - let tcx = self.tcx; if self.visit(poly_predicate.skip_binder().ty).is_break() || self - .visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) + .visit_projection_ty(poly_predicate.skip_binder().projection_ty) .is_break() { return; diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index d4ced20f86319..f3bbf9016835e 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -6,6 +6,7 @@ use rustc_errors::ErrorReported; use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::error::ExpectedFound; +use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable}; use std::marker::PhantomData; @@ -633,9 +634,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { // only reason we can fail to make progress on // trait selection is because we don't have enough // information about the types in the trait. - *stalled_on = trait_ref_infer_vars( + *stalled_on = substs_infer_vars( self.selcx, - trait_obligation.predicate.map_bound(|pred| pred.trait_ref), + trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs), ); debug!( @@ -663,9 +664,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { match project::poly_project_and_unify_type(self.selcx, &project_obligation) { Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)), Ok(Ok(None)) => { - *stalled_on = trait_ref_infer_vars( + *stalled_on = substs_infer_vars( self.selcx, - project_obligation.predicate.to_poly_trait_ref(tcx), + project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs), ); ProcessResult::Unchanged } @@ -678,16 +679,15 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } } -/// Returns the set of inference variables contained in a trait ref. -fn trait_ref_infer_vars<'a, 'tcx>( +/// Returns the set of inference variables contained in `substs`. +fn substs_infer_vars<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + substs: ty::Binder>, ) -> Vec> { selcx .infcx() - .resolve_vars_if_possible(trait_ref) - .skip_binder() - .substs + .resolve_vars_if_possible(substs) + .skip_binder() // ok because this check doesn't care about regions .iter() // FIXME(eddyb) try using `skip_current_subtree` to skip everything that // doesn't contain inference variables, not just the outermost level. diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index e155f0366e19f..7de20e477fe04 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -292,11 +292,7 @@ fn predicate_references_self( // // This is ALT2 in issue #56288, see that for discussion of the // possible alternatives. - if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) { - Some(sp) - } else { - None - } + if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None } } ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index 95670b9bdb983..529de1a287484 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -198,7 +198,7 @@ pub fn setup_constraining_predicates<'tcx>( // `<::Baz as Iterator>::Output = ::Output` // Then the projection only applies if `T` is known, but it still // does not determine `U`. - let inputs = parameters_for(&projection.projection_ty.trait_ref(tcx), true); + let inputs = parameters_for(&projection.projection_ty, true); let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p)); if !relies_only_on_inputs { continue; From dfee89f75545b4fadc559eee324afc8bb0bdc1be Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 12 Feb 2021 22:44:43 +0000 Subject: [PATCH 087/103] Make ProjectionTy::trait_ref truncate substs again Also make sure that type arguments of associated types are printed in some error messages. --- compiler/rustc_middle/src/ty/error.rs | 40 ++++++++++++++++--- compiler/rustc_middle/src/ty/mod.rs | 16 +++++++- compiler/rustc_middle/src/ty/sty.rs | 37 ++++++++++++----- .../src/traits/error_reporting/mod.rs | 3 +- compiler/rustc_traits/src/chalk/lowering.rs | 7 +--- compiler/rustc_typeck/src/check/closure.rs | 14 +++---- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 7 ++-- .../rustc_typeck/src/check/method/suggest.rs | 33 ++++++++------- .../constraint-assoc-type-suggestion.rs | 17 ++++++++ .../constraint-assoc-type-suggestion.stderr | 27 +++++++++++++ .../method-unsatified-assoc-type-predicate.rs | 35 ++++++++++++++++ ...hod-unsatified-assoc-type-predicate.stderr | 29 ++++++++++++++ 12 files changed, 216 insertions(+), 49 deletions(-) create mode 100644 src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs create mode 100644 src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr create mode 100644 src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs create mode 100644 src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 1669c59d7f1b9..ff95524492409 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -1,5 +1,6 @@ use crate::traits::{ObligationCause, ObligationCauseCode}; use crate::ty::diagnostics::suggest_constraining_type_param; +use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt}; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, DiagnosticBuilder}; @@ -400,14 +401,22 @@ impl<'tcx> TyCtxt<'tcx> { { // Synthesize the associated type restriction `Add`. // FIXME: extract this logic for use in other diagnostics. - let trait_ref = proj.trait_ref(self); + let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self); let path = self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs); let item_name = self.item_name(proj.item_def_id); + let item_args = self.format_generic_args(assoc_substs); + let path = if path.ends_with('>') { - format!("{}, {} = {}>", &path[..path.len() - 1], item_name, p) + format!( + "{}, {}{} = {}>", + &path[..path.len() - 1], + item_name, + item_args, + p + ) } else { - format!("{}<{} = {}>", path, item_name, p) + format!("{}<{}{} = {}>", path, item_name, item_args, p) }; note = !suggest_constraining_type_param( self, @@ -556,7 +565,7 @@ impl Trait for X { ty: Ty<'tcx>, ) -> bool { let assoc = self.associated_item(proj_ty.item_def_id); - let trait_ref = proj_ty.trait_ref(self); + let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self); if let Some(item) = self.hir().get_if_local(body_owner_def_id) { if let Some(hir_generics) = item.generics() { // Get the `DefId` for the type parameter corresponding to `A` in `::Foo`. @@ -590,6 +599,7 @@ impl Trait for X { &trait_ref, pred.bounds, &assoc, + assoc_substs, ty, msg, ) { @@ -607,6 +617,7 @@ impl Trait for X { &trait_ref, param.bounds, &assoc, + assoc_substs, ty, msg, ); @@ -692,6 +703,7 @@ impl Trait for X { db, self.def_span(def_id), &assoc, + proj_ty.trait_ref_and_own_substs(self).1, values.found, &msg, ) { @@ -856,6 +868,7 @@ fn foo(&self) -> Self::T { String::new() } trait_ref: &ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, assoc: &ty::AssocItem, + assoc_substs: &[ty::GenericArg<'tcx>], ty: Ty<'tcx>, msg: &str, ) -> bool { @@ -865,7 +878,12 @@ fn foo(&self) -> Self::T { String::new() } // Relate the type param against `T` in `::Foo`. ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id) && self.constrain_associated_type_structured_suggestion( - db, ptr.span, assoc, ty, msg, + db, + ptr.span, + assoc, + assoc_substs, + ty, + msg, ) } _ => false, @@ -879,6 +897,7 @@ fn foo(&self) -> Self::T { String::new() } db: &mut DiagnosticBuilder<'_>, span: Span, assoc: &ty::AssocItem, + assoc_substs: &[ty::GenericArg<'tcx>], ty: Ty<'tcx>, msg: &str, ) -> bool { @@ -890,11 +909,20 @@ fn foo(&self) -> Self::T { String::new() } let span = Span::new(pos, pos, span.ctxt()); (span, format!(", {} = {}", assoc.ident, ty)) } else { - (span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty)) + let item_args = self.format_generic_args(assoc_substs); + (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty)) }; db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect); return true; } false } + + fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String { + let mut item_args = String::new(); + FmtPrinter::new(self, &mut item_args, hir::def::Namespace::TypeNS) + .path_generic_args(Ok, args) + .expect("could not write to `String`."); + item_args + } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index babab005edb2b..b7f62437fa5a8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1289,8 +1289,22 @@ impl<'tcx> PolyProjectionPredicate<'tcx> { self.skip_binder().projection_ty.item_def_id } + /// Returns the `DefId` of the trait of the associated item being projected. #[inline] - pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> { + pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId { + self.skip_binder().projection_ty.trait_def_id(tcx) + } + + #[inline] + pub fn projection_self_ty(&self) -> Binder> { + self.map_bound(|predicate| predicate.projection_ty.self_ty()) + } + + /// Get the [PolyTraitRef] required for this projection to be well formed. + /// Note that for generic associated types the predicates of the associated + /// type also need to be checked. + #[inline] + pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> { // Note: unlike with `TraitRef::to_poly_trait_ref()`, // `self.0.trait_ref` is permitted to have escaping regions. // This is because here `self` has a `Binder` and so does our diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 388a576787055..754108ea3c58a 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -17,7 +17,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::vec::Idx; use rustc_macros::HashStable; -use rustc_span::symbol::{kw, Ident, Symbol}; +use rustc_span::symbol::{kw, Symbol}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi; use std::borrow::Cow; @@ -1112,20 +1112,35 @@ pub struct ProjectionTy<'tcx> { } impl<'tcx> ProjectionTy<'tcx> { + pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId { + tcx.associated_item(self.item_def_id).container.id() + } + + /// Extracts the underlying trait reference and own substs from this projection. + /// For example, if this is a projection of `::Item<'a>`, + /// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs + pub fn trait_ref_and_own_substs( + &self, + tcx: TyCtxt<'tcx>, + ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) { + let def_id = tcx.associated_item(self.item_def_id).container.id(); + let trait_generics = tcx.generics_of(def_id); + ( + ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) }, + &self.substs[trait_generics.count()..], + ) + } + /// Extracts the underlying trait reference from this projection. /// For example, if this is a projection of `::Item`, /// then this function would return a `T: Iterator` trait reference. + /// + /// WARNING: This will drop the substs for generic associated types + /// consider calling [Self::trait_ref_and_own_substs] to get those + /// as well. pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { - // FIXME: This method probably shouldn't exist at all, since it's not - // clear what this method really intends to do. Be careful when - // using this method since the resulting TraitRef additionally - // contains the substs for the assoc_item, which strictly speaking - // is not correct - let def_id = tcx.associated_item(self.item_def_id).container.id(); - // Include substitutions for generic arguments of associated types - let assoc_item = tcx.associated_item(self.item_def_id); - let substs_assoc_item = self.substs.truncate_to(tcx, tcx.generics_of(assoc_item.def_id)); - ty::TraitRef { def_id, substs: substs_assoc_item } + let def_id = self.trait_def_id(tcx); + ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) } } pub fn self_ty(&self) -> Ty<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 3233d1e048bf7..e9aaa65256419 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1589,8 +1589,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282) } ty::PredicateKind::Projection(data) => { - let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx); - let self_ty = trait_ref.skip_binder().self_ty(); + let self_ty = data.projection_ty.self_ty(); let ty = data.ty; if predicate.references_error() { return; diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 7d3589c4b6bd8..fdf5f697e6117 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -779,14 +779,11 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound self, interner: &RustInterner<'tcx>, ) -> chalk_solve::rust_ir::AliasEqBound> { - let trait_ref = self.projection_ty.trait_ref(interner.tcx); + let (trait_ref, own_substs) = self.projection_ty.trait_ref_and_own_substs(interner.tcx); chalk_solve::rust_ir::AliasEqBound { trait_bound: trait_ref.lower_into(interner), associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id), - parameters: self.projection_ty.substs[trait_ref.substs.len()..] - .iter() - .map(|arg| arg.lower_into(interner)) - .collect(), + parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(), value: self.ty.lower_into(interner), } } diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index f34aaec10a9b9..431e6d70ff35c 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -208,7 +208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); // Even if we can't infer the full signature, we may be able to - // infer the kind. This can occur if there is a trait-reference + // infer the kind. This can occur when we elaborate a predicate // like `F : Fn`. Note that due to subtyping we could encounter // many viable options, so pick the most restrictive. let expected_kind = self @@ -234,11 +234,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("deduce_sig_from_projection({:?})", projection); - let trait_ref = projection.to_poly_trait_ref(tcx); + let trait_def_id = projection.trait_def_id(tcx); - let is_fn = tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some(); + let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some(); let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span); - let is_gen = gen_trait == trait_ref.def_id(); + let is_gen = gen_trait == trait_def_id; if !is_fn && !is_gen { debug!("deduce_sig_from_projection: not fn or generator"); return None; @@ -256,7 +256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let input_tys = if is_fn { - let arg_param_ty = trait_ref.skip_binder().substs.type_at(1); + let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1); let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty); debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty); @@ -662,9 +662,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Check that this is a projection from the `Future` trait. - let trait_ref = predicate.projection_ty.trait_ref(self.tcx); + let trait_def_id = predicate.projection_ty.trait_def_id(self.tcx); let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span)); - if trait_ref.def_id != future_trait { + if trait_def_id != future_trait { debug!("deduce_future_output_from_projection: not a future"); return None; } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index bc1a07801ae87..75c73e0b67c07 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -769,9 +769,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter_map(move |obligation| { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Projection(data) => { - Some((bound_predicate.rebind(data).to_poly_trait_ref(self.tcx), obligation)) - } + ty::PredicateKind::Projection(data) => Some(( + bound_predicate.rebind(data).required_poly_trait_ref(self.tcx), + obligation, + )), ty::PredicateKind::Trait(data, _) => { Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation)) } diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index d49c7cae8222b..14d019fa01a74 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -24,6 +24,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::Obligation; use std::cmp::Ordering; +use std::iter; use super::probe::Mode; use super::{CandidateSource, MethodError, NoMatchData}; @@ -649,21 +650,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::Projection(pred) => { let pred = bound_predicate.rebind(pred); // `::Item = String`. - let trait_ref = - pred.skip_binder().projection_ty.trait_ref(self.tcx); - let assoc = self - .tcx - .associated_item(pred.skip_binder().projection_ty.item_def_id); - let ty = pred.skip_binder().ty; - let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty); - let quiet = format!( - "<_ as {}>::{} = {}", - trait_ref.print_only_trait_path(), - assoc.ident, - ty + let projection_ty = pred.skip_binder().projection_ty; + + let substs_with_infer_self = tcx.mk_substs( + iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into()) + .chain(projection_ty.substs.iter().skip(1)), ); - bound_span_label(trait_ref.self_ty(), &obligation, &quiet); - Some((obligation, trait_ref.self_ty())) + + let quiet_projection_ty = ty::ProjectionTy { + substs: substs_with_infer_self, + item_def_id: projection_ty.item_def_id, + }; + + let ty = pred.skip_binder().ty; + + let obligation = format!("{} = {}", projection_ty, ty); + let quiet = format!("{} = {}", quiet_projection_ty, ty); + + bound_span_label(projection_ty.self_ty(), &obligation, &quiet); + Some((obligation, projection_ty.self_ty())) } ty::PredicateKind::Trait(poly_trait_ref, _) => { let p = poly_trait_ref.trait_ref; diff --git a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs new file mode 100644 index 0000000000000..36db3d1bb9e47 --- /dev/null +++ b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs @@ -0,0 +1,17 @@ +// Test that correct syntax is used in suggestion to constrain associated type + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete + +trait X { + type Y; +} + +fn f(a: T::Y) { + //~^ HELP consider constraining the associated type `::Y` to `Vec` + //~| SUGGESTION Y = Vec> + let b: Vec = a; + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr new file mode 100644 index 0000000000000..ecf559d9e94a1 --- /dev/null +++ b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr @@ -0,0 +1,27 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/constraint-assoc-type-suggestion.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0308]: mismatched types + --> $DIR/constraint-assoc-type-suggestion.rs:13:23 + | +LL | let b: Vec = a; + | -------- ^ expected struct `Vec`, found associated type + | | + | expected due to this + | + = note: expected struct `Vec` + found associated type `::Y` +help: consider constraining the associated type `::Y` to `Vec` + | +LL | fn f = Vec>>(a: T::Y) { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs new file mode 100644 index 0000000000000..2de4c7b8492a3 --- /dev/null +++ b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs @@ -0,0 +1,35 @@ +// Test that the predicate printed in an unresolved method error prints the +// generics for a generic associated type. + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete +//~| NOTE `#[warn(incomplete_features)]` on by default +//~| NOTE see issue #44265 + +trait X { + type Y; +} + +trait M { + fn f(&self) {} +} + +impl = i32>> M for T {} + +struct S; +//~^ NOTE method `f` not found for this +//~| NOTE doesn't satisfy `::Y = i32` +//~| NOTE doesn't satisfy `S: M` + +impl X for S { + type Y = bool; +} + +fn f(a: S) { + a.f(); + //~^ ERROR the method `f` exists for struct `S`, but its trait bounds were not satisfied + //~| NOTE method cannot be called on `S` due to unsatisfied trait bounds + //~| NOTE the following trait bounds were not satisfied: +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr new file mode 100644 index 0000000000000..c94155d13c344 --- /dev/null +++ b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr @@ -0,0 +1,29 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/method-unsatified-assoc-type-predicate.rs:4:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied + --> $DIR/method-unsatified-assoc-type-predicate.rs:29:7 + | +LL | struct S; + | --------- + | | + | method `f` not found for this + | doesn't satisfy `::Y = i32` + | doesn't satisfy `S: M` +... +LL | a.f(); + | ^ method cannot be called on `S` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `::Y = i32` + which is required by `S: M` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0599`. From d785c8c447bd7f972e68e346a3f7b04c56ce486b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 12 Feb 2021 22:45:19 +0000 Subject: [PATCH 088/103] Remove unnecessary function parameters project.rs --- .../src/traits/project.rs | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index a38e3817a95e5..bfaca4215edb7 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -741,11 +741,7 @@ fn project_type<'cx, 'tcx>( return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); } - let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); - - debug!(?obligation_trait_ref); - - if obligation_trait_ref.references_error() { + if obligation.predicate.references_error() { return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx()))); } @@ -754,19 +750,19 @@ fn project_type<'cx, 'tcx>( // Make sure that the following procedures are kept in order. ParamEnv // needs to be first because it has highest priority, and Select checks // the return value of push_candidate which assumes it's ran at last. - assemble_candidates_from_param_env(selcx, obligation, &obligation_trait_ref, &mut candidates); + assemble_candidates_from_param_env(selcx, obligation, &mut candidates); - assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates); + assemble_candidates_from_trait_def(selcx, obligation, &mut candidates); - assemble_candidates_from_object_ty(selcx, obligation, &obligation_trait_ref, &mut candidates); + assemble_candidates_from_object_ty(selcx, obligation, &mut candidates); if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates { // Avoid normalization cycle from selection (see // `assemble_candidates_from_object_ty`). // FIXME(lazy_normalization): Lazy normalization should save us from - // having to do special case this. + // having to special case this. } else { - assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates); + assemble_candidates_from_impls(selcx, obligation, &mut candidates); }; match candidates { @@ -792,14 +788,12 @@ fn project_type<'cx, 'tcx>( fn assemble_candidates_from_param_env<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ) { debug!("assemble_candidates_from_param_env(..)"); assemble_candidates_from_predicates( selcx, obligation, - obligation_trait_ref, candidate_set, ProjectionTyCandidate::ParamEnv, obligation.param_env.caller_bounds().iter(), @@ -820,7 +814,6 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>( fn assemble_candidates_from_trait_def<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ) { debug!("assemble_candidates_from_trait_def(..)"); @@ -828,7 +821,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( let tcx = selcx.tcx(); // Check whether the self-type is itself a projection. // If so, extract what we know from the trait and try to come up with a good answer. - let bounds = match *obligation_trait_ref.self_ty().kind() { + let bounds = match *obligation.predicate.self_ty().kind() { ty::Projection(ref data) => tcx.item_bounds(data.item_def_id).subst(tcx, data.substs), ty::Opaque(def_id, substs) => tcx.item_bounds(def_id).subst(tcx, substs), ty::Infer(ty::TyVar(_)) => { @@ -843,7 +836,6 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( assemble_candidates_from_predicates( selcx, obligation, - obligation_trait_ref, candidate_set, ProjectionTyCandidate::TraitDef, bounds.iter(), @@ -863,14 +855,13 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( fn assemble_candidates_from_object_ty<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ) { debug!("assemble_candidates_from_object_ty(..)"); let tcx = selcx.tcx(); - let self_ty = obligation_trait_ref.self_ty(); + let self_ty = obligation.predicate.self_ty(); let object_ty = selcx.infcx().shallow_resolve(self_ty); let data = match object_ty.kind() { ty::Dynamic(data, ..) => data, @@ -890,7 +881,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( assemble_candidates_from_predicates( selcx, obligation, - obligation_trait_ref, candidate_set, ProjectionTyCandidate::Object, env_predicates, @@ -901,7 +891,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( fn assemble_candidates_from_predicates<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>, env_predicates: impl Iterator>, @@ -947,14 +936,13 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( fn assemble_candidates_from_impls<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ) { debug!("assemble_candidates_from_impls"); // If we are resolving `>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: - let poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref); + let poly_trait_ref = obligation.predicate.trait_ref(selcx.tcx()).to_poly_trait_ref(); let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); let _ = selcx.infcx().commit_if_ok(|_| { let impl_source = match selcx.select(&trait_obligation) { From eeb82e45fe42ec77efd99b706f96b3e66bcfb524 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 12 Feb 2021 22:45:54 +0000 Subject: [PATCH 089/103] Add more tests for generic associated type bounds --- .../generic-associated-type-bounds.rs | 35 +++++++++++++ .../generic-associated-types/issue-76535.rs | 6 +-- .../issue-76535.stderr | 39 +-------------- .../generic-associated-types/issue-79422.rs | 5 +- .../issue-79422.stderr | 40 +++------------ .../projection-type-lifetime-mismatch.rs | 36 +++++++++++++ .../projection-type-lifetime-mismatch.stderr | 27 ++++++++++ .../unsatified-item-lifetime-bound.rs | 28 +++++++++++ .../unsatified-item-lifetime-bound.stderr | 50 +++++++++++++++++++ 9 files changed, 190 insertions(+), 76 deletions(-) create mode 100644 src/test/ui/generic-associated-types/generic-associated-type-bounds.rs create mode 100644 src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs create mode 100644 src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr create mode 100644 src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs create mode 100644 src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr diff --git a/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs b/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs new file mode 100644 index 0000000000000..8094450e5e137 --- /dev/null +++ b/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs @@ -0,0 +1,35 @@ +// run-pass + +#![allow(incomplete_features)] +#![feature(generic_associated_types)] + +pub trait X { + type Y<'a>; + fn m(&self) -> Self::Y<'_>; +} + +impl X for () { + type Y<'a> = &'a (); + + fn m(&self) -> Self::Y<'_> { + self + } +} + +fn f(x: &impl for<'a> X = &'a ()>) -> &() { + x.m() +} + +fn g X = &'a ()>>(x: &T) -> &() { + x.m() +} + +fn h(x: &()) -> &() { + x.m() +} + +fn main() { + f(&()); + g(&()); + h(&()); +} diff --git a/src/test/ui/generic-associated-types/issue-76535.rs b/src/test/ui/generic-associated-types/issue-76535.rs index 2b4757d8d15ed..5e73a88298622 100644 --- a/src/test/ui/generic-associated-types/issue-76535.rs +++ b/src/test/ui/generic-associated-types/issue-76535.rs @@ -1,11 +1,11 @@ #![feature(generic_associated_types)] - //~^ WARNING the feature +//~^ WARNING the feature pub trait SubTrait {} pub trait SuperTrait { type SubType<'a>: SubTrait; - //~^ ERROR missing generics for associated + //~^ ERROR missing generics for associated fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>; } @@ -36,6 +36,4 @@ impl SuperTrait for SuperStruct { fn main() { let sub: Box> = Box::new(SuperStruct::new(0)); - //~^ ERROR the trait - //~| ERROR the trait } diff --git a/src/test/ui/generic-associated-types/issue-76535.stderr b/src/test/ui/generic-associated-types/issue-76535.stderr index ce4875af9c012..17661e0d90a4a 100644 --- a/src/test/ui/generic-associated-types/issue-76535.stderr +++ b/src/test/ui/generic-associated-types/issue-76535.stderr @@ -23,41 +23,6 @@ help: use angle brackets to add missing lifetime argument LL | type SubType<'a><'a>: SubTrait; | ^^^^ -error[E0038]: the trait `SuperTrait` cannot be made into an object - --> $DIR/issue-76535.rs:38:14 - | -LL | let sub: Box> = Box::new(SuperStruct::new(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object - | - = help: consider moving `get_sub` to another trait -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-76535.rs:10:37 - | -LL | pub trait SuperTrait { - | ---------- this trait cannot be made into an object... -... -LL | fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>; - | ^^^^^^^^^^^^^^^^^ ...because method `get_sub` references the `Self` type in its return type - -error[E0038]: the trait `SuperTrait` cannot be made into an object - --> $DIR/issue-76535.rs:38:57 - | -LL | let sub: Box> = Box::new(SuperStruct::new(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object - | - = help: consider moving `get_sub` to another trait -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-76535.rs:10:37 - | -LL | pub trait SuperTrait { - | ---------- this trait cannot be made into an object... -... -LL | fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>; - | ^^^^^^^^^^^^^^^^^ ...because method `get_sub` references the `Self` type in its return type - = note: required because of the requirements on the impl of `CoerceUnsized>>>` for `Box` - = note: required by cast to type `Box>>` - -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to previous error; 1 warning emitted -Some errors have detailed explanations: E0038, E0107. -For more information about an error, try `rustc --explain E0038`. +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/generic-associated-types/issue-79422.rs b/src/test/ui/generic-associated-types/issue-79422.rs index 26b38430dd9a5..aeb33ca54641c 100644 --- a/src/test/ui/generic-associated-types/issue-79422.rs +++ b/src/test/ui/generic-associated-types/issue-79422.rs @@ -19,7 +19,7 @@ impl<'a, T> RefCont<'a, T> for Box { trait MapLike { type VRefCont<'a>: RefCont<'a, V>; - //~^ ERROR missing generics + //~^ ERROR missing generics fn get<'a>(&'a self, key: &K) -> Option>; } @@ -42,6 +42,5 @@ impl MapLike for Source { fn main() { let m = Box::new(std::collections::BTreeMap::::new()) as Box>>; - //~^ ERROR the trait - //~^^^ ERROR the trait + //~^^ ERROR type mismatch resolving } diff --git a/src/test/ui/generic-associated-types/issue-79422.stderr b/src/test/ui/generic-associated-types/issue-79422.stderr index d2e12962715f0..a119bff03e290 100644 --- a/src/test/ui/generic-associated-types/issue-79422.stderr +++ b/src/test/ui/generic-associated-types/issue-79422.stderr @@ -14,41 +14,17 @@ help: use angle brackets to add missing lifetime argument LL | type VRefCont<'a><'a>: RefCont<'a, V>; | ^^^^ -error[E0038]: the trait `MapLike` cannot be made into an object - --> $DIR/issue-79422.rs:44:12 - | -LL | as Box>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object - | - = help: consider moving `get` to another trait -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-79422.rs:23:38 - | -LL | trait MapLike { - | ------- this trait cannot be made into an object... -... -LL | fn get<'a>(&'a self, key: &K) -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `get` references the `Self` type in its return type - -error[E0038]: the trait `MapLike` cannot be made into an object +error[E0271]: type mismatch resolving ` as MapLike>::VRefCont<'static> == (dyn RefCont<'_, u8> + 'static)` --> $DIR/issue-79422.rs:43:13 | LL | let m = Box::new(std::collections::BTreeMap::::new()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object - | - = help: consider moving `get` to another trait -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-79422.rs:23:38 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn RefCont`, found reference | -LL | trait MapLike { - | ------- this trait cannot be made into an object... -... -LL | fn get<'a>(&'a self, key: &K) -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `get` references the `Self` type in its return type - = note: required because of the requirements on the impl of `CoerceUnsized + 'static)>>>` for `Box>` - = note: required by cast to type `Box + 'static)>>` + = note: expected trait object `(dyn RefCont<'_, u8> + 'static)` + found reference `&'static u8` + = note: required for the cast to the object type `dyn MapLike + 'static)>` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0038, E0107. -For more information about an error, try `rustc --explain E0038`. +Some errors have detailed explanations: E0107, E0271. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs new file mode 100644 index 0000000000000..0024e127a982c --- /dev/null +++ b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs @@ -0,0 +1,36 @@ +#![allow(incomplete_features)] +#![feature(generic_associated_types)] + +pub trait X { + type Y<'a>; + fn m(&self) -> Self::Y<'_>; +} + +impl X for () { + type Y<'a> = &'a (); + + fn m(&self) -> Self::Y<'_> { + self + } +} + +fn f(x: &impl for<'a> X = &'a ()>) -> &'static () { + x.m() + //~^ ERROR explicit lifetime required +} + +fn g X = &'a ()>>(x: &T) -> &'static () { + x.m() + //~^ ERROR explicit lifetime required +} + +fn h(x: &()) -> &'static () { + x.m() + //~^ ERROR explicit lifetime required +} + +fn main() { + f(&()); + g(&()); + h(&()); +} diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr new file mode 100644 index 0000000000000..13b765dfa5719 --- /dev/null +++ b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr @@ -0,0 +1,27 @@ +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/projection-type-lifetime-mismatch.rs:18:5 + | +LL | fn f(x: &impl for<'a> X = &'a ()>) -> &'static () { + | ------------------------------- help: add explicit lifetime `'static` to the type of `x`: `&'static impl for<'a> X = &'a ()>` +LL | x.m() + | ^^^^^ lifetime `'static` required + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/projection-type-lifetime-mismatch.rs:23:5 + | +LL | fn g X = &'a ()>>(x: &T) -> &'static () { + | -- help: add explicit lifetime `'static` to the type of `x`: `&'static T` +LL | x.m() + | ^^^^^ lifetime `'static` required + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/projection-type-lifetime-mismatch.rs:28:5 + | +LL | fn h(x: &()) -> &'static () { + | --- help: add explicit lifetime `'static` to the type of `x`: `&'static ()` +LL | x.m() + | ^^^^^ lifetime `'static` required + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs new file mode 100644 index 0000000000000..7bcc7ba752ad0 --- /dev/null +++ b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs @@ -0,0 +1,28 @@ +#![allow(incomplete_features)] +#![feature(generic_associated_types)] + +pub trait X { + type Y<'a: 'static>; + //~^ WARNING unnecessary lifetime parameter +} + +impl X for () { + type Y<'a> = &'a (); +} + +struct B<'a, T: for<'r> X = &'r ()>> { + f: ::Y<'a>, + //~^ ERROR lifetime bound not satisfied +} + +struct C<'a, T: X> { + f: ::Y<'a>, + //~^ ERROR lifetime bound not satisfied +} + +struct D<'a> { + f: <() as X>::Y<'a>, + //~^ ERROR lifetime bound not satisfied +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr new file mode 100644 index 0000000000000..1c81d33ccfe72 --- /dev/null +++ b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr @@ -0,0 +1,50 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/unsatified-item-lifetime-bound.rs:5:12 + | +LL | type Y<'a: 'static>; + | ^^^^^^^^^^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +error[E0478]: lifetime bound not satisfied + --> $DIR/unsatified-item-lifetime-bound.rs:14:8 + | +LL | f: ::Y<'a>, + | ^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 13:10 + --> $DIR/unsatified-item-lifetime-bound.rs:13:10 + | +LL | struct B<'a, T: for<'r> X = &'r ()>> { + | ^^ + = note: but lifetime parameter must outlive the static lifetime + +error[E0478]: lifetime bound not satisfied + --> $DIR/unsatified-item-lifetime-bound.rs:19:8 + | +LL | f: ::Y<'a>, + | ^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 18:10 + --> $DIR/unsatified-item-lifetime-bound.rs:18:10 + | +LL | struct C<'a, T: X> { + | ^^ + = note: but lifetime parameter must outlive the static lifetime + +error[E0478]: lifetime bound not satisfied + --> $DIR/unsatified-item-lifetime-bound.rs:24:8 + | +LL | f: <() as X>::Y<'a>, + | ^^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 23:10 + --> $DIR/unsatified-item-lifetime-bound.rs:23:10 + | +LL | struct D<'a> { + | ^^ + = note: but lifetime parameter must outlive the static lifetime + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0478`. From be1ed00712ce0b884e1fc9779f25b1758e994d0b Mon Sep 17 00:00:00 2001 From: kadmin Date: Sat, 13 Feb 2021 07:53:28 +0000 Subject: [PATCH 090/103] Add additional type info to mismatch err --- compiler/rustc_typeck/src/astconv/generics.rs | 51 ++++++++++++++----- src/test/ui/const-generics/diagnostics.rs | 13 +++++ src/test/ui/const-generics/diagnostics.stderr | 27 ++++++++++ .../ui/const-generics/invalid-enum.stderr | 20 -------- 4 files changed, 79 insertions(+), 32 deletions(-) create mode 100644 src/test/ui/const-generics/diagnostics.rs create mode 100644 src/test/ui/const-generics/diagnostics.stderr diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 67e37ca8d8e49..341f6fadba174 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -24,6 +24,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx: TyCtxt<'_>, arg: &GenericArg<'_>, param: &GenericParamDef, + // DefId of the function + //body_def_id: DefId, possible_ordering_error: bool, help: Option<&str>, ) { @@ -46,19 +48,44 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Specific suggestion set for diagnostics match (arg, ¶m.kind) { ( - GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }), - GenericParamDefKind::Const { .. }, + GenericArg::Type(hir::Ty { + kind: hir::TyKind::Path(rustc_hir::QPath::Resolved(_, path)), + .. + }), + GenericParamDefKind::Const, ) => { - let suggestions = vec![ - (arg.span().shrink_to_lo(), String::from("{ ")), - (arg.span().shrink_to_hi(), String::from(" }")), - ]; - err.multipart_suggestion( - "if this generic argument was intended as a const parameter, \ - try surrounding it with braces:", - suggestions, - Applicability::MaybeIncorrect, - ); + use rustc_hir::def::{DefKind, Res}; + match path.res { + Res::Err => {} + Res::Def(DefKind::TyParam, src_def_id) => (|| { + let param_hir_id = match param.def_id.as_local() { + Some(x) => tcx.hir().local_def_id_to_hir_id(x), + None => return, + }; + let param_name = tcx.hir().ty_param_name(param_hir_id); + let param_type = tcx.type_of(param.def_id); + if param_type.is_suggestable() { + err.span_suggestion( + tcx.def_span(src_def_id), + &format!("try changing to a const-generic parameter:"), + format!("const {}: {}", param_name, param_type), + Applicability::MaybeIncorrect, + ); + } + })(), + _ => { + let suggestions = vec![ + (arg.span().shrink_to_lo(), String::from("{ ")), + (arg.span().shrink_to_hi(), String::from(" }")), + ]; + err.multipart_suggestion( + "if this generic argument was intended as a const parameter, \ + try surrounding it with braces:", + suggestions, + Applicability::MaybeIncorrect, + ); + } + } } ( GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }), diff --git a/src/test/ui/const-generics/diagnostics.rs b/src/test/ui/const-generics/diagnostics.rs new file mode 100644 index 0000000000000..c90e3d0e0eba9 --- /dev/null +++ b/src/test/ui/const-generics/diagnostics.rs @@ -0,0 +1,13 @@ +#![crate_type="lib"] +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct A; +trait Foo {} +impl Foo for A {} +//~^ ERROR type provided when a constant +//~| ERROR cannot find type + +struct B; +impl Foo for B {} +//~^ ERROR type provided when a constant diff --git a/src/test/ui/const-generics/diagnostics.stderr b/src/test/ui/const-generics/diagnostics.stderr new file mode 100644 index 0000000000000..a66858a310c85 --- /dev/null +++ b/src/test/ui/const-generics/diagnostics.stderr @@ -0,0 +1,27 @@ +error[E0412]: cannot find type `N` in this scope + --> $DIR/diagnostics.rs:7:16 + | +LL | struct A; + | ---------------------- similarly named struct `A` defined here +LL | trait Foo {} +LL | impl Foo for A {} + | ^ help: a struct with a similar name exists: `A` + +error[E0747]: type provided when a constant was expected + --> $DIR/diagnostics.rs:7:16 + | +LL | impl Foo for A {} + | ^ + +error[E0747]: type provided when a constant was expected + --> $DIR/diagnostics.rs:12:19 + | +LL | impl Foo for B {} + | - ^ + | | + | help: try changing to a const-generic parameter:: `const N: u8` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0412, E0747. +For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/const-generics/invalid-enum.stderr b/src/test/ui/const-generics/invalid-enum.stderr index 7822fc072e35c..c062fc9ac88b3 100644 --- a/src/test/ui/const-generics/invalid-enum.stderr +++ b/src/test/ui/const-generics/invalid-enum.stderr @@ -30,44 +30,24 @@ error[E0747]: type provided when a constant was expected | LL | let _: Example = Example { x: 0 }; | ^^^^^^^^^^^^^^ - | -help: if this generic argument was intended as a const parameter, try surrounding it with braces: - | -LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 }; - | ^ ^ error[E0747]: type provided when a constant was expected --> $DIR/invalid-enum.rs:33:18 | LL | let _: Example = Example { x: 0 }; | ^^^^^^^^^^^^^^^^^^^ - | -help: if this generic argument was intended as a const parameter, try surrounding it with braces: - | -LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 }; - | ^ ^ error[E0747]: type provided when a constant was expected --> $DIR/invalid-enum.rs:21:12 | LL | test_1::(); | ^^^^^^^^^^^^^^ - | -help: if this generic argument was intended as a const parameter, try surrounding it with braces: - | -LL | test_1::<{ CompileFlag::A }>(); - | ^ ^ error[E0747]: type provided when a constant was expected --> $DIR/invalid-enum.rs:25:15 | LL | test_2::<_, CompileFlag::A>(0); | ^^^^^^^^^^^^^^ - | -help: if this generic argument was intended as a const parameter, try surrounding it with braces: - | -LL | test_2::<_, { CompileFlag::A }>(0); - | ^ ^ error: aborting due to 7 previous errors From a9b16c6d714dcec62b9e92f1ad7963b999c163c9 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 13 Feb 2021 21:42:32 -0800 Subject: [PATCH 091/103] Improve error and help messages --- compiler/rustc_lint/src/types.rs | 8 ++--- .../ui/enum/enum-discrim-too-small2.stderr | 8 ++--- src/test/ui/issues/issue-79744.rs | 2 +- src/test/ui/issues/issue-79744.stderr | 2 +- src/test/ui/lint/lint-type-limits2.stderr | 2 +- src/test/ui/lint/lint-type-limits3.stderr | 2 +- src/test/ui/lint/lint-type-overflow.stderr | 32 +++++++++---------- src/test/ui/lint/lint-type-overflow2.stderr | 2 +- src/test/ui/lint/type-overflow.rs | 12 +++---- src/test/ui/lint/type-overflow.stderr | 26 +++++++-------- 10 files changed, 48 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index d9f4da23d2f86..b64f18d24832f 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -225,7 +225,7 @@ fn report_bin_hex_error( (t.name_str(), actually.to_string()) } }; - let mut err = lint.build(&format!("literal out of range for {}", t)); + let mut err = lint.build(&format!("literal out of range for `{}`", t)); err.note(&format!( "the literal `{}` (decimal `{}`) does not fit into \ the type `{}` and will become `{}{}`", @@ -238,12 +238,12 @@ fn report_bin_hex_error( let (sans_suffix, _) = repr_str.split_at(pos); err.span_suggestion( expr.span, - &format!("consider using `{}` instead", sugg_ty), + &format!("consider using the type `{}` instead", sugg_ty), format!("{}{}", sans_suffix, sugg_ty), Applicability::MachineApplicable, ); } else { - err.help(&format!("consider using `{}` instead", sugg_ty)); + err.help(&format!("consider using the type `{}` instead", sugg_ty)); } } err.emit(); @@ -345,7 +345,7 @@ fn lint_int_literal<'tcx>( if let Some(sugg_ty) = get_type_suggestion(&cx.typeck_results().node_type(e.hir_id), v, negative) { - err.help(&format!("consider using `{}` instead", sugg_ty)); + err.help(&format!("consider using the type `{}` instead", sugg_ty)); } err.emit(); }); diff --git a/src/test/ui/enum/enum-discrim-too-small2.stderr b/src/test/ui/enum/enum-discrim-too-small2.stderr index f0deb26e96db4..43830679535de 100644 --- a/src/test/ui/enum/enum-discrim-too-small2.stderr +++ b/src/test/ui/enum/enum-discrim-too-small2.stderr @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ = note: the literal `223` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using `u8` instead + = help: consider using the type `u8` instead error: literal out of range for `i16` --> $DIR/enum-discrim-too-small2.rs:15:12 @@ -19,7 +19,7 @@ LL | Ci16 = 55555, | ^^^^^ | = note: the literal `55555` does not fit into the type `i16` whose range is `-32768..=32767` - = help: consider using `u16` instead + = help: consider using the type `u16` instead error: literal out of range for `i32` --> $DIR/enum-discrim-too-small2.rs:22:12 @@ -28,7 +28,7 @@ LL | Ci32 = 3_000_000_000, | ^^^^^^^^^^^^^ | = note: the literal `3_000_000_000` does not fit into the type `i32` whose range is `-2147483648..=2147483647` - = help: consider using `u32` instead + = help: consider using the type `u32` instead error: literal out of range for `i64` --> $DIR/enum-discrim-too-small2.rs:29:12 @@ -37,7 +37,7 @@ LL | Ci64 = 9223372036854775809, | ^^^^^^^^^^^^^^^^^^^ | = note: the literal `9223372036854775809` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` - = help: consider using `u64` instead + = help: consider using the type `u64` instead error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-79744.rs b/src/test/ui/issues/issue-79744.rs index 49051f2cee655..e9725a027d379 100644 --- a/src/test/ui/issues/issue-79744.rs +++ b/src/test/ui/issues/issue-79744.rs @@ -2,7 +2,7 @@ fn main() { let elem = 6i8; let e2 = 230; //~^ ERROR literal out of range for `i8` - //~| HELP consider using `u8` instead + //~| HELP consider using the type `u8` instead let mut vec = Vec::new(); diff --git a/src/test/ui/issues/issue-79744.stderr b/src/test/ui/issues/issue-79744.stderr index b35700cd47268..6f6dd44d2369e 100644 --- a/src/test/ui/issues/issue-79744.stderr +++ b/src/test/ui/issues/issue-79744.stderr @@ -6,7 +6,7 @@ LL | let e2 = 230; | = note: `#[deny(overflowing_literals)]` on by default = note: the literal `230` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using `u8` instead + = help: consider using the type `u8` instead error: aborting due to previous error diff --git a/src/test/ui/lint/lint-type-limits2.stderr b/src/test/ui/lint/lint-type-limits2.stderr index 357fde7151ca2..3562cb440a661 100644 --- a/src/test/ui/lint/lint-type-limits2.stderr +++ b/src/test/ui/lint/lint-type-limits2.stderr @@ -18,7 +18,7 @@ note: the lint level is defined here LL | #![warn(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ = note: the literal `128` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using `u8` instead + = help: consider using the type `u8` instead error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/lint/lint-type-limits3.stderr b/src/test/ui/lint/lint-type-limits3.stderr index c8558cfc2143c..823d1a4c76fd6 100644 --- a/src/test/ui/lint/lint-type-limits3.stderr +++ b/src/test/ui/lint/lint-type-limits3.stderr @@ -18,7 +18,7 @@ note: the lint level is defined here LL | #![warn(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ = note: the literal `200` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using `u8` instead + = help: consider using the type `u8` instead error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/lint/lint-type-overflow.stderr b/src/test/ui/lint/lint-type-overflow.stderr index f0a8f507d5723..1bb1ec5477609 100644 --- a/src/test/ui/lint/lint-type-overflow.stderr +++ b/src/test/ui/lint/lint-type-overflow.stderr @@ -26,7 +26,7 @@ LL | let x1: i8 = 128; | ^^^ | = note: the literal `128` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using `u8` instead + = help: consider using the type `u8` instead error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:18:19 @@ -35,7 +35,7 @@ LL | let x3: i8 = -129; | ^^^ | = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using `i16` instead + = help: consider using the type `i16` instead error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:19:19 @@ -44,7 +44,7 @@ LL | let x3: i8 = -(129); | ^^^^^ | = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using `i16` instead + = help: consider using the type `i16` instead error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:20:20 @@ -53,7 +53,7 @@ LL | let x3: i8 = -{129}; | ^^^ | = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using `u8` instead + = help: consider using the type `u8` instead error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:22:10 @@ -62,7 +62,7 @@ LL | test(1000); | ^^^^ | = note: the literal `1000` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using `i16` instead + = help: consider using the type `i16` instead error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:24:13 @@ -71,7 +71,7 @@ LL | let x = 128_i8; | ^^^^^^ | = note: the literal `128_i8` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using `u8` instead + = help: consider using the type `u8` instead error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:28:14 @@ -80,7 +80,7 @@ LL | let x = -129_i8; | ^^^^^^ | = note: the literal `129_i8` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using `i16` instead + = help: consider using the type `i16` instead error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:32:18 @@ -89,7 +89,7 @@ LL | let x: i32 = 2147483648; | ^^^^^^^^^^ | = note: the literal `2147483648` does not fit into the type `i32` whose range is `-2147483648..=2147483647` - = help: consider using `u32` instead + = help: consider using the type `u32` instead error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:33:13 @@ -98,7 +98,7 @@ LL | let x = 2147483648_i32; | ^^^^^^^^^^^^^^ | = note: the literal `2147483648_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647` - = help: consider using `u32` instead + = help: consider using the type `u32` instead error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:36:19 @@ -107,7 +107,7 @@ LL | let x: i32 = -2147483649; | ^^^^^^^^^^ | = note: the literal `2147483649` does not fit into the type `i32` whose range is `-2147483648..=2147483647` - = help: consider using `i64` instead + = help: consider using the type `i64` instead error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:37:14 @@ -116,7 +116,7 @@ LL | let x = -2147483649_i32; | ^^^^^^^^^^^^^^ | = note: the literal `2147483649_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647` - = help: consider using `i64` instead + = help: consider using the type `i64` instead error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:38:13 @@ -125,7 +125,7 @@ LL | let x = 2147483648; | ^^^^^^^^^^ | = note: the literal `2147483648` does not fit into the type `i32` whose range is `-2147483648..=2147483647` - = help: consider using `u32` instead + = help: consider using the type `u32` instead error: literal out of range for `i64` --> $DIR/lint-type-overflow.rs:40:13 @@ -134,7 +134,7 @@ LL | let x = 9223372036854775808_i64; | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: the literal `9223372036854775808_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` - = help: consider using `u64` instead + = help: consider using the type `u64` instead error: literal out of range for `i64` --> $DIR/lint-type-overflow.rs:42:13 @@ -143,7 +143,7 @@ LL | let x = 18446744073709551615_i64; | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the literal `18446744073709551615_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` - = help: consider using `u64` instead + = help: consider using the type `u64` instead error: literal out of range for `i64` --> $DIR/lint-type-overflow.rs:43:19 @@ -152,7 +152,7 @@ LL | let x: i64 = -9223372036854775809; | ^^^^^^^^^^^^^^^^^^^ | = note: the literal `9223372036854775809` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` - = help: consider using `i128` instead + = help: consider using the type `i128` instead error: literal out of range for `i64` --> $DIR/lint-type-overflow.rs:44:14 @@ -161,7 +161,7 @@ LL | let x = -9223372036854775809_i64; | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: the literal `9223372036854775809_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` - = help: consider using `i128` instead + = help: consider using the type `i128` instead error: aborting due to 18 previous errors diff --git a/src/test/ui/lint/lint-type-overflow2.stderr b/src/test/ui/lint/lint-type-overflow2.stderr index ab28c4aaf477b..3d40cdf96efdb 100644 --- a/src/test/ui/lint/lint-type-overflow2.stderr +++ b/src/test/ui/lint/lint-type-overflow2.stderr @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ = note: the literal `128` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using `u8` instead + = help: consider using the type `u8` instead error: literal out of range for `f32` --> $DIR/lint-type-overflow2.rs:9:14 diff --git a/src/test/ui/lint/type-overflow.rs b/src/test/ui/lint/type-overflow.rs index e40321e56bf15..6234b794c1f48 100644 --- a/src/test/ui/lint/type-overflow.rs +++ b/src/test/ui/lint/type-overflow.rs @@ -7,16 +7,16 @@ fn main() { let ok = 0b1000_0001; // should be ok -> i32 let ok = 0b0111_1111i8; // should be ok -> 127i8 - let fail = 0b1000_0001i8; //~WARNING literal out of range for i8 + let fail = 0b1000_0001i8; //~WARNING literal out of range for `i8` - let fail = 0x8000_0000_0000_0000i64; //~WARNING literal out of range for i64 + let fail = 0x8000_0000_0000_0000i64; //~WARNING literal out of range for `i64` - let fail = 0x1_FFFF_FFFFu32; //~WARNING literal out of range for u32 + let fail = 0x1_FFFF_FFFFu32; //~WARNING literal out of range for `u32` let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; - //~^ WARNING literal out of range for i128 + //~^ WARNING literal out of range for `i128` - let fail = 0x8FFF_FFFF_FFFF_FFFE; //~WARNING literal out of range for i32 + let fail = 0x8FFF_FFFF_FFFF_FFFE; //~WARNING literal out of range for `i32` - let fail = -0b1111_1111i8; //~WARNING literal out of range for i8 + let fail = -0b1111_1111i8; //~WARNING literal out of range for `i8` } diff --git a/src/test/ui/lint/type-overflow.stderr b/src/test/ui/lint/type-overflow.stderr index dafce414d2fdf..521223e325650 100644 --- a/src/test/ui/lint/type-overflow.stderr +++ b/src/test/ui/lint/type-overflow.stderr @@ -10,55 +10,55 @@ note: the lint level is defined here LL | #![warn(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ = note: the literal `255i8` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using `u8` instead + = help: consider using the type `u8` instead -warning: literal out of range for i8 +warning: literal out of range for `i8` --> $DIR/type-overflow.rs:10:16 | LL | let fail = 0b1000_0001i8; - | ^^^^^^^^^^^^^ help: consider using `u8` instead: `0b1000_0001u8` + | ^^^^^^^^^^^^^ help: consider using the type `u8` instead: `0b1000_0001u8` | = note: the literal `0b1000_0001i8` (decimal `129`) does not fit into the type `i8` and will become `-127i8` -warning: literal out of range for i64 +warning: literal out of range for `i64` --> $DIR/type-overflow.rs:12:16 | LL | let fail = 0x8000_0000_0000_0000i64; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `u64` instead: `0x8000_0000_0000_0000u64` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the type `u64` instead: `0x8000_0000_0000_0000u64` | = note: the literal `0x8000_0000_0000_0000i64` (decimal `9223372036854775808`) does not fit into the type `i64` and will become `-9223372036854775808i64` -warning: literal out of range for u32 +warning: literal out of range for `u32` --> $DIR/type-overflow.rs:14:16 | LL | let fail = 0x1_FFFF_FFFFu32; - | ^^^^^^^^^^^^^^^^ help: consider using `u64` instead: `0x1_FFFF_FFFFu64` + | ^^^^^^^^^^^^^^^^ help: consider using the type `u64` instead: `0x1_FFFF_FFFFu64` | = note: the literal `0x1_FFFF_FFFFu32` (decimal `8589934591`) does not fit into the type `u32` and will become `4294967295u32` -warning: literal out of range for i128 +warning: literal out of range for `i128` --> $DIR/type-overflow.rs:16:22 | LL | let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into the type `i128` and will become `-170141183460469231731687303715884105728i128` - = help: consider using `u128` instead + = help: consider using the type `u128` instead -warning: literal out of range for i32 +warning: literal out of range for `i32` --> $DIR/type-overflow.rs:19:16 | LL | let fail = 0x8FFF_FFFF_FFFF_FFFE; | ^^^^^^^^^^^^^^^^^^^^^ | = note: the literal `0x8FFF_FFFF_FFFF_FFFE` (decimal `10376293541461622782`) does not fit into the type `i32` and will become `-2i32` - = help: consider using `i128` instead + = help: consider using the type `i128` instead -warning: literal out of range for i8 +warning: literal out of range for `i8` --> $DIR/type-overflow.rs:21:17 | LL | let fail = -0b1111_1111i8; - | ^^^^^^^^^^^^^ help: consider using `i16` instead: `0b1111_1111i16` + | ^^^^^^^^^^^^^ help: consider using the type `i16` instead: `0b1111_1111i16` | = note: the literal `0b1111_1111i8` (decimal `255`) does not fit into the type `i8` and will become `-1i8` From a491f51218f93cc6373b28b2f0f753c5c1a5b295 Mon Sep 17 00:00:00 2001 From: Edward Shen Date: Sun, 14 Feb 2021 23:59:45 -0500 Subject: [PATCH 092/103] Use delay_span_bug for mismatched subst/hir arg --- .../borrow_check/diagnostics/region_name.rs | 11 ++--- .../issue-82126-mismatched-subst-and-hir.rs | 25 +++++++++++ ...ssue-82126-mismatched-subst-and-hir.stderr | 43 +++++++++++++++++++ 3 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs create mode 100644 src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs index cbca012824f82..77297ded40d75 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs @@ -634,14 +634,11 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { | GenericArgKind::Const(_), _, ) => { - // I *think* that HIR lowering should ensure this - // doesn't happen, even in erroneous - // programs. Else we should use delay-span-bug. - span_bug!( + // HIR lowering is insufficient in erroneous programs, so + // we need to use delay_span_bug here. See #82126. + self.infcx.tcx.sess.delay_span_bug( hir_arg.span(), - "unmatched subst and hir arg: found {:?} vs {:?}", - kind, - hir_arg, + &format!("unmatched subst and hir arg: found {:?} vs {:?}", kind, hir_arg), ); } } diff --git a/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs b/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs new file mode 100644 index 0000000000000..b6cb617e2f0e7 --- /dev/null +++ b/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs @@ -0,0 +1,25 @@ +// Regression test for #82087. Checks that mismatched lifetimes and types are +// properly handled. + +// edition:2018 + +use std::sync::Mutex; + +struct MarketMultiplier {} + +impl MarketMultiplier { + fn buy(&mut self) -> &mut usize { + todo!() + } +} + +async fn buy_lock(generator: &Mutex) -> LockedMarket<'_> { + //~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument was supplied + //~^^ ERROR this struct takes 1 type argument but 0 type arguments were supplied + LockedMarket(generator.lock().unwrap().buy()) + //~^ ERROR cannot return value referencing temporary value +} + +struct LockedMarket(T); + +fn main() {} diff --git a/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr b/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr new file mode 100644 index 0000000000000..b6844f50488e1 --- /dev/null +++ b/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr @@ -0,0 +1,43 @@ +error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59 + | +LL | async fn buy_lock(generator: &Mutex) -> LockedMarket<'_> { + | ^^^^^^^^^^^^---- help: remove these generics + | | + | expected 0 lifetime arguments + | +note: struct defined here, with 0 lifetime parameters + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8 + | +LL | struct LockedMarket(T); + | ^^^^^^^^^^^^ + +error[E0107]: this struct takes 1 type argument but 0 type arguments were supplied + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59 + | +LL | async fn buy_lock(generator: &Mutex) -> LockedMarket<'_> { + | ^^^^^^^^^^^^ expected 1 type argument + | +note: struct defined here, with 1 type parameter: `T` + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8 + | +LL | struct LockedMarket(T); + | ^^^^^^^^^^^^ - +help: add missing type argument + | +LL | async fn buy_lock(generator: &Mutex) -> LockedMarket<'_, T> { + | ^^^ + +error[E0515]: cannot return value referencing temporary value + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:19:5 + | +LL | LockedMarket(generator.lock().unwrap().buy()) + | ^^^^^^^^^^^^^-------------------------^^^^^^^ + | | | + | | temporary value created here + | returns a value referencing data owned by the current function + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0107, E0515. +For more information about an error, try `rustc --explain E0107`. From f856224e16ef378968114c3811d99bf5cd0e64cb Mon Sep 17 00:00:00 2001 From: Edward Shen Date: Mon, 15 Feb 2021 00:03:57 -0500 Subject: [PATCH 093/103] Fix test issue reference --- src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs b/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs index b6cb617e2f0e7..2e6b88a4beba8 100644 --- a/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs +++ b/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs @@ -1,4 +1,4 @@ -// Regression test for #82087. Checks that mismatched lifetimes and types are +// Regression test for #82126. Checks that mismatched lifetimes and types are // properly handled. // edition:2018 From a4b2fafcc19801e858afc59ed3b319c39adefc20 Mon Sep 17 00:00:00 2001 From: Edward Shen Date: Mon, 15 Feb 2021 00:28:58 -0500 Subject: [PATCH 094/103] Revise HIR lowering comment --- .../rustc_mir/src/borrow_check/diagnostics/region_name.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs index 77297ded40d75..c8b45f87639a2 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs @@ -634,8 +634,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { | GenericArgKind::Const(_), _, ) => { - // HIR lowering is insufficient in erroneous programs, so - // we need to use delay_span_bug here. See #82126. + // HIR lowering sometimes doesn't catch this in erroneous + // programs, so we need to use delay_span_bug here. See #82126. self.infcx.tcx.sess.delay_span_bug( hir_arg.span(), &format!("unmatched subst and hir arg: found {:?} vs {:?}", kind, hir_arg), From aee1e59e6f00876a881e9d8c2ff00e0f11f896eb Mon Sep 17 00:00:00 2001 From: mark Date: Sun, 7 Feb 2021 20:40:33 -0600 Subject: [PATCH 095/103] Simplify pattern grammar by allowing nested leading vert Along the way, we also implement a handful of diagnostics improvements and fixes, particularly with respect to the special handling of `||` in place of `|` and when there are leading verts in function params, which don't allow top-level or-patterns anyway. --- compiler/rustc_expand/src/expand.rs | 6 +- .../rustc_parse/src/parser/diagnostics.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 8 +- compiler/rustc_parse/src/parser/mod.rs | 1 + .../rustc_parse/src/parser/nonterminal.rs | 4 +- compiler/rustc_parse/src/parser/pat.rs | 183 ++++++++++-------- compiler/rustc_parse/src/parser/stmt.rs | 2 +- .../feature-gate-or_patterns.stderr | 8 +- .../ui/or-patterns/fn-param-wrap-parens.fixed | 2 +- .../ui/or-patterns/fn-param-wrap-parens.rs | 2 +- .../or-patterns/fn-param-wrap-parens.stderr | 4 +- .../ui/or-patterns/multiple-pattern-typo.rs | 14 +- .../or-patterns/multiple-pattern-typo.stderr | 14 +- .../or-patterns/or-patterns-syntactic-fail.rs | 25 +-- .../or-patterns-syntactic-fail.stderr | 91 +-------- .../ui/or-patterns/remove-leading-vert.fixed | 26 +-- .../ui/or-patterns/remove-leading-vert.rs | 26 +-- .../ui/or-patterns/remove-leading-vert.stderr | 72 ++----- 18 files changed, 188 insertions(+), 302 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 870b5c92d8983..8c5395b12abce 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -22,7 +22,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, PResult}; use rustc_feature::Features; -use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser}; +use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, GateOr, Parser, RecoverComma}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; use rustc_session::lint::BuiltinLintDiagnostics; @@ -914,7 +914,9 @@ pub fn parse_ast_fragment<'a>( } } AstFragmentKind::Ty => AstFragment::Ty(this.parse_ty()?), - AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat(None)?), + AstFragmentKind::Pat => { + AstFragment::Pat(this.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)?) + } AstFragmentKind::Arms | AstFragmentKind::Fields | AstFragmentKind::FieldPats diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 5512e849c451d..0f49386dec07b 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1654,7 +1654,7 @@ impl<'a> Parser<'a> { } pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P, P)> { - let pat = self.parse_pat(Some("argument name"))?; + let pat = self.parse_pat_no_top_alt(Some("argument name"))?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 20430ece05b06..59fd060aa2465 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1726,7 +1726,7 @@ impl<'a> Parser<'a> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { - let pat = this.parse_pat(PARAM_EXPECTED)?; + let pat = this.parse_pat_no_top_alt(PARAM_EXPECTED)?; let ty = if this.eat(&token::Colon) { this.parse_ty()? } else { @@ -1803,7 +1803,7 @@ impl<'a> Parser<'a> { /// The `let` token has already been eaten. fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; - let pat = self.parse_top_pat(GateOr::No, RecoverComma::Yes)?; + let pat = self.parse_pat_allow_top_alt(None, GateOr::No, RecoverComma::Yes)?; self.expect(&token::Eq)?; let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| { this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into()) @@ -1866,7 +1866,7 @@ impl<'a> Parser<'a> { _ => None, }; - let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?; + let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::Yes)?; if !self.eat_keyword(kw::In) { self.error_missing_in_for_loop(); } @@ -1977,7 +1977,7 @@ impl<'a> Parser<'a> { let attrs = self.parse_outer_attributes()?; self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; - let pat = this.parse_top_pat(GateOr::No, RecoverComma::Yes)?; + let pat = this.parse_pat_allow_top_alt(None, GateOr::No, RecoverComma::Yes)?; let guard = if this.eat_keyword(kw::If) { let if_span = this.prev_token.span; let cond = this.parse_expr()?; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 18013f1250bdb..ace4134b1f698 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -14,6 +14,7 @@ use crate::lexer::UnmatchedBrace; pub use attr_wrapper::AttrWrapper; pub use diagnostics::AttemptLocalParseRecovery; use diagnostics::Error; +pub use pat::{GateOr, RecoverComma}; pub use path::PathStyle; use rustc_ast::ptr::P; diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 40dd938f000e3..a84ae5151442d 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -120,9 +120,9 @@ impl<'a> Parser<'a> { }, NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => { token::NtPat(self.collect_tokens_no_attrs(|this| match kind { - NonterminalKind::Pat2018 { .. } => this.parse_pat(None), + NonterminalKind::Pat2018 { .. } => this.parse_pat_no_top_alt(None), NonterminalKind::Pat2021 { .. } => { - this.parse_top_pat(GateOr::Yes, RecoverComma::No) + this.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No) } _ => unreachable!(), })?) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 317ef84742c21..8874548da784d 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -19,14 +19,14 @@ const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here" /// Whether or not an or-pattern should be gated when occurring in the current context. #[derive(PartialEq, Clone, Copy)] -pub(super) enum GateOr { +pub enum GateOr { Yes, No, } /// Whether or not to recover a `,` when parsing or-patterns. #[derive(PartialEq, Copy, Clone)] -pub(super) enum RecoverComma { +pub enum RecoverComma { Yes, No, } @@ -37,80 +37,57 @@ impl<'a> Parser<'a> { /// Corresponds to `pat` in RFC 2535 and does not admit or-patterns /// at the top level. Used when parsing the parameters of lambda expressions, /// functions, function pointers, and `pat` macro fragments. - pub fn parse_pat(&mut self, expected: Expected) -> PResult<'a, P> { + pub fn parse_pat_no_top_alt(&mut self, expected: Expected) -> PResult<'a, P> { self.parse_pat_with_range_pat(true, expected) } - /// Entry point to the main pattern parser. + /// Parses a pattern. + /// /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. - pub(super) fn parse_top_pat( + /// Used for parsing patterns in all cases when `pat` is not used. + /// + /// Note that after the FCP in , + /// a leading vert is allowed in nested or-patterns, too. This allows us to + /// simplify the grammar somewhat. + pub fn parse_pat_allow_top_alt( &mut self, + expected: Expected, gate_or: GateOr, rc: RecoverComma, ) -> PResult<'a, P> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). - let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes; - let leading_vert_span = self.prev_token.span; - - // Parse the possibly-or-pattern. - let pat = self.parse_pat_with_or(None, gate_or, rc)?; - - // If we parsed a leading `|` which should be gated, - // and no other gated or-pattern has been parsed thus far, - // then we should really gate the leading `|`. - // This complicated procedure is done purely for diagnostics UX. - if gated_leading_vert && self.sess.gated_spans.is_ungated(sym::or_patterns) { - self.sess.gated_spans.gate(sym::or_patterns, leading_vert_span); - } - - Ok(pat) - } - - /// Parse the pattern for a function or function pointer parameter. - /// Special recovery is provided for or-patterns and leading `|`. - pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P> { - self.recover_leading_vert(None, "not allowed in a parameter pattern"); - let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?; - - if let PatKind::Or(..) = &pat.kind { - self.ban_illegal_fn_param_or_pat(&pat); - } - - Ok(pat) - } + let leading_vert_span = + if self.eat_or_separator(None) { Some(self.prev_token.span) } else { None }; - /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens. - fn ban_illegal_fn_param_or_pat(&self, pat: &Pat) { - let msg = "wrap the pattern in parenthesis"; - let fix = format!("({})", pprust::pat_to_string(pat)); - self.struct_span_err(pat.span, "an or-pattern parameter must be wrapped in parenthesis") - .span_suggestion(pat.span, msg, fix, Applicability::MachineApplicable) - .emit(); - } - - /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). - /// Corresponds to `pat` in RFC 2535. - fn parse_pat_with_or( - &mut self, - expected: Expected, - gate_or: GateOr, - rc: RecoverComma, - ) -> PResult<'a, P> { // Parse the first pattern (`p_0`). - let first_pat = self.parse_pat(expected)?; + let first_pat = self.parse_pat_no_top_alt(expected)?; self.maybe_recover_unexpected_comma(first_pat.span, rc, gate_or)?; // If the next token is not a `|`, // this is not an or-pattern and we should exit here. if !self.check(&token::BinOp(token::Or)) && self.token != token::OrOr { + // If we parsed a leading `|` which should be gated, + // then we should really gate the leading `|`. + // This complicated procedure is done purely for diagnostics UX. + if let Some(leading_vert_span) = leading_vert_span { + if gate_or == GateOr::Yes && self.sess.gated_spans.is_ungated(sym::or_patterns) { + self.sess.gated_spans.gate(sym::or_patterns, leading_vert_span); + } + + // If there was a leading vert, treat this as an or-pattern. This improves + // diagnostics. + let span = leading_vert_span.to(self.prev_token.span); + return Ok(self.mk_pat(span, PatKind::Or(vec![first_pat]))); + } + return Ok(first_pat); } // Parse the patterns `p_1 | ... | p_n` where `n > 0`. - let lo = first_pat.span; + let lo = leading_vert_span.unwrap_or(first_pat.span); let mut pats = vec![first_pat]; while self.eat_or_separator(Some(lo)) { - let pat = self.parse_pat(expected).map_err(|mut err| { + let pat = self.parse_pat_no_top_alt(expected).map_err(|mut err| { err.span_label(lo, WHILE_PARSING_OR_MSG); err })?; @@ -127,6 +104,62 @@ impl<'a> Parser<'a> { Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats))) } + /// Parse the pattern for a function or function pointer parameter. + pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P> { + // We actually do _not_ allow top-level or-patterns in function params, but we use + // `parse_pat_allow_top_alt` anyway so that we can detect when a user tries to use it. This + // allows us to print a better error message. + // + // In order to get good UX, we first recover in the case of a leading vert for an illegal + // top-level or-pat. Normally, this means recovering both `|` and `||`, but in this case, + // a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that + // separately. + if let token::OrOr = self.token.kind { + let span = self.token.span; + let mut err = self.struct_span_err(span, "unexpected `||` before function parameter"); + err.span_suggestion( + span, + "remove the `||`", + String::new(), + Applicability::MachineApplicable, + ); + err.note("alternatives in or-patterns are separated with `|`, not `||`"); + err.emit(); + self.bump(); + } + + let pat = self.parse_pat_allow_top_alt(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?; + + if let PatKind::Or(..) = &pat.kind { + self.ban_illegal_fn_param_or_pat(&pat); + } + + Ok(pat) + } + + /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens. + fn ban_illegal_fn_param_or_pat(&self, pat: &Pat) { + // If all we have a leading vert, then print a special message. This is the case if + // `parse_pat_allow_top_alt` returns an or-pattern with one variant. + let (msg, fix) = match &pat.kind { + PatKind::Or(pats) if pats.len() == 1 => { + let msg = "remove the leading `|`"; + let fix = pprust::pat_to_string(pat); + (msg, fix) + } + + _ => { + let msg = "wrap the pattern in parentheses"; + let fix = format!("({})", pprust::pat_to_string(pat)); + (msg, fix) + } + }; + + self.struct_span_err(pat.span, "an or-pattern parameter must be wrapped in parentheses") + .span_suggestion(pat.span, msg, fix, Applicability::MachineApplicable) + .emit(); + } + /// Eat the or-pattern `|` separator. /// If instead a `||` token is encountered, recover and pretend we parsed `|`. fn eat_or_separator(&mut self, lo: Option) -> bool { @@ -179,7 +212,7 @@ impl<'a> Parser<'a> { /// We have parsed `||` instead of `|`. Error and suggest `|` instead. fn ban_unexpected_or_or(&mut self, lo: Option) { - let mut err = self.struct_span_err(self.token.span, "unexpected token `||` after pattern"); + let mut err = self.struct_span_err(self.token.span, "unexpected token `||` in pattern"); err.span_suggestion( self.token.span, "use a single `|` to separate multiple alternative patterns", @@ -244,7 +277,7 @@ impl<'a> Parser<'a> { /// sequence of patterns until `)` is reached. fn skip_pat_list(&mut self) -> PResult<'a, ()> { while !self.check(&token::CloseDelim(token::Paren)) { - self.parse_pat(None)?; + self.parse_pat_no_top_alt(None)?; if !self.eat(&token::Comma) { return Ok(()); } @@ -252,22 +285,6 @@ impl<'a> Parser<'a> { Ok(()) } - /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. - /// See `parse_pat_with_or` for details on parsing or-patterns. - fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P> { - self.recover_leading_vert(None, "only allowed in a top-level pattern"); - self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No) - } - - /// Recover if `|` or `||` is here. - /// The user is thinking that a leading `|` is allowed in this position. - fn recover_leading_vert(&mut self, lo: Option, ctx: &str) { - if let token::BinOp(token::Or) | token::OrOr = self.token.kind { - self.ban_illegal_vert(lo, "leading", ctx); - self.bump(); - } - } - /// A `|` or possibly `||` token shouldn't be here. Ban it. fn ban_illegal_vert(&mut self, lo: Option, pos: &str, ctx: &str) { let span = self.token.span; @@ -305,8 +322,9 @@ impl<'a> Parser<'a> { self.parse_pat_tuple_or_parens()? } else if self.check(&token::OpenDelim(token::Bracket)) { // Parse `[pat, pat,...]` as a slice pattern. - let (pats, _) = - self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat_with_or_inner())?; + let (pats, _) = self.parse_delim_comma_seq(token::Bracket, |p| { + p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No) + })?; PatKind::Slice(pats) } else if self.check(&token::DotDot) && !self.is_pat_range_end_start(1) { // A rest pattern `..`. @@ -429,7 +447,7 @@ impl<'a> Parser<'a> { // At this point we attempt to parse `@ $pat_rhs` and emit an error. self.bump(); // `@` - let mut rhs = self.parse_pat(None)?; + let mut rhs = self.parse_pat_no_top_alt(None)?; let sp = lhs.span.to(rhs.span); if let PatKind::Ident(_, _, ref mut sub @ None) = rhs.kind { @@ -518,8 +536,9 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { - let (fields, trailing_comma) = - self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?; + let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { + p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No) + })?; // Here, `(pat,)` is a tuple pattern. // For backward compatibility, `(..)` is a tuple pattern as well. @@ -548,7 +567,7 @@ impl<'a> Parser<'a> { } // Parse the pattern we hope to be an identifier. - let mut pat = self.parse_pat(Some("identifier"))?; + let mut pat = self.parse_pat_no_top_alt(Some("identifier"))?; // If we don't have `mut $ident (@ pat)?`, error. if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind { @@ -793,7 +812,7 @@ impl<'a> Parser<'a> { fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind> { let ident = self.parse_ident()?; let sub = if self.eat(&token::At) { - Some(self.parse_pat(Some("binding pattern"))?) + Some(self.parse_pat_no_top_alt(Some("binding pattern"))?) } else { None }; @@ -832,7 +851,9 @@ impl<'a> Parser<'a> { if qself.is_some() { return self.error_qpath_before_pat(&path, "("); } - let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?; + let (fields, _) = self.parse_paren_comma_seq(|p| { + p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No) + })?; Ok(PatKind::TupleStruct(path, fields)) } @@ -998,7 +1019,7 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form `fieldname: pat`. let fieldname = self.parse_field_name()?; self.bump(); - let pat = self.parse_pat_with_or_inner()?; + let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)?; hi = pat.span; (pat, fieldname, false) } else { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index e36ebd5e48113..2e00ddfaacc81 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -220,7 +220,7 @@ impl<'a> Parser<'a> { /// Parses a local variable declaration. fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; - let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?; + let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::Yes)?; let (err, ty) = if self.eat(&token::Colon) { // Save the state of the parser before parsing type normally, in case there is a `:` diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns.stderr index a9e43a4575da0..c01d17c0b3d7e 100644 --- a/src/test/ui/or-patterns/feature-gate-or_patterns.stderr +++ b/src/test/ui/or-patterns/feature-gate-or_patterns.stderr @@ -8,10 +8,10 @@ LL | Some(0 | 1 | 2) => {} = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:28:11 + --> $DIR/feature-gate-or_patterns.rs:28:9 | LL | let | A | B; - | ^^^^^ + | ^^^^^^^ | = note: see issue #54883 for more information = help: add `#![feature(or_patterns)]` to the crate attributes to enable @@ -26,10 +26,10 @@ LL | let A | B; = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:30:11 + --> $DIR/feature-gate-or_patterns.rs:30:9 | LL | for | A | B in 0 {} - | ^^^^^ + | ^^^^^^^ | = note: see issue #54883 for more information = help: add `#![feature(or_patterns)]` to the crate attributes to enable diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.fixed b/src/test/ui/or-patterns/fn-param-wrap-parens.fixed index 08730fe8b07b7..bbc75d2b411eb 100644 --- a/src/test/ui/or-patterns/fn-param-wrap-parens.fixed +++ b/src/test/ui/or-patterns/fn-param-wrap-parens.fixed @@ -11,4 +11,4 @@ enum E { A, B } use E::*; #[cfg(FALSE)] -fn fun1((A | B): E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis +fn fun1((A | B): E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.rs b/src/test/ui/or-patterns/fn-param-wrap-parens.rs index ed667e0e66067..65b93dcbf7467 100644 --- a/src/test/ui/or-patterns/fn-param-wrap-parens.rs +++ b/src/test/ui/or-patterns/fn-param-wrap-parens.rs @@ -11,4 +11,4 @@ enum E { A, B } use E::*; #[cfg(FALSE)] -fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis +fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.stderr b/src/test/ui/or-patterns/fn-param-wrap-parens.stderr index 2c6e4d9838ddc..0e6424a430043 100644 --- a/src/test/ui/or-patterns/fn-param-wrap-parens.stderr +++ b/src/test/ui/or-patterns/fn-param-wrap-parens.stderr @@ -1,8 +1,8 @@ -error: an or-pattern parameter must be wrapped in parenthesis +error: an or-pattern parameter must be wrapped in parentheses --> $DIR/fn-param-wrap-parens.rs:14:9 | LL | fn fun1(A | B: E) {} - | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` + | ^^^^^ help: wrap the pattern in parentheses: `(A | B)` error: aborting due to previous error diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.rs b/src/test/ui/or-patterns/multiple-pattern-typo.rs index 702c9573741e7..4d06101044f6c 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.rs +++ b/src/test/ui/or-patterns/multiple-pattern-typo.rs @@ -4,41 +4,41 @@ fn main() { let x = 3; match x { - 1 | 2 || 3 => (), //~ ERROR unexpected token `||` after pattern + 1 | 2 || 3 => (), //~ ERROR unexpected token `||` in pattern _ => (), } match x { - (1 | 2 || 3) => (), //~ ERROR unexpected token `||` after pattern + (1 | 2 || 3) => (), //~ ERROR unexpected token `||` in pattern _ => (), } match (x,) { - (1 | 2 || 3,) => (), //~ ERROR unexpected token `||` after pattern + (1 | 2 || 3,) => (), //~ ERROR unexpected token `||` in pattern _ => (), } struct TS(u8); match TS(x) { - TS(1 | 2 || 3) => (), //~ ERROR unexpected token `||` after pattern + TS(1 | 2 || 3) => (), //~ ERROR unexpected token `||` in pattern _ => (), } struct NS { f: u8 } match (NS { f: x }) { - NS { f: 1 | 2 || 3 } => (), //~ ERROR unexpected token `||` after pattern + NS { f: 1 | 2 || 3 } => (), //~ ERROR unexpected token `||` in pattern _ => (), } match [x] { - [1 | 2 || 3] => (), //~ ERROR unexpected token `||` after pattern + [1 | 2 || 3] => (), //~ ERROR unexpected token `||` in pattern _ => (), } match x { - || 1 | 2 | 3 => (), //~ ERROR unexpected token `||` after pattern + || 1 | 2 | 3 => (), //~ ERROR unexpected token `||` in pattern _ => (), } } diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.stderr b/src/test/ui/or-patterns/multiple-pattern-typo.stderr index cb32068ec0d5e..b0a82b3673b83 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.stderr +++ b/src/test/ui/or-patterns/multiple-pattern-typo.stderr @@ -1,4 +1,4 @@ -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:7:15 | LL | 1 | 2 || 3 => (), @@ -6,7 +6,7 @@ LL | 1 | 2 || 3 => (), | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:12:16 | LL | (1 | 2 || 3) => (), @@ -14,7 +14,7 @@ LL | (1 | 2 || 3) => (), | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:17:16 | LL | (1 | 2 || 3,) => (), @@ -22,7 +22,7 @@ LL | (1 | 2 || 3,) => (), | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:24:18 | LL | TS(1 | 2 || 3) => (), @@ -30,7 +30,7 @@ LL | TS(1 | 2 || 3) => (), | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:31:23 | LL | NS { f: 1 | 2 || 3 } => (), @@ -38,7 +38,7 @@ LL | NS { f: 1 | 2 || 3 } => (), | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:36:16 | LL | [1 | 2 || 3] => (), @@ -46,7 +46,7 @@ LL | [1 | 2 || 3] => (), | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:41:9 | LL | || 1 | 2 | 3 => (), diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs index efe90b3e3c60c..cbc24eb26fa47 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs @@ -14,29 +14,8 @@ fn no_top_level_or_patterns() { // -------- This looks like an or-pattern but is in fact `|A| (B: E | ())`. // ...and for now neither do we allow or-patterns at the top level of functions. - fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis + fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses fn fun2(| A | B: E) {} - //~^ ERROR a leading `|` is not allowed in a parameter pattern - //~| ERROR an or-pattern parameter must be wrapped in parenthesis -} - -// We also do not allow a leading `|` when not in a top level position: - -fn no_leading_inner() { - struct TS(E); - struct NS { f: E } - - let ( | A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern - let ( | A | B,) = (E::B,); //~ ERROR a leading `|` is only allowed in a top-level pattern - let [ | A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern - let TS( | A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern - let NS { f: | A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern - - let ( || A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern - let [ || A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern - let TS( || A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern - let NS { f: || A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern - - let recovery_witness: String = 0; //~ ERROR mismatched types + //~^ ERROR an or-pattern parameter must be wrapped in parentheses } diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index 989aeb5200645..db4d827757b03 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -1,82 +1,14 @@ -error: an or-pattern parameter must be wrapped in parenthesis +error: an or-pattern parameter must be wrapped in parentheses --> $DIR/or-patterns-syntactic-fail.rs:17:13 | LL | fn fun1(A | B: E) {} - | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` + | ^^^^^ help: wrap the pattern in parentheses: `(A | B)` -error: a leading `|` is not allowed in a parameter pattern +error: an or-pattern parameter must be wrapped in parentheses --> $DIR/or-patterns-syntactic-fail.rs:19:13 | LL | fn fun2(| A | B: E) {} - | ^ help: remove the `|` - -error: an or-pattern parameter must be wrapped in parenthesis - --> $DIR/or-patterns-syntactic-fail.rs:19:15 - | -LL | fn fun2(| A | B: E) {} - | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:30:11 - | -LL | let ( | A | B) = E::A; - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:31:11 - | -LL | let ( | A | B,) = (E::B,); - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:32:11 - | -LL | let [ | A | B ] = [E::A]; - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:33:13 - | -LL | let TS( | A | B ); - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:34:17 - | -LL | let NS { f: | A | B }; - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:36:11 - | -LL | let ( || A | B) = E::A; - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:37:11 - | -LL | let [ || A | B ] = [E::A]; - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:38:13 - | -LL | let TS( || A | B ); - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:39:17 - | -LL | let NS { f: || A | B }; - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` + | ^^^^^^^ help: wrap the pattern in parentheses: `(A | B)` error[E0369]: no implementation for `E | ()` --> $DIR/or-patterns-syntactic-fail.rs:13:22 @@ -88,17 +20,6 @@ LL | let _ = |A | B: E| (); | = note: an implementation of `std::ops::BitOr` might be missing for `E` -error[E0308]: mismatched types - --> $DIR/or-patterns-syntactic-fail.rs:41:36 - | -LL | let recovery_witness: String = 0; - | ------ ^ - | | | - | | expected struct `String`, found integer - | | help: try using a conversion method: `0.to_string()` - | expected due to this - -error: aborting due to 14 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0308, E0369. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/or-patterns/remove-leading-vert.fixed b/src/test/ui/or-patterns/remove-leading-vert.fixed index 443ef398293d9..c8fac4faa2a66 100644 --- a/src/test/ui/or-patterns/remove-leading-vert.fixed +++ b/src/test/ui/or-patterns/remove-leading-vert.fixed @@ -9,17 +9,17 @@ fn main() {} #[cfg(FALSE)] fn leading() { - fn fun1( A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern - fn fun2( A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern - let ( A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern - let ( A): (E); //~ ERROR a leading `|` is only allowed in a top-level pattern - let ( A,): (E,); //~ ERROR a leading `|` is only allowed in a top-level pattern - let [ A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern - let [ A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern - let TS( A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern - let TS( A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern - let NS { f: A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern - let NS { f: A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern + fn fun1( A: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses + fn fun2( A: E) {} //~ ERROR unexpected `||` before function parameter + let ( | A): E; + let ( | A): (E); //~ ERROR unexpected token `||` in pattern + let ( | A,): (E,); + let [ | A ]: [E; 1]; + let [ | A ]: [E; 1]; //~ ERROR unexpected token `||` in pattern + let TS( | A ): TS; + let TS( | A ): TS; //~ ERROR unexpected token `||` in pattern + let NS { f: | A }: NS; + let NS { f: | A }: NS; //~ ERROR unexpected token `||` in pattern } #[cfg(FALSE)] @@ -29,12 +29,12 @@ fn trailing() { let ( A | B ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern let [ A | B ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern let S { f: B }; //~ ERROR a trailing `|` is not allowed in an or-pattern - let ( A | B ): E; //~ ERROR unexpected token `||` after pattern + let ( A | B ): E; //~ ERROR unexpected token `||` in pattern //~^ ERROR a trailing `|` is not allowed in an or-pattern match A { A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern - A | B => {} //~ ERROR unexpected token `||` after pattern + A | B => {} //~ ERROR unexpected token `||` in pattern //~^ ERROR a trailing `|` is not allowed in an or-pattern | A | B => {} //~^ ERROR a trailing `|` is not allowed in an or-pattern diff --git a/src/test/ui/or-patterns/remove-leading-vert.rs b/src/test/ui/or-patterns/remove-leading-vert.rs index 3c427a6f7b23e..2cf6b27ab1aac 100644 --- a/src/test/ui/or-patterns/remove-leading-vert.rs +++ b/src/test/ui/or-patterns/remove-leading-vert.rs @@ -9,17 +9,17 @@ fn main() {} #[cfg(FALSE)] fn leading() { - fn fun1( | A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern - fn fun2( || A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern - let ( | A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern - let ( || A): (E); //~ ERROR a leading `|` is only allowed in a top-level pattern - let ( | A,): (E,); //~ ERROR a leading `|` is only allowed in a top-level pattern - let [ | A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern - let [ || A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern - let TS( | A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern - let TS( || A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern - let NS { f: | A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern - let NS { f: || A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern + fn fun1( | A: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses + fn fun2( || A: E) {} //~ ERROR unexpected `||` before function parameter + let ( | A): E; + let ( || A): (E); //~ ERROR unexpected token `||` in pattern + let ( | A,): (E,); + let [ | A ]: [E; 1]; + let [ || A ]: [E; 1]; //~ ERROR unexpected token `||` in pattern + let TS( | A ): TS; + let TS( || A ): TS; //~ ERROR unexpected token `||` in pattern + let NS { f: | A }: NS; + let NS { f: || A }: NS; //~ ERROR unexpected token `||` in pattern } #[cfg(FALSE)] @@ -29,12 +29,12 @@ fn trailing() { let ( A | B | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern let [ A | B | ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern let S { f: B | }; //~ ERROR a trailing `|` is not allowed in an or-pattern - let ( A || B | ): E; //~ ERROR unexpected token `||` after pattern + let ( A || B | ): E; //~ ERROR unexpected token `||` in pattern //~^ ERROR a trailing `|` is not allowed in an or-pattern match A { A | => {} //~ ERROR a trailing `|` is not allowed in an or-pattern A || => {} //~ ERROR a trailing `|` is not allowed in an or-pattern - A || B | => {} //~ ERROR unexpected token `||` after pattern + A || B | => {} //~ ERROR unexpected token `||` in pattern //~^ ERROR a trailing `|` is not allowed in an or-pattern | A | B | => {} //~^ ERROR a trailing `|` is not allowed in an or-pattern diff --git a/src/test/ui/or-patterns/remove-leading-vert.stderr b/src/test/ui/or-patterns/remove-leading-vert.stderr index 53025230a63c2..5c9efd44a187f 100644 --- a/src/test/ui/or-patterns/remove-leading-vert.stderr +++ b/src/test/ui/or-patterns/remove-leading-vert.stderr @@ -1,10 +1,10 @@ -error: a leading `|` is not allowed in a parameter pattern +error: an or-pattern parameter must be wrapped in parentheses --> $DIR/remove-leading-vert.rs:12:14 | LL | fn fun1( | A: E) {} - | ^ help: remove the `|` + | ^^^ help: remove the leading `|`: `A` -error: a leading `|` is not allowed in a parameter pattern +error: unexpected `||` before function parameter --> $DIR/remove-leading-vert.rs:13:14 | LL | fn fun2( || A: E) {} @@ -12,67 +12,29 @@ LL | fn fun2( || A: E) {} | = note: alternatives in or-patterns are separated with `|`, not `||` -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/remove-leading-vert.rs:14:11 - | -LL | let ( | A): E; - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern +error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:15:11 | LL | let ( || A): (E); - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/remove-leading-vert.rs:16:11 - | -LL | let ( | A,): (E,); - | ^ help: remove the `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/remove-leading-vert.rs:17:11 - | -LL | let [ | A ]: [E; 1]; - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern +error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:18:11 | LL | let [ || A ]: [E; 1]; - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/remove-leading-vert.rs:19:13 - | -LL | let TS( | A ): TS; - | ^ help: remove the `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` -error: a leading `|` is only allowed in a top-level pattern +error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:20:13 | LL | let TS( || A ): TS; - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/remove-leading-vert.rs:21:17 - | -LL | let NS { f: | A }: NS; - | ^ help: remove the `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` -error: a leading `|` is only allowed in a top-level pattern +error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:22:17 | LL | let NS { f: || A }: NS; - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:27:13 @@ -114,7 +76,7 @@ LL | let S { f: B | }; | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:32:13 | LL | let ( A || B | ): E; @@ -148,7 +110,7 @@ LL | A || => {} | = note: alternatives in or-patterns are separated with `|`, not `||` -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:37:11 | LL | A || B | => {} @@ -168,9 +130,9 @@ error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:39:17 | LL | | A | B | => {} - | - ^ help: remove the `|` - | | - | while parsing this or-pattern starting here + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:43:11 @@ -196,5 +158,5 @@ LL | let a | ; | | | while parsing this or-pattern starting here -error: aborting due to 26 previous errors +error: aborting due to 21 previous errors From b86c5db96eecbf6f4b08cd3f29d5a5b4dae13aee Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Thu, 4 Feb 2021 02:12:31 -0500 Subject: [PATCH 096/103] Implement reborrow for closure captures --- compiler/rustc_typeck/src/check/upvar.rs | 103 +++++++++++------- .../2229_closure_analysis/by_value.rs | 3 +- .../2229_closure_analysis/by_value.stderr | 11 +- .../2229_closure_analysis/move_closure.rs | 8 +- .../2229_closure_analysis/move_closure.stderr | 8 +- .../run_pass/move_closure.rs | 41 +++++++ 6 files changed, 121 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index d097f863ad2f9..79c60ab3cfe0f 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -180,7 +180,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("seed place {:?}", place); let upvar_id = ty::UpvarId::new(*var_hir_id, local_def_id); - let capture_kind = self.init_capture_kind(capture_clause, upvar_id, span); + let capture_kind = + self.init_capture_kind_for_place(&place, capture_clause, upvar_id, span); let fake_info = ty::CaptureInfo { capture_kind_expr_id: None, path_expr_id: None, @@ -449,7 +450,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base => bug!("Expected upvar, found={:?}", base), }; - let place = restrict_capture_precision(place, capture_info.capture_kind); + let place = restrict_capture_precision(place); let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) { None => { @@ -897,15 +898,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn init_capture_kind( + fn init_capture_kind_for_place( &self, + place: &Place<'tcx>, capture_clause: hir::CaptureBy, upvar_id: ty::UpvarId, closure_span: Span, ) -> ty::UpvarCapture<'tcx> { match capture_clause { - hir::CaptureBy::Value => ty::UpvarCapture::ByValue(None), - hir::CaptureBy::Ref => { + // In case of a move closure if the data is accessed through a reference we + // want to capture by ref to allow precise capture using reborrows. + // + // If the data will be moved out of this place, then the place will be truncated + // at the first Deref in `adjust_upvar_borrow_kind_for_consume` and then moved into + // the closure. + hir::CaptureBy::Value if !place.deref_tys().any(ty::TyS::is_ref) => { + ty::UpvarCapture::ByValue(None) + } + hir::CaptureBy::Value | hir::CaptureBy::Ref => { let origin = UpvarRegion(upvar_id, closure_span); let upvar_region = self.next_region_var(origin); let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region }; @@ -1109,12 +1119,18 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { place_with_id, diag_expr_id, mode ); - // we only care about moves - match mode { - euv::Copy => { - return; - } - euv::Move => {} + let place = truncate_capture_for_move(place_with_id.place.clone()); + match (self.capture_clause, mode) { + // In non-move closures, we only care about moves + (hir::CaptureBy::Ref, euv::Copy) => return, + + (hir::CaptureBy::Ref, euv::Move) | (hir::CaptureBy::Value, euv::Move | euv::Copy) => {} + }; + + let place_with_id = PlaceWithHirId { place: place.clone(), hir_id: place_with_id.hir_id }; + + if !self.capture_information.contains_key(&place) { + self.init_capture_info_for_place(&place_with_id, diag_expr_id); } let tcx = self.fcx.tcx; @@ -1128,13 +1144,15 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { let usage_span = tcx.hir().span(diag_expr_id); - // To move out of an upvar, this must be a FnOnce closure - self.adjust_closure_kind( - upvar_id.closure_expr_id, - ty::ClosureKind::FnOnce, - usage_span, - place_with_id.place.clone(), - ); + if matches!(mode, euv::Move) { + // To move out of an upvar, this must be a FnOnce closure + self.adjust_closure_kind( + upvar_id.closure_expr_id, + ty::ClosureKind::FnOnce, + usage_span, + place.clone(), + ); + } let capture_info = ty::CaptureInfo { capture_kind_expr_id: Some(diag_expr_id), @@ -1317,8 +1335,12 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id); - let capture_kind = - self.fcx.init_capture_kind(self.capture_clause, upvar_id, self.closure_span); + let capture_kind = self.fcx.init_capture_kind_for_place( + &place_with_id.place, + self.capture_clause, + upvar_id, + self.closure_span, + ); let expr_id = Some(diag_expr_id); let capture_info = ty::CaptureInfo { @@ -1392,15 +1414,10 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { } /// Truncate projections so that following rules are obeyed by the captured `place`: -/// -/// - No Derefs in move closure, this will result in value behind a reference getting moved. /// - No projections are applied to raw pointers, since these require unsafe blocks. We capture /// them completely. /// - No Index projections are captured, since arrays are captured completely. -fn restrict_capture_precision<'tcx>( - mut place: Place<'tcx>, - capture_kind: ty::UpvarCapture<'tcx>, -) -> Place<'tcx> { +fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> { if place.projections.is_empty() { // Nothing to do here return place; @@ -1412,7 +1429,6 @@ fn restrict_capture_precision<'tcx>( } let mut truncated_length = usize::MAX; - let mut first_deref_projection = usize::MAX; for (i, proj) in place.projections.iter().enumerate() { if proj.ty.is_unsafe_ptr() { @@ -1426,31 +1442,36 @@ fn restrict_capture_precision<'tcx>( truncated_length = truncated_length.min(i); break; } - ProjectionKind::Deref => { - // We only drop Derefs in case of move closures - // There might be an index projection or raw ptr ahead, so we don't stop here. - first_deref_projection = first_deref_projection.min(i); - } + ProjectionKind::Deref => {} ProjectionKind::Field(..) => {} // ignore ProjectionKind::Subslice => {} // We never capture this } } - let length = place - .projections - .len() - .min(truncated_length) - // In case of capture `ByValue` we want to not capture derefs - .min(match capture_kind { - ty::UpvarCapture::ByValue(..) => first_deref_projection, - ty::UpvarCapture::ByRef(..) => usize::MAX, - }); + let length = place.projections.len().min(truncated_length); place.projections.truncate(length); place } +/// Truncates a place so that the resultant capture doesn't move data out of a reference +fn truncate_capture_for_move(mut place: Place<'tcx>) -> Place<'tcx> { + for (i, proj) in place.projections.iter().enumerate() { + match proj.kind { + ProjectionKind::Deref => { + // We only drop Derefs in case of move closures + // There might be an index projection or raw ptr ahead, so we don't stop here. + place.projections.truncate(i); + return place; + } + _ => {} + } + } + + place +} + fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String { let variable_name = match place.base { PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(), diff --git a/src/test/ui/closures/2229_closure_analysis/by_value.rs b/src/test/ui/closures/2229_closure_analysis/by_value.rs index 1007fb582e5ed..27c8fb1363f17 100644 --- a/src/test/ui/closures/2229_closure_analysis/by_value.rs +++ b/src/test/ui/closures/2229_closure_analysis/by_value.rs @@ -26,7 +26,8 @@ fn big_box() { //~^ First Pass analysis includes: //~| Min Capture analysis includes: let p = t.0.0; - //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue + //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow + //~| NOTE: Capturing t[(0, 0)] -> ByValue //~| NOTE: Min Capture t[(0, 0)] -> ByValue println!("{} {:?}", t.1, p); //~^ NOTE: Capturing t[(1, 0)] -> ImmBorrow diff --git a/src/test/ui/closures/2229_closure_analysis/by_value.stderr b/src/test/ui/closures/2229_closure_analysis/by_value.stderr index fe04dbef6d8b5..944e4c40a78ef 100644 --- a/src/test/ui/closures/2229_closure_analysis/by_value.stderr +++ b/src/test/ui/closures/2229_closure_analysis/by_value.stderr @@ -28,13 +28,18 @@ LL | | LL | | }; | |_____^ | -note: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue +note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow + --> $DIR/by_value.rs:28:17 + | +LL | let p = t.0.0; + | ^^^^^ +note: Capturing t[(0, 0)] -> ByValue --> $DIR/by_value.rs:28:17 | LL | let p = t.0.0; | ^^^^^ note: Capturing t[(1, 0)] -> ImmBorrow - --> $DIR/by_value.rs:31:29 + --> $DIR/by_value.rs:32:29 | LL | println!("{} {:?}", t.1, p); | ^^^ @@ -57,7 +62,7 @@ note: Min Capture t[(0, 0)] -> ByValue LL | let p = t.0.0; | ^^^^^ note: Min Capture t[(1, 0)] -> ImmBorrow - --> $DIR/by_value.rs:31:29 + --> $DIR/by_value.rs:32:29 | LL | println!("{} {:?}", t.1, p); | ^^^ diff --git a/src/test/ui/closures/2229_closure_analysis/move_closure.rs b/src/test/ui/closures/2229_closure_analysis/move_closure.rs index 8bdc999ca3c3f..d57c2280438ba 100644 --- a/src/test/ui/closures/2229_closure_analysis/move_closure.rs +++ b/src/test/ui/closures/2229_closure_analysis/move_closure.rs @@ -18,8 +18,8 @@ fn simple_ref() { //~^ ERROR: First Pass analysis includes: //~| ERROR: Min Capture analysis includes: *ref_s += 10; - //~^ NOTE: Capturing ref_s[Deref] -> ByValue - //~| NOTE: Min Capture ref_s[] -> ByValue + //~^ NOTE: Capturing ref_s[Deref] -> UniqueImmBorrow + //~| NOTE: Min Capture ref_s[Deref] -> UniqueImmBorrow }; c(); } @@ -39,8 +39,8 @@ fn struct_contains_ref_to_another_struct() { //~^ ERROR: First Pass analysis includes: //~| ERROR: Min Capture analysis includes: t.0.0 = "new s".into(); - //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue - //~| NOTE: Min Capture t[(0, 0)] -> ByValue + //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow + //~| NOTE: Min Capture t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow }; c(); diff --git a/src/test/ui/closures/2229_closure_analysis/move_closure.stderr b/src/test/ui/closures/2229_closure_analysis/move_closure.stderr index a745f14598ee2..554dc11f6badb 100644 --- a/src/test/ui/closures/2229_closure_analysis/move_closure.stderr +++ b/src/test/ui/closures/2229_closure_analysis/move_closure.stderr @@ -46,7 +46,7 @@ LL | | LL | | }; | |_____^ | -note: Capturing ref_s[Deref] -> ByValue +note: Capturing ref_s[Deref] -> UniqueImmBorrow --> $DIR/move_closure.rs:20:9 | LL | *ref_s += 10; @@ -64,7 +64,7 @@ LL | | LL | | }; | |_____^ | -note: Min Capture ref_s[] -> ByValue +note: Min Capture ref_s[Deref] -> UniqueImmBorrow --> $DIR/move_closure.rs:20:9 | LL | *ref_s += 10; @@ -82,7 +82,7 @@ LL | | LL | | }; | |_____^ | -note: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue +note: Capturing t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow --> $DIR/move_closure.rs:41:9 | LL | t.0.0 = "new s".into(); @@ -100,7 +100,7 @@ LL | | LL | | }; | |_____^ | -note: Min Capture t[(0, 0)] -> ByValue +note: Min Capture t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow --> $DIR/move_closure.rs:41:9 | LL | t.0.0 = "new s".into(); diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs index 4007a5a48aaec..afaafbda01877 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs @@ -56,9 +56,50 @@ fn no_ref_nested() { c(); } +struct A<'a>(&'a mut String, &'a mut String); +// Test that reborrowing works as expected for move closures +// by attempting a disjoint capture through a reference. +fn disjoint_via_ref() { + let mut x = String::new(); + let mut y = String::new(); + + let mut a = A(&mut x, &mut y); + let a = &mut a; + + let mut c1 = move || { + a.0.truncate(0); + }; + + let mut c2 = move || { + a.1.truncate(0); + }; + + c1(); + c2(); +} + +// Test that even if a path is moved into the closure, the closure is not FnOnce +// if the path is not moved by the closure call. +fn data_moved_but_not_fn_once() { + let x = Box::new(10i32); + + let c = move || { + // *x has type i32 which is Copy. So even though the box `x` will be moved + // into the closure, `x` is never moved when the closure is called, i.e. the + // ownership stays with the closure and therefore we can call the function multiple times. + let _x = *x; + }; + + c(); + c(); +} + fn main() { simple_ref(); struct_contains_ref_to_another_struct(); no_ref(); no_ref_nested(); + + disjoint_via_ref(); + data_moved_but_not_fn_once(); } From e39c3c05a472a7b4ecb2e3f93f1b7f299ea18664 Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Mon, 8 Feb 2021 23:31:26 -0500 Subject: [PATCH 097/103] Handle restricting closure origin --- compiler/rustc_typeck/src/check/upvar.rs | 5 +--- .../closure-origin-array-diagnostics.rs | 16 +++++++++++++ .../closure-origin-array-diagnostics.stderr | 23 +++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 79c60ab3cfe0f..12eacdf25e2f1 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -206,11 +206,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If we have an origin, store it. if let Some(origin) = delegate.current_origin.clone() { let origin = if self.tcx.features().capture_disjoint_fields { - origin + (origin.0, restrict_capture_precision(origin.1)) } else { - // FIXME(project-rfc-2229#31): Once the changes to support reborrowing are - // made, make sure we are selecting and restricting - // the origin correctly. (origin.0, Place { projections: vec![], ..origin.1 }) }; diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.rs new file mode 100644 index 0000000000000..cd7c25620a7c4 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.rs @@ -0,0 +1,16 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| `#[warn(incomplete_features)]` on by default +//~| see issue #53488 + +// Test that array access is not stored as part of closure kind origin + +fn expect_fn(_f: F) {} + +fn main() { + let s = [format!("s"), format!("s")]; + let c = || { //~ ERROR expected a closure that implements the `Fn` + let [_, _s] = s; + }; + expect_fn(c); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr new file mode 100644 index 0000000000000..bd9428771f4c5 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr @@ -0,0 +1,23 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/closure-origin-array-diagnostics.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` + --> $DIR/closure-origin-array-diagnostics.rs:12:13 + | +LL | let c = || { + | ^^ this closure implements `FnOnce`, not `Fn` +LL | let [_, _s] = s; + | - closure is `FnOnce` because it moves the variable `s` out of its environment +LL | }; +LL | expect_fn(c); + | --------- the requirement to implement `Fn` derives from here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0525`. From 1b86ad8485a1937ecd16b2dd5d9c5feb4eac93ec Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Thu, 11 Feb 2021 19:36:05 -0500 Subject: [PATCH 098/103] Treat read of COpy types via refs as not move in move-closure --- compiler/rustc_typeck/src/check/upvar.rs | 9 +- .../2229_closure_analysis/move_closure.rs | 93 +++++++-- .../2229_closure_analysis/move_closure.stderr | 189 ++++++++++++++++-- 3 files changed, 256 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 12eacdf25e2f1..fbbc1fba8771f 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -1116,14 +1116,21 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { place_with_id, diag_expr_id, mode ); - let place = truncate_capture_for_move(place_with_id.place.clone()); match (self.capture_clause, mode) { // In non-move closures, we only care about moves (hir::CaptureBy::Ref, euv::Copy) => return, + // We want to capture Copy types that read through a ref via a reborrow + (hir::CaptureBy::Value, euv::Copy) + if place_with_id.place.deref_tys().any(ty::TyS::is_ref) => + { + return; + } + (hir::CaptureBy::Ref, euv::Move) | (hir::CaptureBy::Value, euv::Move | euv::Copy) => {} }; + let place = truncate_capture_for_move(place_with_id.place.clone()); let place_with_id = PlaceWithHirId { place: place.clone(), hir_id: place_with_id.hir_id }; if !self.capture_information.contains_key(&place) { diff --git a/src/test/ui/closures/2229_closure_analysis/move_closure.rs b/src/test/ui/closures/2229_closure_analysis/move_closure.rs index d57c2280438ba..1c574da5f48bc 100644 --- a/src/test/ui/closures/2229_closure_analysis/move_closure.rs +++ b/src/test/ui/closures/2229_closure_analysis/move_closure.rs @@ -6,7 +6,25 @@ //~| NOTE: see issue #53488 #![feature(rustc_attrs)] -// Test we truncate derefs properly +fn simple_move_closure() { + struct S(String); + struct T(S); + + let t = T(S("s".into())); + let mut c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + move || { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + t.0.0 = "new S".into(); + //~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue + //~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue + }; + c(); +} + +// Test move closure use reborrows when using references fn simple_ref() { let mut s = 10; let ref_s = &mut s; @@ -24,8 +42,8 @@ fn simple_ref() { c(); } -// Test we truncate derefs properly -fn struct_contains_ref_to_another_struct() { +// Test move closure use reborrows when using references +fn struct_contains_ref_to_another_struct_1() { struct S(String); struct T<'a>(&'a mut S); @@ -46,27 +64,78 @@ fn struct_contains_ref_to_another_struct() { c(); } -// Test that we don't reduce precision when there is nothing deref. -fn no_ref() { +// Test that we can use reborrows to read data of Copy types +// i.e. without truncating derefs +fn struct_contains_ref_to_another_struct_2() { + struct S(i32); + struct T<'a>(&'a S); + + let s = S(0); + let t = T(&s); + + let mut c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + move || { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + let _t = t.0.0; + //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow + //~| NOTE: Min Capture t[(0, 0),Deref,(0, 0)] -> ImmBorrow + }; + + c(); +} + +// Test that we can use truncate to move out of !Copy types +fn struct_contains_ref_to_another_struct_3() { struct S(String); - struct T(S); + struct T<'a>(&'a S); + + let s = S("s".into()); + let t = T(&s); - let t = T(S("s".into())); let mut c = #[rustc_capture_analysis] //~^ ERROR: attributes on expressions are experimental //~| NOTE: see issue #15701 move || { //~^ ERROR: First Pass analysis includes: //~| ERROR: Min Capture analysis includes: - t.0.0 = "new S".into(); - //~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue - //~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue + let _t = t.0.0; + //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow + //~| NOTE: Capturing t[(0, 0)] -> ByValue + //~| NOTE: Min Capture t[(0, 0)] -> ByValue + }; + + c(); +} + +// Test that derefs of box are truncated in move closures +fn truncate_box_derefs() { + struct S(i32); + + let b = Box::new(S(10)); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + move || { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + let _t = b.0; + //~^ NOTE: Capturing b[Deref,(0, 0)] -> ByValue + //~| NOTE: Capturing b[] -> ByValue + //~| NOTE: Min Capture b[] -> ByValue }; + c(); } fn main() { + simple_move_closure(); simple_ref(); - struct_contains_ref_to_another_struct(); - no_ref(); + struct_contains_ref_to_another_struct_1(); + struct_contains_ref_to_another_struct_2(); + struct_contains_ref_to_another_struct_3(); + truncate_box_derefs(); } diff --git a/src/test/ui/closures/2229_closure_analysis/move_closure.stderr b/src/test/ui/closures/2229_closure_analysis/move_closure.stderr index 554dc11f6badb..b91ef4dd85c48 100644 --- a/src/test/ui/closures/2229_closure_analysis/move_closure.stderr +++ b/src/test/ui/closures/2229_closure_analysis/move_closure.stderr @@ -8,7 +8,7 @@ LL | let mut c = #[rustc_capture_analysis] = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable error[E0658]: attributes on expressions are experimental - --> $DIR/move_closure.rs:35:17 + --> $DIR/move_closure.rs:32:17 | LL | let mut c = #[rustc_capture_analysis] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let mut c = #[rustc_capture_analysis] = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable error[E0658]: attributes on expressions are experimental - --> $DIR/move_closure.rs:55:17 + --> $DIR/move_closure.rs:53:17 | LL | let mut c = #[rustc_capture_analysis] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,6 +25,33 @@ LL | let mut c = #[rustc_capture_analysis] = note: see issue #15701 for more information = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable +error[E0658]: attributes on expressions are experimental + --> $DIR/move_closure.rs:76:17 + | +LL | let mut c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/move_closure.rs:98:17 + | +LL | let mut c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/move_closure.rs:119:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/move_closure.rs:3:12 | @@ -40,6 +67,42 @@ error: First Pass analysis includes: LL | / move || { LL | | LL | | +LL | | t.0.0 = "new S".into(); +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Capturing t[(0, 0),(0, 0)] -> ByValue + --> $DIR/move_closure.rs:20:9 + | +LL | t.0.0 = "new S".into(); + | ^^^^^ + +error: Min Capture analysis includes: + --> $DIR/move_closure.rs:17:5 + | +LL | / move || { +LL | | +LL | | +LL | | t.0.0 = "new S".into(); +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture t[(0, 0),(0, 0)] -> ByValue + --> $DIR/move_closure.rs:20:9 + | +LL | t.0.0 = "new S".into(); + | ^^^^^ + +error: First Pass analysis includes: + --> $DIR/move_closure.rs:35:5 + | +LL | / move || { +LL | | +LL | | LL | | *ref_s += 10; LL | | LL | | @@ -47,13 +110,13 @@ LL | | }; | |_____^ | note: Capturing ref_s[Deref] -> UniqueImmBorrow - --> $DIR/move_closure.rs:20:9 + --> $DIR/move_closure.rs:38:9 | LL | *ref_s += 10; | ^^^^^^ error: Min Capture analysis includes: - --> $DIR/move_closure.rs:17:5 + --> $DIR/move_closure.rs:35:5 | LL | / move || { LL | | @@ -65,13 +128,13 @@ LL | | }; | |_____^ | note: Min Capture ref_s[Deref] -> UniqueImmBorrow - --> $DIR/move_closure.rs:20:9 + --> $DIR/move_closure.rs:38:9 | LL | *ref_s += 10; | ^^^^^^ error: First Pass analysis includes: - --> $DIR/move_closure.rs:38:5 + --> $DIR/move_closure.rs:56:5 | LL | / move || { LL | | @@ -83,13 +146,13 @@ LL | | }; | |_____^ | note: Capturing t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow - --> $DIR/move_closure.rs:41:9 + --> $DIR/move_closure.rs:59:9 | LL | t.0.0 = "new s".into(); | ^^^^^ error: Min Capture analysis includes: - --> $DIR/move_closure.rs:38:5 + --> $DIR/move_closure.rs:56:5 | LL | / move || { LL | | @@ -101,47 +164,129 @@ LL | | }; | |_____^ | note: Min Capture t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow - --> $DIR/move_closure.rs:41:9 + --> $DIR/move_closure.rs:59:9 | LL | t.0.0 = "new s".into(); | ^^^^^ error: First Pass analysis includes: - --> $DIR/move_closure.rs:58:5 + --> $DIR/move_closure.rs:79:5 | LL | / move || { LL | | LL | | -LL | | t.0.0 = "new S".into(); +LL | | let _t = t.0.0; LL | | LL | | LL | | }; | |_____^ | -note: Capturing t[(0, 0),(0, 0)] -> ByValue - --> $DIR/move_closure.rs:61:9 +note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow + --> $DIR/move_closure.rs:82:18 | -LL | t.0.0 = "new S".into(); - | ^^^^^ +LL | let _t = t.0.0; + | ^^^^^ error: Min Capture analysis includes: - --> $DIR/move_closure.rs:58:5 + --> $DIR/move_closure.rs:79:5 | LL | / move || { LL | | LL | | -LL | | t.0.0 = "new S".into(); +LL | | let _t = t.0.0; LL | | LL | | LL | | }; | |_____^ | -note: Min Capture t[(0, 0),(0, 0)] -> ByValue - --> $DIR/move_closure.rs:61:9 +note: Min Capture t[(0, 0),Deref,(0, 0)] -> ImmBorrow + --> $DIR/move_closure.rs:82:18 | -LL | t.0.0 = "new S".into(); - | ^^^^^ +LL | let _t = t.0.0; + | ^^^^^ + +error: First Pass analysis includes: + --> $DIR/move_closure.rs:101:5 + | +LL | / move || { +LL | | +LL | | +LL | | let _t = t.0.0; +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow + --> $DIR/move_closure.rs:104:18 + | +LL | let _t = t.0.0; + | ^^^^^ +note: Capturing t[(0, 0)] -> ByValue + --> $DIR/move_closure.rs:104:18 + | +LL | let _t = t.0.0; + | ^^^^^ + +error: Min Capture analysis includes: + --> $DIR/move_closure.rs:101:5 + | +LL | / move || { +LL | | +LL | | +LL | | let _t = t.0.0; +... | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture t[(0, 0)] -> ByValue + --> $DIR/move_closure.rs:104:18 + | +LL | let _t = t.0.0; + | ^^^^^ + +error: First Pass analysis includes: + --> $DIR/move_closure.rs:122:5 + | +LL | / move || { +LL | | +LL | | +LL | | let _t = b.0; +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing b[Deref,(0, 0)] -> ByValue + --> $DIR/move_closure.rs:125:18 + | +LL | let _t = b.0; + | ^^^ +note: Capturing b[] -> ByValue + --> $DIR/move_closure.rs:125:18 + | +LL | let _t = b.0; + | ^^^ + +error: Min Capture analysis includes: + --> $DIR/move_closure.rs:122:5 + | +LL | / move || { +LL | | +LL | | +LL | | let _t = b.0; +... | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture b[] -> ByValue + --> $DIR/move_closure.rs:125:18 + | +LL | let _t = b.0; + | ^^^ -error: aborting due to 9 previous errors; 1 warning emitted +error: aborting due to 18 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0658`. From f99e152e5a02d75e5df1a10b33d4e8592cd25fee Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Sat, 13 Feb 2021 01:59:35 -0500 Subject: [PATCH 099/103] Use iter::position in truncate_capture_for_move --- compiler/rustc_typeck/src/check/upvar.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index fbbc1fba8771f..69c09528662d3 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -1461,16 +1461,10 @@ fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> { /// Truncates a place so that the resultant capture doesn't move data out of a reference fn truncate_capture_for_move(mut place: Place<'tcx>) -> Place<'tcx> { - for (i, proj) in place.projections.iter().enumerate() { - match proj.kind { - ProjectionKind::Deref => { - // We only drop Derefs in case of move closures - // There might be an index projection or raw ptr ahead, so we don't stop here. - place.projections.truncate(i); - return place; - } - _ => {} - } + if let Some(i) = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref) { + // We only drop Derefs in case of move closures + // There might be an index projection or raw ptr ahead, so we don't stop here. + place.projections.truncate(i); } place From b97951b50f81862ccd997d48b20f50d05cd5157e Mon Sep 17 00:00:00 2001 From: kadmin Date: Sun, 14 Feb 2021 04:35:18 +0000 Subject: [PATCH 100/103] Update w/ comments --- compiler/rustc_typeck/src/astconv/generics.rs | 60 ++++++++++--------- .../const-param-shadowing.stderr | 2 +- src/test/ui/const-generics/diagnostics.rs | 11 +++- src/test/ui/const-generics/diagnostics.stderr | 33 +++++++++- src/test/ui/const-generics/invalid-enum.rs | 12 ++-- .../ui/const-generics/invalid-enum.stderr | 26 +++++++- 6 files changed, 101 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 341f6fadba174..b421adbf9eab1 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -6,8 +6,9 @@ use crate::astconv::{ use crate::errors::AssocTypeBindingNotAllowed; use crate::structured_errors::{StructuredDiagnostic, WrongNumberOfGenericArgs}; use rustc_ast::ast::ParamKindOrd; -use rustc_errors::{struct_span_err, Applicability, ErrorReported}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; use rustc_middle::ty::{ @@ -24,8 +25,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx: TyCtxt<'_>, arg: &GenericArg<'_>, param: &GenericParamDef, - // DefId of the function - //body_def_id: DefId, possible_ordering_error: bool, help: Option<&str>, ) { @@ -45,6 +44,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } + let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut DiagnosticBuilder<'_>| { + let suggestions = vec![ + (arg.span().shrink_to_lo(), String::from("{ ")), + (arg.span().shrink_to_hi(), String::from(" }")), + ]; + err.multipart_suggestion( + "if this generic argument was intended as a const parameter, \ + surround it with braces", + suggestions, + Applicability::MaybeIncorrect, + ); + }; + // Specific suggestion set for diagnostics match (arg, ¶m.kind) { ( @@ -53,40 +65,34 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .. }), GenericParamDefKind::Const, - ) => { - use rustc_hir::def::{DefKind, Res}; - match path.res { - Res::Err => {} - Res::Def(DefKind::TyParam, src_def_id) => (|| { - let param_hir_id = match param.def_id.as_local() { - Some(x) => tcx.hir().local_def_id_to_hir_id(x), - None => return, - }; + ) => match path.res { + Res::Err => { + add_braces_suggestion(arg, &mut err); + err.set_primary_message( + "unresolved item provided when a constant was expected", + ); + } + Res::Def(DefKind::TyParam, src_def_id) => { + if let Some(param_local_id) = param.def_id.as_local() { + let param_hir_id = tcx.hir().local_def_id_to_hir_id(param_local_id); let param_name = tcx.hir().ty_param_name(param_hir_id); let param_type = tcx.type_of(param.def_id); if param_type.is_suggestable() { err.span_suggestion( tcx.def_span(src_def_id), - &format!("try changing to a const-generic parameter:"), + "consider changing this type paramater to a `const`-generic", format!("const {}: {}", param_name, param_type), Applicability::MaybeIncorrect, ); - } - })(), - _ => { - let suggestions = vec![ - (arg.span().shrink_to_lo(), String::from("{ ")), - (arg.span().shrink_to_hi(), String::from(" }")), - ]; - err.multipart_suggestion( - "if this generic argument was intended as a const parameter, \ - try surrounding it with braces:", - suggestions, - Applicability::MaybeIncorrect, - ); + }; } } - } + _ => add_braces_suggestion(arg, &mut err), + }, + ( + GenericArg::Type(hir::Ty { kind: hir::TyKind::Path(_), .. }), + GenericParamDefKind::Const, + ) => add_braces_suggestion(arg, &mut err), ( GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }), GenericParamDefKind::Const { .. }, diff --git a/src/test/ui/const-generics/const-param-shadowing.stderr b/src/test/ui/const-generics/const-param-shadowing.stderr index 7447ca3ff3631..17ccd2f3527b0 100644 --- a/src/test/ui/const-generics/const-param-shadowing.stderr +++ b/src/test/ui/const-generics/const-param-shadowing.stderr @@ -4,7 +4,7 @@ error[E0747]: type provided when a constant was expected LL | fn test() -> Foo { | ^ | -help: if this generic argument was intended as a const parameter, try surrounding it with braces: +help: if this generic argument was intended as a const parameter, surround it with braces | LL | fn test() -> Foo<{ N }> { | ^ ^ diff --git a/src/test/ui/const-generics/diagnostics.rs b/src/test/ui/const-generics/diagnostics.rs index c90e3d0e0eba9..1581af5ab2751 100644 --- a/src/test/ui/const-generics/diagnostics.rs +++ b/src/test/ui/const-generics/diagnostics.rs @@ -1,13 +1,18 @@ #![crate_type="lib"] -#![feature(const_generics)] +#![feature(min_const_generics)] #![allow(incomplete_features)] struct A; trait Foo {} impl Foo for A {} -//~^ ERROR type provided when a constant -//~| ERROR cannot find type +//~^ ERROR cannot find type +//~| unresolved item provided when a constant struct B; impl Foo for B {} //~^ ERROR type provided when a constant + +struct C; +impl Foo for C {} +//~^ ERROR cannot find type +//~| unresolved item provided when a constant diff --git a/src/test/ui/const-generics/diagnostics.stderr b/src/test/ui/const-generics/diagnostics.stderr index a66858a310c85..33f5337eb8072 100644 --- a/src/test/ui/const-generics/diagnostics.stderr +++ b/src/test/ui/const-generics/diagnostics.stderr @@ -7,11 +7,25 @@ LL | trait Foo {} LL | impl Foo for A {} | ^ help: a struct with a similar name exists: `A` -error[E0747]: type provided when a constant was expected +error[E0412]: cannot find type `T` in this scope + --> $DIR/diagnostics.rs:16:32 + | +LL | struct A; + | ---------------------- similarly named struct `A` defined here +... +LL | impl Foo for C {} + | ^ help: a struct with a similar name exists: `A` + +error[E0747]: unresolved item provided when a constant was expected --> $DIR/diagnostics.rs:7:16 | LL | impl Foo for A {} | ^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | impl Foo for A<{ N }> {} + | ^ ^ error[E0747]: type provided when a constant was expected --> $DIR/diagnostics.rs:12:19 @@ -19,9 +33,22 @@ error[E0747]: type provided when a constant was expected LL | impl Foo for B {} | - ^ | | - | help: try changing to a const-generic parameter:: `const N: u8` + | help: consider changing this type paramater to a `const`-generic: `const N: u8` + +error[E0747]: unresolved item provided when a constant was expected + --> $DIR/diagnostics.rs:16:32 + | +LL | impl Foo for C {} + | ^ + | + = note: type arguments must be provided before constant arguments + = help: reorder the arguments: consts: `` +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | impl Foo for C {} + | ^ ^ -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0412, E0747. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/const-generics/invalid-enum.rs b/src/test/ui/const-generics/invalid-enum.rs index 4ca10ed8b71a2..32939dcd2861b 100644 --- a/src/test/ui/const-generics/invalid-enum.rs +++ b/src/test/ui/const-generics/invalid-enum.rs @@ -3,14 +3,14 @@ #[derive(PartialEq, Eq)] enum CompileFlag { - A, - B, + A, + B, } pub fn test_1() {} pub fn test_2(x: T) {} pub struct Example{ - x: T, + x: T, } impl Example { @@ -20,15 +20,15 @@ impl Example { pub fn main() { test_1::(); //~^ ERROR: expected type, found variant - //~| ERROR: type provided when a constant was expected + //~| ERROR: unresolved item provided when a constant was expected test_2::<_, CompileFlag::A>(0); //~^ ERROR: expected type, found variant - //~| ERROR: type provided when a constant was expected + //~| ERROR: unresolved item provided when a constant was expected let _: Example = Example { x: 0 }; //~^ ERROR: expected type, found variant - //~| ERROR: type provided when a constant was expected + //~| ERROR: unresolved item provided when a constant was expected let _: Example = Example { x: 0 }; //~^ ERROR: type provided when a constant was expected diff --git a/src/test/ui/const-generics/invalid-enum.stderr b/src/test/ui/const-generics/invalid-enum.stderr index c062fc9ac88b3..cfbc61f02543b 100644 --- a/src/test/ui/const-generics/invalid-enum.stderr +++ b/src/test/ui/const-generics/invalid-enum.stderr @@ -25,29 +25,49 @@ LL | let _: Example = Example { x: 0 }; | not a type | help: try using the variant's enum: `CompileFlag` -error[E0747]: type provided when a constant was expected +error[E0747]: unresolved item provided when a constant was expected --> $DIR/invalid-enum.rs:29:18 | LL | let _: Example = Example { x: 0 }; | ^^^^^^^^^^^^^^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 }; + | ^ ^ error[E0747]: type provided when a constant was expected --> $DIR/invalid-enum.rs:33:18 | LL | let _: Example = Example { x: 0 }; | ^^^^^^^^^^^^^^^^^^^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 }; + | ^ ^ -error[E0747]: type provided when a constant was expected +error[E0747]: unresolved item provided when a constant was expected --> $DIR/invalid-enum.rs:21:12 | LL | test_1::(); | ^^^^^^^^^^^^^^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | test_1::<{ CompileFlag::A }>(); + | ^ ^ -error[E0747]: type provided when a constant was expected +error[E0747]: unresolved item provided when a constant was expected --> $DIR/invalid-enum.rs:25:15 | LL | test_2::<_, CompileFlag::A>(0); | ^^^^^^^^^^^^^^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | test_2::<_, { CompileFlag::A }>(0); + | ^ ^ error: aborting due to 7 previous errors From f52029553fa97153eb7f3fc724523cc1a61dfaba Mon Sep 17 00:00:00 2001 From: kadmin Date: Tue, 16 Feb 2021 19:03:22 +0000 Subject: [PATCH 101/103] Remove ordering hint --- compiler/rustc_typeck/src/astconv/generics.rs | 4 +++- src/test/ui/const-generics/diagnostics.stderr | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index b421adbf9eab1..0ea0ccaceabd4 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -70,7 +70,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { add_braces_suggestion(arg, &mut err); err.set_primary_message( "unresolved item provided when a constant was expected", - ); + ) + .emit(); + return; } Res::Def(DefKind::TyParam, src_def_id) => { if let Some(param_local_id) = param.def_id.as_local() { diff --git a/src/test/ui/const-generics/diagnostics.stderr b/src/test/ui/const-generics/diagnostics.stderr index 33f5337eb8072..7d038ff955d6c 100644 --- a/src/test/ui/const-generics/diagnostics.stderr +++ b/src/test/ui/const-generics/diagnostics.stderr @@ -41,8 +41,6 @@ error[E0747]: unresolved item provided when a constant was expected LL | impl Foo for C {} | ^ | - = note: type arguments must be provided before constant arguments - = help: reorder the arguments: consts: `` help: if this generic argument was intended as a const parameter, surround it with braces | LL | impl Foo for C {} From a98b22c837edd73b11c8fca02a8bcedc9c94eb95 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 16 Feb 2021 11:45:46 -0800 Subject: [PATCH 102/103] Add caveat to Path::display() about lossiness --- library/std/src/path.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 1889e54933867..581c09e23dfa6 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2321,7 +2321,9 @@ impl Path { } /// Returns an object that implements [`Display`] for safely printing paths - /// that may contain non-Unicode data. + /// that may contain non-Unicode data. This may perform lossy conversion, + /// depending on the platform. If you would like an implementation which + /// escapes the path please use [`Debug`] instead. /// /// [`Display`]: fmt::Display /// @@ -2555,7 +2557,9 @@ impl fmt::Debug for Path { /// /// A [`Path`] might contain non-Unicode data. This `struct` implements the /// [`Display`] trait in a way that mitigates that. It is created by the -/// [`display`](Path::display) method on [`Path`]. +/// [`display`](Path::display) method on [`Path`]. This may perform lossy +/// conversion, depending on the platform. If you would like an implementation +/// which escapes the path please use [`Debug`] instead. /// /// # Examples /// From 61bb1836f8f2e72e9e92187cc763d0873d603b91 Mon Sep 17 00:00:00 2001 From: Giacomo Stevanato Date: Tue, 16 Feb 2021 21:49:56 +0100 Subject: [PATCH 103/103] Optimize Iterator::is_sorted_by by using Iterator::all for internal iteration --- library/core/src/iter/traits/iterator.rs | 25 +++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 9f7ced829b0ac..b9ec2becbd2f8 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3317,24 +3317,31 @@ pub trait Iterator { /// /// [`is_sorted`]: Iterator::is_sorted #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] - fn is_sorted_by(mut self, mut compare: F) -> bool + fn is_sorted_by(mut self, compare: F) -> bool where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Option, { + #[inline] + fn check<'a, T>( + last: &'a mut T, + mut compare: impl FnMut(&T, &T) -> Option + 'a, + ) -> impl FnMut(T) -> bool + 'a { + move |curr| { + if let Some(Ordering::Greater) | None = compare(&last, &curr) { + return false; + } + *last = curr; + true + } + } + let mut last = match self.next() { Some(e) => e, None => return true, }; - while let Some(curr) = self.next() { - if let Some(Ordering::Greater) | None = compare(&last, &curr) { - return false; - } - last = curr; - } - - true + self.all(check(&mut last, compare)) } /// Checks if the elements of this iterator are sorted using the given key extraction