use hir_expand::name::{known, AsName, Name};
use rustc_hash::FxHashSet;
-use crate::nameres::DefMap;
use crate::{
db::DefDatabase,
item_scope::ItemInNs,
+ nameres::DefMap,
path::{ModPath, PathKind},
visibility::Visibility,
ModuleDefId, ModuleId,
const MAX_PATH_LEN: usize = 15;
-impl ModPath {
+trait ModPathExt {
+ fn starts_with_std(&self) -> bool;
+ fn can_start_with_std(&self) -> bool;
+}
+
+impl ModPathExt for ModPath {
fn starts_with_std(&self) -> bool {
self.segments().first() == Some(&known::std)
}
}
// - if the item is the crate root of a dependency crate, return the name from the extern prelude
- for (name, def_id) in root.def_map(db).extern_prelude() {
+ let root_def_map = root.def_map(db);
+ for (name, def_id) in root_def_map.extern_prelude() {
if item == ItemInNs::Types(*def_id) {
let name = scope_name.unwrap_or_else(|| name.clone());
- return Some(ModPath::from_segments(PathKind::Plain, vec![name]));
+
+ let name_already_occupied_in_type_ns = def_map
+ .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
+ def_map[local_id].scope.get(&name).take_types().filter(|&id| id != *def_id)
+ })
+ .is_some();
+ return Some(ModPath::from_segments(
+ if name_already_occupied_in_type_ns {
+ cov_mark::hit!(ambiguous_crate_start);
+ PathKind::Abs
+ } else {
+ PathKind::Plain
+ },
+ vec![name],
+ ));
}
}
// - if the item is in the prelude, return the name from there
- if let Some(prelude_module) = def_map.prelude() {
+ if let Some(prelude_module) = root_def_map.prelude() {
+ // Preludes in block DefMaps are ignored, only the crate DefMap is searched
let prelude_def_map = prelude_module.def_map(db);
let prelude_scope: &crate::item_scope::ItemScope =
&prelude_def_map[prelude_module.local_id].scope;
) {
path.push_segment(name);
- let new_path = if let Some(best_path) = best_path {
- select_best_path(best_path, path, prefer_no_std)
- } else {
- path
+ let new_path = match best_path {
+ Some(best_path) => select_best_path(best_path, path, prefer_no_std),
+ None => path,
};
best_path_len = new_path.len();
best_path = Some(new_path);
});
for path in extern_paths {
- let new_path = if let Some(best_path) = best_path {
- select_best_path(best_path, path, prefer_no_std)
- } else {
- path
+ let new_path = match best_path {
+ Some(best_path) => select_best_path(best_path, path, prefer_no_std),
+ None => path,
};
best_path = Some(new_path);
}
}
}
- if let Some(prefix) = prefixed.map(PrefixKind::prefix) {
- best_path.or_else(|| {
+ match prefixed.map(PrefixKind::prefix) {
+ Some(prefix) => best_path.or_else(|| {
scope_name.map(|scope_name| ModPath::from_segments(prefix, vec![scope_name]))
- })
- } else {
- best_path
+ }),
+ None => best_path,
}
}
if let Some((name, vis)) = data.scope.name_of(item) {
if vis.is_visible_from(db, from) {
- let is_private = if let Visibility::Module(private_to) = vis {
- private_to.local_id == module.local_id
- } else {
- false
+ let is_private = match vis {
+ Visibility::Module(private_to) => private_to.local_id == module.local_id,
+ Visibility::Public => false,
};
- let is_original_def = if let Some(module_def_id) = item.as_module_def_id() {
- data.scope.declarations().any(|it| it == module_def_id)
- } else {
- false
+ let is_original_def = match item.as_module_def_id() {
+ Some(module_def_id) => data.scope.declarations().any(|it| it == module_def_id),
+ None => false,
};
// Ignore private imports. these could be used if we are
let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path));
let ast_path =
parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap();
- let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap();
+ let mod_path = ModPath::from_src(&db, ast_path, &Hygiene::new_unhygienic()).unwrap();
let def_map = module.def_map(&db);
let resolved = def_map
//- /main.rs crate:main deps:std
$0
//- /std.rs crate:std
-pub mod prelude { pub struct S; }
-#[prelude_import]
-pub use prelude::*;
+pub mod prelude {
+ pub mod rust_2018 {
+ pub struct S;
+ }
+}
"#,
"S",
"S",
$0
//- /std.rs crate:std
pub mod prelude {
- pub enum Option<T> { Some(T), None }
- pub use Option::*;
+ pub mod rust_2018 {
+ pub enum Option<T> { Some(T), None }
+ pub use Option::*;
+ }
}
-#[prelude_import]
-pub use prelude::*;
"#;
check_found_path(code, "None", "None", "None", "None");
check_found_path(code, "Some", "Some", "Some", "Some");
"dep",
);
}
+
+ #[test]
+ fn prelude_with_inner_items() {
+ check_found_path(
+ r#"
+//- /main.rs crate:main deps:std
+fn f() {
+ fn inner() {}
+ $0
+}
+//- /std.rs crate:std
+pub mod prelude {
+ pub mod rust_2018 {
+ pub enum Option { None }
+ pub use Option::*;
+ }
+}
+ "#,
+ "None",
+ "None",
+ "None",
+ "None",
+ );
+ }
}