Repository: intellij-rust/intellij-rust
Issue: completion failed when typing “.unwrap()”

## Environment

* **IntelliJ Rust plugin version:** 0.4.180.4932-222
* **Rust toolchain version:** stable-x86_64-pc-windows-msvc rustc 1.64.0 (a55dd71d5 2022-09-19)
* **IDE name and version:** CLion 2022.2.4 CL-222.4345.21
* **Operating system:** windows 11 

## Problem description 
completion failed when typing “.unwrap()”

## Steps to reproduce

```rust
use std::mem::size_of;
use windows::core::*;
use windows::Win32::Foundation::*;
use windows::Win32::Graphics::Gdi::{GetStockObject, GRAY_BRUSH, HBRUSH};
use windows::Win32::System::LibraryLoader::*;
use windows::Win32::UI::WindowsAndMessaging::*;

pub struct Window {
    window:HWND,
}

impl Window {
    pub fn create(title:String,width:i32,height:i32)->Window{
        unsafe {
            let style = WS_VISIBLE|WS_OVERLAPPEDWINDOW;
            let mut rect = RECT{
                left : 0,
                top : 0,
                right : width,
                bottom : height,
            };
            AdjustWindowRect(&mut rect,style,BOOL(0));
            let wc = WNDCLASSEXW{
                cbSize : size_of::<WNDCLASSEXW>() as u32,
                style : CS_HREDRAW|CS_VREDRAW,
                lpfnWndProc : Some(Window::window_proc),
                /*
                    hInstance : GetModuleHandleW(None).un... <- Completion Failed
                 */
                _hInstance : GetModuleHandleW(None).unwrap(),_   //<- Here
                lpszClassName : w!("ClassName").into(),
                hbrBackground : HBRUSH(GetStockObject(GRAY_BRUSH).0),
                ..Default::default()
            };
            println!("0:{}",GetLastError().0);
            RegisterClassExW(&wc);
            println!("1:{}",GetLastError().0);
            let hwnd = CreateWindowExW(
                WINDOW_EX_STYLE::default(),
                w!("ClassName"),
                &HSTRING::from(title).into(),
                style,
                CW_USEDEFAULT,CW_USEDEFAULT,
                rect.right-rect.left,
                rect.bottom-rect.top,
                None,None,
                GetModuleHandleW(None).unwrap(),
                None
            );
            println!("2:{}",GetLastError().0);
            assert_ne!(hwnd.0, 0);
            ShowWindow(hwnd,SW_SHOW);
            Window{
                window:hwnd,
            }
        }
    }
    pub fn pump_message(&self)->bool{
        unsafe {
            let mut msg = MSG::default();
            while PeekMessageW(&mut msg,None,0,0,PM_REMOVE).into() {
                if msg.message == WM_QUIT {
                    return false;
                }
                TranslateMessage(&msg);
                DispatchMessageW(&msg);
            }
        true
        }
    }
    extern "system" fn window_proc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM)->LRESULT{
        unsafe{
            if message == WM_DESTROY {
                PostQuitMessage(0);
            }
            DefWindowProcW(window,message,wparam,lparam)
        }
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        unsafe {
            UnregisterClassW(w!("ClassName"),GetModuleHandleW(None).unwrap());
            println!("3:{}",GetLastError().0);
        }
    }
}
```

Changed files:
src/test/kotlin/org/rust/lang/core/completion/RsCompletionTestBase.kt
src/test/kotlin/org/rust/lang/core/completion/RsCompletionTestFixtureBase.kt
src/main/kotlin/org/rust/lang/core/resolve/PathResolutionContext.kt
src/test/kotlin/org/rust/lang/core/completion/RsExternCrateCompletionTest.kt
src/test/kotlin/org/rust/lang/core/resolve/RsPackageLibraryResolveTest.kt
src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt
src/main/kotlin/org/rust/lang/core/resolve2/FacadeResolve.kt

diff --git a/src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt b/src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt
index d3168a677..86b273c7d 100644
--- a/src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt
+++ b/src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt
@@ -257,6 +257,20 @@ fun processModDeclResolveVariants(modDecl: RsModDeclItem, processor: RsResolvePr
     return false
 }
 
+/**
+ * Variants from [processExternCrateResolveVariants] + all renamings `extern crate name as alias;`
+ * See https://doc.rust-lang.org/reference/names/preludes.html#extern-prelude
+ */
+fun processExternPreludeResolveVariants(ctx: PathResolutionContext, processor: RsResolveProcessor): Boolean {
+    val (project, defMap) = ctx.containingModInfo ?: return false
+    for ((name, externCrateDefMap) in defMap.externPrelude.entriesWithNames(processor.names)) {
+        val externCrateRoot = externCrateDefMap.rootAsRsMod(project) ?: continue
+        if (processor(name, externCrateRoot)) return true
+    }
+    return false
+}
+
+/** Processes dependencies crates (specified in Cargo.toml) */
 fun processExternCrateResolveVariants(
     element: RsElement,
     isCompletion: Boolean,
@@ -371,7 +385,7 @@ fun processPathResolveVariants(ctx: PathResolutionContext, pathKind: RsPathResol
             }
         }
         is RsPathResolveKind.ExternCratePath -> {
-            processExternCrateResolveVariants(ctx.crateRoot ?: ctx.context, ctx.isCompletion, processor)
+            processExternPreludeResolveVariants(ctx, processor)
         }
         is RsPathResolveKind.AssocTypeBindingPath -> {
             processAssocTypeVariants(pathKind.parent, processor)
diff --git a/src/main/kotlin/org/rust/lang/core/resolve/PathResolutionContext.kt b/src/main/kotlin/org/rust/lang/core/resolve/PathResolutionContext.kt
index f50ac5bca..29672dd0c 100644
--- a/src/main/kotlin/org/rust/lang/core/resolve/PathResolutionContext.kt
+++ b/src/main/kotlin/org/rust/lang/core/resolve/PathResolutionContext.kt
@@ -29,6 +29,7 @@ class PathResolutionContext(
     var lazyContainingModInfo: Lazy<RsModInfo?> = lazy(NONE) {
         getModInfo(containingMod)
     }
+    val containingModInfo: RsModInfo? get() = lazyContainingModInfo.value
     val implLookup: ImplLookup by lazy(NONE) {
         givenImplLookup ?: ImplLookup.relativeTo(context)
     }
diff --git a/src/main/kotlin/org/rust/lang/core/resolve2/FacadeResolve.kt b/src/main/kotlin/org/rust/lang/core/resolve2/FacadeResolve.kt
index 3bc22e35c..5b7341ed4 100644
--- a/src/main/kotlin/org/rust/lang/core/resolve2/FacadeResolve.kt
+++ b/src/main/kotlin/org/rust/lang/core/resolve2/FacadeResolve.kt
@@ -86,10 +86,7 @@ fun processItemDeclarationsUsingModInfo(
             val existingItemInScope = modData.visibleItems[name]
             if (existingItemInScope != null && existingItemInScope.types.any { !it.visibility.isInvisible }) continue
 
-            val externCrateRoot = externCrateDefMap.root.toRsMod(info)
-                // crate root can't multiresolve
-                .singleOrNull()
-                ?: continue
+            val externCrateRoot = externCrateDefMap.rootAsRsMod(info.project) ?: continue
             processor(name, externCrateRoot) && return true
         }
     }
@@ -465,7 +462,7 @@ private fun isModShadowedByOtherMod(mod: RsMod, modData: ModData, crate: Crate):
     }
 }
 
-private fun <T> Map<String, T>.entriesWithNames(names: Set<String>?): Map<String, T> {
+fun <T> Map<String, T>.entriesWithNames(names: Set<String>?): Map<String, T> {
     return if (names.isNullOrEmpty()) {
         this
     } else if (names.size == 1) {
@@ -646,6 +643,8 @@ private fun ModData.toRsModNullable(project: Project): List<RsMod> {
         }
 }
 
+fun CrateDefMap.rootAsRsMod(project: Project): RsMod? = root.toRsMod(project).singleOrNull()
+
 private inline fun <reified T : RsNamedElement> RsItemsOwner.getExpandedItemsWithName(name: String): List<T> =
     expandedItemsCached.named[name]?.filterIsInstance<T>() ?: emptyList()
 
diff --git a/src/test/kotlin/org/rust/lang/core/completion/RsCompletionTestBase.kt b/src/test/kotlin/org/rust/lang/core/completion/RsCompletionTestBase.kt
index 71e2207c4..1d34f174e 100644
--- a/src/test/kotlin/org/rust/lang/core/completion/RsCompletionTestBase.kt
+++ b/src/test/kotlin/org/rust/lang/core/completion/RsCompletionTestBase.kt
@@ -80,6 +80,12 @@ abstract class RsCompletionTestBase(private val defaultFileName: String = "main.
         render: LookupElement.() -> String = { lookupString }
     ) = completionFixture.checkContainsCompletion(code, variants, render)
 
+    protected fun checkContainsCompletionByFileTree(
+        variant: String,
+        @Language("Rust") code: String,
+        render: LookupElement.() -> String = { lookupString }
+    ) = completionFixture.checkContainsCompletionByFileTree(code, listOf(variant), render)
+
     protected fun checkContainsCompletionByFileTree(
         variants: List<String>,
         @Language("Rust") code: String,
diff --git a/src/test/kotlin/org/rust/lang/core/completion/RsCompletionTestFixtureBase.kt b/src/test/kotlin/org/rust/lang/core/completion/RsCompletionTestFixtureBase.kt
index 7d6eb3f11..3e35f8d8a 100644
--- a/src/test/kotlin/org/rust/lang/core/completion/RsCompletionTestFixtureBase.kt
+++ b/src/test/kotlin/org/rust/lang/core/completion/RsCompletionTestFixtureBase.kt
@@ -82,22 +82,26 @@ abstract class RsCompletionTestFixtureBase<IN>(
         }
     }
 
-    fun checkContainsCompletion(
-        code: IN,
-        variants: Iterable<String>,
-        render: LookupElement.() -> String = { lookupString }
-    ) {
+    private fun withNoInsertCompletion(action: () -> Unit) {
         val oldAutocomplete = CodeInsightSettings.getInstance().AUTOCOMPLETE_ON_CODE_COMPLETION
         CodeInsightSettings.getInstance().AUTOCOMPLETE_ON_CODE_COMPLETION = false
         try {
-            prepare(code)
-            doContainsCompletion(variants.toSet(), render)
+            action()
         } finally {
             CodeInsightSettings.getInstance().AUTOCOMPLETE_ON_CODE_COMPLETION = oldAutocomplete
         }
     }
 
-    fun doContainsCompletion(variants: Set<String>, render: LookupElement.() -> String) {
+    fun checkContainsCompletion(
+        code: IN,
+        variants: Iterable<String>,
+        render: LookupElement.() -> String = { lookupString }
+    ) {
+        prepare(code)
+        doContainsCompletion(variants.toSet(), render)
+    }
+
+    fun doContainsCompletion(variants: Set<String>, render: LookupElement.() -> String) = withNoInsertCompletion {
         val lookups = myFixture.completeBasic()
 
         checkNotNull(lookups) {
@@ -115,7 +119,7 @@ abstract class RsCompletionTestFixtureBase<IN>(
         code: IN,
         variants: Set<String>,
         render: LookupElement.() -> String = { lookupString }
-    ) {
+    ) = withNoInsertCompletion {
         prepare(code)
         val lookups = myFixture.completeBasic()
         checkNotNull(lookups) {
@@ -126,7 +130,7 @@ abstract class RsCompletionTestFixtureBase<IN>(
         }
     }
 
-    fun checkContainsCompletionPrefixes(code: IN, prefixes: List<String>) {
+    fun checkContainsCompletionPrefixes(code: IN, prefixes: List<String>) = withNoInsertCompletion {
         prepare(code)
         val lookups = myFixture.completeBasic()
 
diff --git a/src/test/kotlin/org/rust/lang/core/completion/RsExternCrateCompletionTest.kt b/src/test/kotlin/org/rust/lang/core/completion/RsExternCrateCompletionTest.kt
index 1a923c58a..3bd0cd10d 100644
--- a/src/test/kotlin/org/rust/lang/core/completion/RsExternCrateCompletionTest.kt
+++ b/src/test/kotlin/org/rust/lang/core/completion/RsExternCrateCompletionTest.kt
@@ -35,4 +35,37 @@ class RsExternCrateCompletionTest : RsCompletionTestBase() {
     fun `test extern crate does not suggest transitive dependency`() = checkNoCompletion("""
         extern crate trans_l/*caret*/
     """)
+
+    fun `test absolute path suggest dependency`() = checkContainsCompletionByFileTree("test_package", """
+    //- lib.rs
+    //- main.rs
+        fn main() {
+            ::test_packa/*caret*/
+        }
+    """)
+
+    fun `test absolute path suggest std`() = checkContainsCompletionByFileTree("std", """
+    //- lib.rs
+    //- main.rs
+        fn main() {
+            ::st/*caret*/
+        }
+    """)
+
+    fun `test absolute path suggest aliased extern crate`() = checkContainsCompletionByFileTree(
+        listOf("test_package", "test_package2"), """
+    //- lib.rs
+    //- main.rs
+        extern crate test_package as test_package2;
+        fn main() {
+            ::test_packa/*caret*/
+        }
+    """)
+
+    fun `test absolute path don't suggest self`() = checkNoCompletionByFileTree("""
+    //- lib.rs
+        fn main() {
+            ::self/*caret*/
+        }
+    """)
 }
diff --git a/src/test/kotlin/org/rust/lang/core/resolve/RsPackageLibraryResolveTest.kt b/src/test/kotlin/org/rust/lang/core/resolve/RsPackageLibraryResolveTest.kt
index 763f3f441..1410eaf68 100644
--- a/src/test/kotlin/org/rust/lang/core/resolve/RsPackageLibraryResolveTest.kt
+++ b/src/test/kotlin/org/rust/lang/core/resolve/RsPackageLibraryResolveTest.kt
@@ -765,6 +765,35 @@ class RsPackageLibraryResolveTest : RsResolveTestBase() {
                                    //^ dep-lib/lib.rs
     """)
 
+    fun `test absolute path using aliased extern crate 1`() = stubOnlyResolve("""
+    //- lib.rs
+        pub fn func() {}
+    //- main.rs
+        extern crate test_package as foo;
+
+        fn main() {
+            ::foo::func();
+        }        //^ lib.rs
+    """)
+
+    fun `test absolute path using aliased extern crate 2`() = stubOnlyResolve("""
+    //- lib.rs
+        extern crate self as foo;
+
+        fn main() {
+            ::foo::func();
+        }        //^ lib.rs
+        pub fn func() {}
+    """)
+
+    fun `test unresolved absolute path self`() = stubOnlyResolve("""
+    //- lib.rs
+        pub fn func() {}
+        fn main() {
+            ::self::func();
+        }         //^ unresolved
+    """)
+
     fun `test extern crate in super chain (edition 2018)`() = stubOnlyResolve("""
     //- dep-lib/lib.rs
         pub struct Foo;