From 538ec1122baeccd85ab672fd0a9f1186d2171058 Mon Sep 17 00:00:00 2001 From: Alexander Andreev Date: Mon, 29 Jul 2019 09:54:40 +0300 Subject: Added resolve modules inside inline module #1510 --- crates/ra_hir/src/nameres/collector.rs | 148 +++++++++++++++++++++++--------- crates/ra_hir/src/nameres/tests/mods.rs | 53 ++++++++---- 2 files changed, 147 insertions(+), 54 deletions(-) diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 7f765caf3..80b71e2d9 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; +use std::sync::Arc; -use arrayvec::ArrayVec; -use ra_db::FileId; +use ra_db::{FileId, SourceRoot}; use ra_syntax::{ast, SmolStr}; use relative_path::RelativePathBuf; use rustc_hash::FxHashMap; @@ -106,7 +106,7 @@ where file_id: file_id.into(), raw_items: &raw_items, } - .collect(raw_items.items()); + .collect(None, raw_items.items()); // main name resolution fixed-point loop. let mut i = 0; @@ -456,7 +456,7 @@ where let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items); let raw_items = self.db.raw_items(file_id); ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items } - .collect(raw_items.items()); + .collect(None, raw_items.items()); } else { log::error!("Too deep macro expansion: {:?}", macro_call_id); self.def_map.poison_macros.insert(macro_def_id); @@ -482,10 +482,10 @@ impl ModCollector<'_, &'_ mut DefCollector<&'_ DB>> where DB: DefDatabase, { - fn collect(&mut self, items: &[raw::RawItem]) { + fn collect(&mut self, parent_module: Option<&Name>, items: &[raw::RawItem]) { for item in items { match *item { - raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), + raw::RawItem::Module(m) => self.collect_module(parent_module, &self.raw_items[m]), raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push(( self.module_id, import, @@ -497,7 +497,7 @@ where } } - fn collect_module(&mut self, module: &raw::ModuleData) { + fn collect_module(&mut self, _module: Option<&Name>, module: &raw::ModuleData) { match module { // inline module, just recurse raw::ModuleData::Definition { name, items, ast_id } => { @@ -509,7 +509,7 @@ where file_id: self.file_id, raw_items: self.raw_items, } - .collect(&*items); + .collect(Some(name), &*items); } // out of line module, resolve, parse and recurse raw::ModuleData::Declaration { name, ast_id, attr_path } => { @@ -521,6 +521,7 @@ where name, is_root, attr_path.as_ref(), + _module, ) { Ok(file_id) => { let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); @@ -531,7 +532,7 @@ where file_id: file_id.into(), raw_items: &raw_items, } - .collect(raw_items.items()) + .collect(None, raw_items.items()) } Err(candidate) => self.def_collector.def_map.diagnostics.push( DefDiagnostic::UnresolvedModule { @@ -636,46 +637,47 @@ fn resolve_submodule( name: &Name, is_root: bool, attr_path: Option<&SmolStr>, + parent_module: Option<&Name>, ) -> Result { - // FIXME: handle submodules of inline modules properly let file_id = file_id.original_file(db); let source_root_id = db.file_source_root(file_id); let path = db.file_relative_path(file_id); let root = RelativePathBuf::default(); let dir_path = path.parent().unwrap_or(&root); let mod_name = path.file_stem().unwrap_or("unknown"); - let is_dir_owner = is_root || mod_name == "mod"; - - let file_mod = dir_path.join(format!("{}.rs", name)); - let dir_mod = dir_path.join(format!("{}/mod.rs", name)); - let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name)); - let mut candidates = ArrayVec::<[_; 3]>::new(); - let file_attr_mod = attr_path.map(|file_path| { - let file_path = normalize_attribute_path(file_path); - let file_attr_mod = dir_path.join(file_path.as_ref()).normalize(); - candidates.push(file_attr_mod.clone()); - - file_attr_mod - }); - if is_dir_owner { - candidates.push(file_mod.clone()); - candidates.push(dir_mod); - } else { - candidates.push(file_dir_mod.clone()); - }; - let sr = db.source_root(source_root_id); - let mut points_to = candidates.into_iter().filter_map(|path| sr.files.get(&path)).copied(); - // FIXME: handle ambiguity - match points_to.next() { - Some(file_id) => Ok(file_id), - None => { - if let Some(file_attr_mod) = file_attr_mod { - Err(file_attr_mod) + + let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) { + (Some(file_path), Some(parent_name)) => { + let file_path = normalize_attribute_path(file_path); + let path = dir_path.join(format!("{}/{}", parent_name, file_path)).normalize(); + ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath(path)) + } + (Some(file_path), None) => { + let file_path = normalize_attribute_path(file_path); + let path = dir_path.join(file_path.as_ref()).normalize(); + ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path)) + } + (None, Some(parent_name)) => { + let path = dir_path.join(format!("{}/{}.rs", parent_name, name)); + ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path)) + } + _ => { + let is_dir_owner = is_root || mod_name == "mod"; + if is_dir_owner { + let file_mod = dir_path.join(format!("{}.rs", name)); + let dir_mod = dir_path.join(format!("{}/mod.rs", name)); + ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs { + file: file_mod, + directory: dir_mod, + }) } else { - Err(if is_dir_owner { file_mod } else { file_dir_mod }) + let path = dir_path.join(format!("{}/{}.rs", mod_name, name)); + ResolutionMode::OutOfLine(OutOfLineMode::FileInDirectory(path)) } } - } + }; + + resolve_mode.resolve(db.source_root(source_root_id)) } fn normalize_attribute_path(file_path: &SmolStr) -> Cow { @@ -693,6 +695,74 @@ fn normalize_attribute_path(file_path: &SmolStr) -> Cow { } } +enum OutOfLineMode { + RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf }, + FileInDirectory(RelativePathBuf), + WithAttributePath(RelativePathBuf), +} + +impl OutOfLineMode { + pub fn resolve(&self, source_root: Arc) -> Result { + match self { + OutOfLineMode::RootOrModRs { file, directory } => match source_root.files.get(file) { + None => resolve_simple_path(source_root, directory).map_err(|_| file.clone()), + file_id => resolve_find_result(file_id, file), + }, + OutOfLineMode::FileInDirectory(path) => resolve_simple_path(source_root, path), + OutOfLineMode::WithAttributePath(path) => resolve_simple_path(source_root, path), + } + } +} + +enum InsideInlineModuleMode { + File(RelativePathBuf), + WithAttributePath(RelativePathBuf), +} + +impl InsideInlineModuleMode { + pub fn resolve(&self, source_root: Arc) -> Result { + match self { + InsideInlineModuleMode::File(path) => resolve_simple_path(source_root, path), + InsideInlineModuleMode::WithAttributePath(path) => { + resolve_simple_path(source_root, path) + } + } + } +} + +enum ResolutionMode { + OutOfLine(OutOfLineMode), + InsideInlineModule(InsideInlineModuleMode), +} + +impl ResolutionMode { + pub fn resolve(&self, source_root: Arc) -> Result { + use self::ResolutionMode::*; + + match self { + OutOfLine(mode) => mode.resolve(source_root), + InsideInlineModule(mode) => mode.resolve(source_root), + } + } +} + +fn resolve_simple_path( + source_root: Arc, + path: &RelativePathBuf, +) -> Result { + resolve_find_result(source_root.files.get(path), path) +} + +fn resolve_find_result( + file_id: Option<&FileId>, + path: &RelativePathBuf, +) -> Result { + match file_id { + Some(file_id) => Ok(file_id.clone()), + None => Err(path.clone()), + } +} + #[cfg(test)] mod tests { use ra_db::SourceDatabase; diff --git a/crates/ra_hir/src/nameres/tests/mods.rs b/crates/ra_hir/src/nameres/tests/mods.rs index d714a3276..382728149 100644 --- a/crates/ra_hir/src/nameres/tests/mods.rs +++ b/crates/ra_hir/src/nameres/tests/mods.rs @@ -336,10 +336,10 @@ fn module_resolution_explicit_path_mod_rs_with_win_separator() { "###); } -// FIXME: issue #1510. not support out-of-line modules inside inline. +// FIXME: issue #1529. not support out-of-line modules inside inline. #[test] #[ignore] -fn module_resolution_decl_inside_inline_module() { +fn module_resolution_decl_inside_inline_module_with_path_attribute() { let map = def_map_with_crate_graph( r###" //- /main.rs @@ -368,10 +368,39 @@ fn module_resolution_decl_inside_inline_module() { "###); } -// FIXME: issue #1510. not support out-of-line modules inside inline. +#[test] +fn module_resolution_decl_inside_inline_module() { + let map = def_map_with_crate_graph( + r###" + //- /main.rs + mod foo { + mod bar; + } + + //- /foo/bar.rs + pub struct Baz; + "###, + crate_graph! { + "main": ("/main.rs", []), + }, + ); + + assert_snapshot_matches!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +// FIXME: issue #1529. not support out-of-line modules inside inline. #[test] #[ignore] -fn module_resolution_decl_inside_inline_module_2() { +fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { let map = def_map_with_crate_graph( r###" //- /main.rs @@ -400,7 +429,7 @@ fn module_resolution_decl_inside_inline_module_2() { "###); } -// FIXME: issue #1510. not support out-of-line modules inside inline. +// FIXME: issue #1529. not support out-of-line modules inside inline. #[test] #[ignore] fn module_resolution_decl_inside_inline_module_3() { @@ -433,7 +462,7 @@ fn module_resolution_decl_inside_inline_module_3() { "###); } -// FIXME: issue #1510. not support out-of-line modules inside inline. +// FIXME: issue #1529. not support out-of-line modules inside inline. #[test] #[ignore] fn module_resolution_decl_inside_inline_module_empty_path() { @@ -491,7 +520,7 @@ fn module_resolution_decl_empty_path() { "###); } -// FIXME: issue #1510. not support out-of-line modules inside inline. +// FIXME: issue #1529. not support out-of-line modules inside inline. #[test] #[ignore] fn module_resolution_decl_inside_inline_module_relative_path() { @@ -523,9 +552,7 @@ fn module_resolution_decl_inside_inline_module_relative_path() { "###); } -// FIXME: issue #1510. not support out-of-line modules inside inline. #[test] -#[ignore] fn module_resolution_decl_inside_inline_module_in_crate_root() { let map = def_map_with_crate_graph( r###" @@ -557,9 +584,7 @@ fn module_resolution_decl_inside_inline_module_in_crate_root() { "###); } -// FIXME: issue #1510. not support out-of-line modules inside inline. #[test] -#[ignore] fn module_resolution_decl_inside_inline_module_in_mod_rs() { let map = def_map_with_crate_graph( r###" @@ -597,9 +622,7 @@ fn module_resolution_decl_inside_inline_module_in_mod_rs() { "###); } -// FIXME: issue #1510. not support out-of-line modules inside inline. #[test] -#[ignore] fn module_resolution_decl_inside_inline_module_in_non_crate_root() { let map = def_map_with_crate_graph( r###" @@ -613,7 +636,7 @@ fn module_resolution_decl_inside_inline_module_in_non_crate_root() { } use self::bar::baz::Baz; - //- /foo/bar/qwe.rs + //- /bar/qwe.rs pub struct Baz; "###, crate_graph! { @@ -637,7 +660,7 @@ fn module_resolution_decl_inside_inline_module_in_non_crate_root() { "###); } -// FIXME: issue #1510. not support out-of-line modules inside inline. +// FIXME: issue #1529. not support out-of-line modules inside inline. #[test] #[ignore] fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { -- cgit v1.2.3