From 3cf2c3b943a5b373dbd333622c16f3d606fdb6ab Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 25 Apr 2020 16:24:44 +0200 Subject: [PATCH] Prefer core/alloc paths on #![no_std] --- crates/ra_hir_def/src/attr.rs | 23 ++++++--- crates/ra_hir_def/src/find_path.rs | 78 +++++++++++++++++++++++++++--- 2 files changed, 87 insertions(+), 14 deletions(-) diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 714a66b0276..5a86af8ba37 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs @@ -13,7 +13,8 @@ use tt::Subtree; use crate::{ - db::DefDatabase, path::ModPath, src::HasChildSource, src::HasSource, AdtId, AttrDefId, Lookup, + db::DefDatabase, nameres::ModuleSource, path::ModPath, src::HasChildSource, src::HasSource, + AdtId, AttrDefId, Lookup, }; #[derive(Default, Debug, Clone, PartialEq, Eq)] @@ -37,11 +38,19 @@ pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { match def { AttrDefId::ModuleId(module) => { let def_map = db.crate_def_map(module.krate); - let src = match def_map[module.local_id].declaration_source(db) { - Some(it) => it, - None => return Attrs::default(), - }; - Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) + let mod_data = &def_map[module.local_id]; + match mod_data.declaration_source(db) { + Some(it) => { + Attrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner)) + } + None => Attrs::from_attrs_owner( + db, + mod_data.definition_source(db).as_ref().map(|src| match src { + ModuleSource::SourceFile(file) => file as &dyn AttrsOwner, + ModuleSource::Module(module) => module as &dyn AttrsOwner, + }), + ), + } } AttrDefId::FieldId(it) => { let src = it.parent.child_source(db); @@ -106,7 +115,9 @@ pub struct Attr { #[derive(Debug, Clone, PartialEq, Eq)] pub enum AttrInput { + /// `#[attr = "string"]` Literal(SmolStr), + /// `#[attr(subtree)]` TokenTree(Subtree), } diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index 81eff5bfef1..70dcb03e6e3 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs @@ -19,7 +19,7 @@ fn starts_with_std(&self) -> bool { // When std library is present, paths starting with `std::` // should be preferred over paths starting with `core::` and `alloc::` - fn should_start_with_std(&self) -> bool { + fn can_start_with_std(&self) -> bool { self.segments .first() .filter(|&first_segment| { @@ -132,6 +132,9 @@ fn find_path_inner( } // - otherwise, look for modules containing (reexporting) it and import it from one of those + let crate_root = ModuleId { local_id: def_map.root, krate: from.krate }; + let crate_attrs = db.attrs(crate_root.into()); + let prefer_no_std = crate_attrs.by_key("no_std").exists(); let importable_locations = find_importable_locations(db, item, from); let mut best_path = None; let mut best_path_len = max_len; @@ -147,21 +150,32 @@ fn find_path_inner( }; path.segments.push(name); - let new_path = - if let Some(best_path) = best_path { select_best_path(best_path, path) } else { path }; + let new_path = if let Some(best_path) = best_path { + select_best_path(best_path, path, prefer_no_std) + } else { + path + }; best_path_len = new_path.len(); best_path = Some(new_path); } best_path } -fn select_best_path(old_path: ModPath, new_path: ModPath) -> ModPath { - if old_path.starts_with_std() && new_path.should_start_with_std() { +fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath { + if old_path.starts_with_std() && new_path.can_start_with_std() { tested_by!(prefer_std_paths); - old_path - } else if new_path.starts_with_std() && old_path.should_start_with_std() { + if prefer_no_std { + new_path + } else { + old_path + } + } else if new_path.starts_with_std() && old_path.can_start_with_std() { tested_by!(prefer_std_paths); - new_path + if prefer_no_std { + old_path + } else { + new_path + } } else if new_path.len() < old_path.len() { new_path } else { @@ -512,6 +526,54 @@ pub mod sync { check_found_path(code, "std::sync::Arc"); } + #[test] + fn prefer_alloc_paths_over_std() { + covers!(prefer_std_paths); + let code = r#" + //- /main.rs crate:main deps:alloc,std + #![no_std] + + <|> + + //- /std.rs crate:std deps:alloc + + pub mod sync { + pub use alloc::sync::Arc; + } + + //- /zzz.rs crate:alloc + + pub mod sync { + pub struct Arc; + } + "#; + check_found_path(code, "alloc::sync::Arc"); + } + + #[test] + fn prefer_core_paths_over_std() { + covers!(prefer_std_paths); + let code = r#" + //- /main.rs crate:main deps:core,std + #![no_std] + + <|> + + //- /std.rs crate:std deps:core + + pub mod fmt { + pub use core::fmt::Error; + } + + //- /zzz.rs crate:core + + pub mod fmt { + pub struct Error; + } + "#; + check_found_path(code, "core::fmt::Error"); + } + #[test] fn prefer_shorter_paths_if_not_alloc() { let code = r#"