Added resolve modules inside inline module

#1510
This commit is contained in:
Alexander Andreev 2019-07-29 09:54:40 +03:00
parent de278d1649
commit 538ec1122b
2 changed files with 146 additions and 53 deletions

View file

@ -1,7 +1,7 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::sync::Arc;
use arrayvec::ArrayVec; use ra_db::{FileId, SourceRoot};
use ra_db::FileId;
use ra_syntax::{ast, SmolStr}; use ra_syntax::{ast, SmolStr};
use relative_path::RelativePathBuf; use relative_path::RelativePathBuf;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
@ -106,7 +106,7 @@ where
file_id: file_id.into(), file_id: file_id.into(),
raw_items: &raw_items, raw_items: &raw_items,
} }
.collect(raw_items.items()); .collect(None, raw_items.items());
// main name resolution fixed-point loop. // main name resolution fixed-point loop.
let mut i = 0; let mut i = 0;
@ -456,7 +456,7 @@ where
let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items); let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items);
let raw_items = self.db.raw_items(file_id); let raw_items = self.db.raw_items(file_id);
ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items } ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items }
.collect(raw_items.items()); .collect(None, raw_items.items());
} else { } else {
log::error!("Too deep macro expansion: {:?}", macro_call_id); log::error!("Too deep macro expansion: {:?}", macro_call_id);
self.def_map.poison_macros.insert(macro_def_id); self.def_map.poison_macros.insert(macro_def_id);
@ -482,10 +482,10 @@ impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>>
where where
DB: DefDatabase, DB: DefDatabase,
{ {
fn collect(&mut self, items: &[raw::RawItem]) { fn collect(&mut self, parent_module: Option<&Name>, items: &[raw::RawItem]) {
for item in items { for item in items {
match *item { 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(( raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push((
self.module_id, self.module_id,
import, 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 { match module {
// inline module, just recurse // inline module, just recurse
raw::ModuleData::Definition { name, items, ast_id } => { raw::ModuleData::Definition { name, items, ast_id } => {
@ -509,7 +509,7 @@ where
file_id: self.file_id, file_id: self.file_id,
raw_items: self.raw_items, raw_items: self.raw_items,
} }
.collect(&*items); .collect(Some(name), &*items);
} }
// out of line module, resolve, parse and recurse // out of line module, resolve, parse and recurse
raw::ModuleData::Declaration { name, ast_id, attr_path } => { raw::ModuleData::Declaration { name, ast_id, attr_path } => {
@ -521,6 +521,7 @@ where
name, name,
is_root, is_root,
attr_path.as_ref(), attr_path.as_ref(),
_module,
) { ) {
Ok(file_id) => { Ok(file_id) => {
let module_id = self.push_child_module(name.clone(), ast_id, Some(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(), file_id: file_id.into(),
raw_items: &raw_items, raw_items: &raw_items,
} }
.collect(raw_items.items()) .collect(None, raw_items.items())
} }
Err(candidate) => self.def_collector.def_map.diagnostics.push( Err(candidate) => self.def_collector.def_map.diagnostics.push(
DefDiagnostic::UnresolvedModule { DefDiagnostic::UnresolvedModule {
@ -636,46 +637,47 @@ fn resolve_submodule(
name: &Name, name: &Name,
is_root: bool, is_root: bool,
attr_path: Option<&SmolStr>, attr_path: Option<&SmolStr>,
parent_module: Option<&Name>,
) -> Result<FileId, RelativePathBuf> { ) -> Result<FileId, RelativePathBuf> {
// FIXME: handle submodules of inline modules properly
let file_id = file_id.original_file(db); let file_id = file_id.original_file(db);
let source_root_id = db.file_source_root(file_id); let source_root_id = db.file_source_root(file_id);
let path = db.file_relative_path(file_id); let path = db.file_relative_path(file_id);
let root = RelativePathBuf::default(); let root = RelativePathBuf::default();
let dir_path = path.parent().unwrap_or(&root); let dir_path = path.parent().unwrap_or(&root);
let mod_name = path.file_stem().unwrap_or("unknown"); 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 resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) {
let dir_mod = dir_path.join(format!("{}/mod.rs", name)); (Some(file_path), Some(parent_name)) => {
let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name)); let file_path = normalize_attribute_path(file_path);
let mut candidates = ArrayVec::<[_; 3]>::new(); let path = dir_path.join(format!("{}/{}", parent_name, file_path)).normalize();
let file_attr_mod = attr_path.map(|file_path| { ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath(path))
let file_path = normalize_attribute_path(file_path); }
let file_attr_mod = dir_path.join(file_path.as_ref()).normalize(); (Some(file_path), None) => {
candidates.push(file_attr_mod.clone()); let file_path = normalize_attribute_path(file_path);
let path = dir_path.join(file_path.as_ref()).normalize();
file_attr_mod ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path))
}); }
if is_dir_owner { (None, Some(parent_name)) => {
candidates.push(file_mod.clone()); let path = dir_path.join(format!("{}/{}.rs", parent_name, name));
candidates.push(dir_mod); ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path))
} else { }
candidates.push(file_dir_mod.clone()); _ => {
}; let is_dir_owner = is_root || mod_name == "mod";
let sr = db.source_root(source_root_id); if is_dir_owner {
let mut points_to = candidates.into_iter().filter_map(|path| sr.files.get(&path)).copied(); let file_mod = dir_path.join(format!("{}.rs", name));
// FIXME: handle ambiguity let dir_mod = dir_path.join(format!("{}/mod.rs", name));
match points_to.next() { ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs {
Some(file_id) => Ok(file_id), file: file_mod,
None => { directory: dir_mod,
if let Some(file_attr_mod) = file_attr_mod { })
Err(file_attr_mod)
} else { } 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<str> { fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> {
@ -693,6 +695,74 @@ fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> {
} }
} }
enum OutOfLineMode {
RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf },
FileInDirectory(RelativePathBuf),
WithAttributePath(RelativePathBuf),
}
impl OutOfLineMode {
pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
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<SourceRoot>) -> Result<FileId, RelativePathBuf> {
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<SourceRoot>) -> Result<FileId, RelativePathBuf> {
use self::ResolutionMode::*;
match self {
OutOfLine(mode) => mode.resolve(source_root),
InsideInlineModule(mode) => mode.resolve(source_root),
}
}
}
fn resolve_simple_path(
source_root: Arc<SourceRoot>,
path: &RelativePathBuf,
) -> Result<FileId, RelativePathBuf> {
resolve_find_result(source_root.files.get(path), path)
}
fn resolve_find_result(
file_id: Option<&FileId>,
path: &RelativePathBuf,
) -> Result<FileId, RelativePathBuf> {
match file_id {
Some(file_id) => Ok(file_id.clone()),
None => Err(path.clone()),
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ra_db::SourceDatabase; use ra_db::SourceDatabase;

View file

@ -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] #[test]
#[ignore] #[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( let map = def_map_with_crate_graph(
r###" r###"
//- /main.rs //- /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] #[test]
#[ignore] #[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( let map = def_map_with_crate_graph(
r###" r###"
//- /main.rs //- /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] #[test]
#[ignore] #[ignore]
fn module_resolution_decl_inside_inline_module_3() { 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] #[test]
#[ignore] #[ignore]
fn module_resolution_decl_inside_inline_module_empty_path() { 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] #[test]
#[ignore] #[ignore]
fn module_resolution_decl_inside_inline_module_relative_path() { 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] #[test]
#[ignore]
fn module_resolution_decl_inside_inline_module_in_crate_root() { fn module_resolution_decl_inside_inline_module_in_crate_root() {
let map = def_map_with_crate_graph( let map = def_map_with_crate_graph(
r###" 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] #[test]
#[ignore]
fn module_resolution_decl_inside_inline_module_in_mod_rs() { fn module_resolution_decl_inside_inline_module_in_mod_rs() {
let map = def_map_with_crate_graph( let map = def_map_with_crate_graph(
r###" 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] #[test]
#[ignore]
fn module_resolution_decl_inside_inline_module_in_non_crate_root() { fn module_resolution_decl_inside_inline_module_in_non_crate_root() {
let map = def_map_with_crate_graph( let map = def_map_with_crate_graph(
r###" r###"
@ -613,7 +636,7 @@ fn module_resolution_decl_inside_inline_module_in_non_crate_root() {
} }
use self::bar::baz::Baz; use self::bar::baz::Baz;
//- /foo/bar/qwe.rs //- /bar/qwe.rs
pub struct Baz; pub struct Baz;
"###, "###,
crate_graph! { 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] #[test]
#[ignore] #[ignore]
fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() {