Resolve through local re-exports in `lookup_path` (#14772) Fixes https://github.com/rust-lang/rust-clippy/issues/14767 A long standing issue revealed by https://github.com/rust-lang/rust-clippy/pull/14397 changelog: none
diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 58c79c1..282d892 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md
@@ -849,6 +849,7 @@ * [`same_item_push`](https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push) * [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) * [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) +* [`to_digit_is_some`](https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some) * [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref) * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) * [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds)
diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index aef0516..8a1d38e 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs
@@ -759,6 +759,7 @@ same_item_push, seek_from_current, seek_rewind, + to_digit_is_some, transmute_ptr_to_ref, tuple_array_conversions, type_repetition_in_bounds,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ad8b223..64fbc02 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs
@@ -746,7 +746,7 @@ store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(conf))); store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); store.register_late_pass(|_| Box::new(exit::Exit)); - store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome)); + store.register_late_pass(move |_| Box::new(to_digit_is_some::ToDigitIsSome::new(conf))); store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(conf))); store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(conf))); store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index c8a6a41..7d7d74f 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs
@@ -1,10 +1,12 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{paths, sym}; +use clippy_utils::{is_in_const_context, paths, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does @@ -32,7 +34,17 @@ "`char.is_digit()` is clearer" } -declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); +impl_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); + +pub(crate) struct ToDigitIsSome { + msrv: Msrv, +} + +impl ToDigitIsSome { + pub(crate) fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv } + } +} impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { @@ -59,7 +71,9 @@ _ => None, }; - if let Some((is_method_call, char_arg, radix_arg)) = match_result { + if let Some((is_method_call, char_arg, radix_arg)) = match_result + && (!is_in_const_context(cx) || self.msrv.meets(cx, msrvs::CONST_CHAR_IS_DIGIT)) + { let mut applicability = Applicability::MachineApplicable; let char_arg_snip = snippet_with_applicability(cx, char_arg.span, "_", &mut applicability); let radix_snip = snippet_with_applicability(cx, radix_arg.span, "_", &mut applicability);
diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index a6a9187..c641d4e 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs
@@ -292,6 +292,10 @@ if expr.span.in_external_macro(self.cx.tcx.sess.source_map()) { return; } + // Skip checking inside closures since they are visited through `Unwrap::check_fn()` already. + if matches!(expr.kind, ExprKind::Closure(_)) { + return; + } if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) { walk_expr(self, cond); self.visit_branch(expr, cond, then, false);
diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 71985cb..434e431 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs
@@ -23,7 +23,7 @@ // names may refer to stabilized feature flags or library items msrv_aliases! { 1,88,0 { LET_CHAINS } - 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT } + 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT } 1,85,0 { UINT_FLOAT_MIDPOINT } 1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR } 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
diff --git a/tests/ui/checked_unwrap/simple_conditionals.rs b/tests/ui/checked_unwrap/simple_conditionals.rs index 5589d8c..ba0d36d 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.rs +++ b/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -240,6 +240,39 @@ } } +fn issue14763(x: Option<String>, r: Result<(), ()>) { + _ = || { + if x.is_some() { + _ = x.unwrap(); + //~^ unnecessary_unwrap + } else { + _ = x.unwrap(); + //~^ panicking_unwrap + } + }; + _ = || { + if r.is_ok() { + _ = r.as_ref().unwrap(); + //~^ unnecessary_unwrap + } else { + _ = r.as_ref().unwrap(); + //~^ panicking_unwrap + } + }; +} + +const ISSUE14763: fn(Option<String>) = |x| { + _ = || { + if x.is_some() { + _ = x.unwrap(); + //~^ unnecessary_unwrap + } else { + _ = x.unwrap(); + //~^ panicking_unwrap + } + } +}; + fn check_expect() { let x = Some(()); if x.is_some() {
diff --git a/tests/ui/checked_unwrap/simple_conditionals.stderr b/tests/ui/checked_unwrap/simple_conditionals.stderr index 82a36aa..a4bf009 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -271,6 +271,57 @@ LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ +error: called `unwrap` on `x` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:246:17 + | +LL | if x.is_some() { + | -------------- help: try: `if let Some(<item>) = x` +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:249:17 + | +LL | if x.is_some() { + | ----------- because of this check +... +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + +error: called `unwrap` on `r` after checking its variant with `is_ok` + --> tests/ui/checked_unwrap/simple_conditionals.rs:255:17 + | +LL | if r.is_ok() { + | ------------ help: try: `if let Ok(<item>) = &r` +LL | _ = r.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:258:17 + | +LL | if r.is_ok() { + | --------- because of this check +... +LL | _ = r.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `x` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:267:17 + | +LL | if x.is_some() { + | -------------- help: try: `if let Some(<item>) = x` +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:270:17 + | +LL | if x.is_some() { + | ----------- because of this check +... +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + error: creating a shared reference to mutable static --> tests/ui/checked_unwrap/simple_conditionals.rs:183:12 | @@ -281,5 +332,5 @@ = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives = note: `#[deny(static_mut_refs)]` on by default -error: aborting due to 30 previous errors +error: aborting due to 36 previous errors
diff --git a/tests/ui/to_digit_is_some.fixed b/tests/ui/to_digit_is_some.fixed index 627d54c..ff6b32e 100644 --- a/tests/ui/to_digit_is_some.fixed +++ b/tests/ui/to_digit_is_some.fixed
@@ -9,3 +9,20 @@ let _ = char::is_digit(c, 8); //~^ to_digit_is_some } + +#[clippy::msrv = "1.86"] +mod cannot_lint_in_const_context { + fn without_const(c: char) -> bool { + c.is_digit(8) + //~^ to_digit_is_some + } + const fn with_const(c: char) -> bool { + c.to_digit(8).is_some() + } +} + +#[clippy::msrv = "1.87"] +const fn with_const(c: char) -> bool { + c.is_digit(8) + //~^ to_digit_is_some +}
diff --git a/tests/ui/to_digit_is_some.rs b/tests/ui/to_digit_is_some.rs index d4eccc9..5ba0861 100644 --- a/tests/ui/to_digit_is_some.rs +++ b/tests/ui/to_digit_is_some.rs
@@ -9,3 +9,20 @@ let _ = char::to_digit(c, 8).is_some(); //~^ to_digit_is_some } + +#[clippy::msrv = "1.86"] +mod cannot_lint_in_const_context { + fn without_const(c: char) -> bool { + c.to_digit(8).is_some() + //~^ to_digit_is_some + } + const fn with_const(c: char) -> bool { + c.to_digit(8).is_some() + } +} + +#[clippy::msrv = "1.87"] +const fn with_const(c: char) -> bool { + c.to_digit(8).is_some() + //~^ to_digit_is_some +}
diff --git a/tests/ui/to_digit_is_some.stderr b/tests/ui/to_digit_is_some.stderr index f41382a..5ffedb4 100644 --- a/tests/ui/to_digit_is_some.stderr +++ b/tests/ui/to_digit_is_some.stderr
@@ -13,5 +13,17 @@ LL | let _ = char::to_digit(c, 8).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `char::is_digit(c, 8)` -error: aborting due to 2 previous errors +error: use of `.to_digit(..).is_some()` + --> tests/ui/to_digit_is_some.rs:16:9 + | +LL | c.to_digit(8).is_some() + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_digit(8)` + +error: use of `.to_digit(..).is_some()` + --> tests/ui/to_digit_is_some.rs:26:5 + | +LL | c.to_digit(8).is_some() + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_digit(8)` + +error: aborting due to 4 previous errors