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