From 92c595a6a6f7624092432d28ffd7e0ffd189cbda Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Wed, 13 Feb 2019 20:42:43 +0100 Subject: Handle extern crates better, so they work correctly in 2015 edition (see the removed comment.) --- crates/ra_hir/src/nameres.rs | 25 +++++++++++++++++-------- crates/ra_hir/src/nameres/lower.rs | 9 ++------- crates/ra_hir/src/nameres/tests.rs | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 028e2bee3..cd7b41cff 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -287,12 +287,18 @@ where ) -> ReachedFixedPoint { log::debug!("resolving import: {:?} ({:?})", import, self.result.edition); let original_module = Module { krate: self.krate, module_id }; - let (def, reached_fixedpoint) = self.result.resolve_path_fp( - self.db, - ResolveMode::Import, - original_module, - &import.path, - ); + + let (def, reached_fixedpoint) = if import.is_extern_crate { + let res = self.result.resolve_name_in_extern_prelude( + &import + .path + .as_ident() + .expect("extern crate should have been desugared to one-element path"), + ); + (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes }) + } else { + self.result.resolve_path_fp(self.db, ResolveMode::Import, original_module, &import.path) + }; if reached_fixedpoint != ReachedFixedPoint::Yes { return reached_fixedpoint; @@ -502,6 +508,10 @@ impl ItemMap { from_scope.or(from_extern_prelude).or(from_prelude) } + fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { + self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) + } + fn resolve_name_in_crate_root_or_extern_prelude( &self, db: &impl PersistentHirDatabase, @@ -511,8 +521,7 @@ impl ItemMap { let crate_root = module.crate_root(db); let from_crate_root = self[crate_root.module_id].items.get(name).map_or(PerNs::none(), |it| it.def); - let from_extern_prelude = - self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); + let from_extern_prelude = self.resolve_name_in_extern_prelude(name); from_crate_root.or(from_extern_prelude) } diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs index 922dbe9c1..81d80654c 100644 --- a/crates/ra_hir/src/nameres/lower.rs +++ b/crates/ra_hir/src/nameres/lower.rs @@ -8,7 +8,7 @@ use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; use rustc_hash::FxHashMap; use crate::{ - SourceItemId, Path, PathKind, ModuleSource, Name, + SourceItemId, Path, ModuleSource, Name, HirFileId, MacroCallLoc, AsName, PerNs, Function, ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type, ids::LocationCtx, PersistentHirDatabase, @@ -180,13 +180,8 @@ impl LoweredModule { self.add_use_item(source_map, it); } ast::ModuleItemKind::ExternCrateItem(it) => { - // Lower `extern crate x` to `use ::x`. This is kind of cheating - // and only works if we always interpret absolute paths in the - // 2018 style; otherwise `::x` could also refer to a module in - // the crate root. if let Some(name_ref) = it.name_ref() { - let mut path = Path::from_name_ref(name_ref); - path.kind = PathKind::Abs; + let path = Path::from_name_ref(name_ref); let alias = it.alias().and_then(|a| a.name()).map(AsName::as_name); self.imports.alloc(ImportData { path, diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index e764e0855..6402c89c0 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs @@ -542,6 +542,42 @@ fn extern_crate_rename() { ); } +#[test] +fn extern_crate_rename_2015_edition() { + let mut db = MockDatabase::with_files( + " + //- /main.rs + extern crate alloc as alloc_crate; + + mod alloc; + mod sync; + + //- /sync.rs + use alloc_crate::Arc; + + //- /lib.rs + struct Arc; + ", + ); + db.set_crate_graph_from_fixture(crate_graph! { + "main": ("/main.rs", "2015", ["alloc"]), + "alloc": ("/lib.rs", []), + }); + let sync_id = db.file_id_of("/sync.rs"); + + let module = crate::source_binder::module_from_file_id(&db, sync_id).unwrap(); + let krate = module.krate(&db).unwrap(); + let item_map = db.item_map(krate); + + check_module_item_map( + &item_map, + module.module_id, + " + Arc: t v + ", + ); +} + #[test] fn import_across_source_roots() { let mut db = MockDatabase::with_files( -- cgit v1.2.3