From f9c14ac7204c38633e70b3efd47a5b1f9056afd0 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 7 Sep 2020 20:52:37 +0300 Subject: Move most of the logic into the completion module --- crates/base_db/src/input.rs | 8 +- crates/base_db/src/lib.rs | 84 +---------------- crates/hir_def/src/test_db.rs | 3 - crates/hir_expand/src/test_db.rs | 3 - crates/hir_ty/src/test_db.rs | 3 - crates/ide/src/completion/complete_mod.rs | 116 +++++++++++++++++++----- crates/ide/src/completion/completion_context.rs | 5 +- crates/ide_db/src/lib.rs | 3 - 8 files changed, 107 insertions(+), 118 deletions(-) diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs index f3d65cdf0..9a61f1d56 100644 --- a/crates/base_db/src/input.rs +++ b/crates/base_db/src/input.rs @@ -12,7 +12,7 @@ use cfg::CfgOptions; use rustc_hash::{FxHashMap, FxHashSet}; use syntax::SmolStr; use tt::TokenExpander; -use vfs::file_set::FileSet; +use vfs::{file_set::FileSet, VfsPath}; pub use vfs::FileId; @@ -43,6 +43,12 @@ impl SourceRoot { pub fn new_library(file_set: FileSet) -> SourceRoot { SourceRoot { is_library: true, file_set } } + pub fn path_for_file(&self, file: &FileId) -> Option<&VfsPath> { + self.file_set.path_for_file(file) + } + pub fn file_for_path(&self, path: &VfsPath) -> Option<&FileId> { + self.file_set.file_for_path(path) + } pub fn iter(&self) -> impl Iterator + '_ { self.file_set.iter() } diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs index 321007d33..ee3415850 100644 --- a/crates/base_db/src/lib.rs +++ b/crates/base_db/src/lib.rs @@ -96,7 +96,6 @@ pub trait FileLoader { /// `#[path = "C://no/way"]` fn resolve_path(&self, anchor: FileId, path: &str) -> Option; fn relevant_crates(&self, file_id: FileId) -> Arc>; - fn possible_sudmobule_names(&self, module_file: FileId) -> Vec; } /// Database which stores all significant input facts: source code and project @@ -156,8 +155,8 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { } fn resolve_path(&self, anchor: FileId, path: &str) -> Option { // FIXME: this *somehow* should be platform agnostic... - // self.source_root(anchor) - let source_root = self.source_root(anchor); + let source_root = self.0.file_source_root(anchor); + let source_root = self.0.source_root(source_root); source_root.file_set.resolve_path(anchor, path) } @@ -165,83 +164,4 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { let source_root = self.0.file_source_root(file_id); self.0.source_root_crates(source_root) } - - fn possible_sudmobule_names(&self, module_file: FileId) -> Vec { - possible_sudmobule_names(&self.source_root(module_file).file_set, module_file) - } -} - -impl FileLoaderDelegate<&'_ T> { - fn source_root(&self, anchor: FileId) -> Arc { - let source_root = self.0.file_source_root(anchor); - self.0.source_root(source_root) - } -} - -fn possible_sudmobule_names(module_files: &FileSet, module_file: FileId) -> Vec { - let directory_to_look_for_submodules = match module_files - .path_for_file(&module_file) - .and_then(|module_file_path| get_directory_with_submodules(module_file_path)) - { - Some(directory) => directory, - None => return Vec::new(), - }; - module_files - .iter() - .filter(|submodule_file| submodule_file != &module_file) - .filter_map(|submodule_file| { - let submodule_path = module_files.path_for_file(&submodule_file)?; - if submodule_path.parent()? == directory_to_look_for_submodules { - submodule_path.file_name_and_extension() - } else { - None - } - }) - .filter_map(|file_name_and_extension| { - match file_name_and_extension { - // TODO kb wrong resolution for nested non-file modules (mod tests { mod <|> }) - // TODO kb in src/bin when a module is included into another, - // the included file gets "moved" into a directory below and now cannot add any other modules - ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => None, - (file_name, Some("rs")) => Some(file_name.to_owned()), - (subdirectory_name, None) => { - let mod_rs_path = - directory_to_look_for_submodules.join(subdirectory_name)?.join("mod.rs")?; - if module_files.file_for_path(&mod_rs_path).is_some() { - Some(subdirectory_name.to_owned()) - } else { - None - } - } - _ => None, - } - }) - .collect() -} - -fn get_directory_with_submodules(module_file_path: &VfsPath) -> Option { - let module_directory_path = module_file_path.parent()?; - match module_file_path.file_name_and_extension()? { - ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => { - Some(module_directory_path) - } - (regular_rust_file_name, Some("rs")) => { - if matches!( - ( - module_directory_path - .parent() - .as_ref() - .and_then(|path| path.file_name_and_extension()), - module_directory_path.file_name_and_extension(), - ), - (Some(("src", None)), Some(("bin", None))) - ) { - // files in /src/bin/ can import each other directly - Some(module_directory_path) - } else { - module_directory_path.join(regular_rust_file_name) - } - } - _ => None, - } } diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs index 5bcfaf464..42a762936 100644 --- a/crates/hir_def/src/test_db.rs +++ b/crates/hir_def/src/test_db.rs @@ -63,9 +63,6 @@ impl FileLoader for TestDB { fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } - fn possible_sudmobule_names(&self, module_file: FileId) -> Vec { - FileLoaderDelegate(self).possible_sudmobule_names(module_file) - } } impl TestDB { diff --git a/crates/hir_expand/src/test_db.rs b/crates/hir_expand/src/test_db.rs index cf42dde7a..86a5d867e 100644 --- a/crates/hir_expand/src/test_db.rs +++ b/crates/hir_expand/src/test_db.rs @@ -46,7 +46,4 @@ impl FileLoader for TestDB { fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } - fn possible_sudmobule_names(&self, module_file: FileId) -> Vec { - FileLoaderDelegate(self).possible_sudmobule_names(module_file) - } } diff --git a/crates/hir_ty/src/test_db.rs b/crates/hir_ty/src/test_db.rs index 0696f41dd..15b8435e9 100644 --- a/crates/hir_ty/src/test_db.rs +++ b/crates/hir_ty/src/test_db.rs @@ -73,9 +73,6 @@ impl FileLoader for TestDB { fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } - fn possible_sudmobule_names(&self, module_file: FileId) -> Vec { - FileLoaderDelegate(self).possible_sudmobule_names(module_file) - } } impl TestDB { diff --git a/crates/ide/src/completion/complete_mod.rs b/crates/ide/src/completion/complete_mod.rs index 4c1e79603..da3d93bad 100644 --- a/crates/ide/src/completion/complete_mod.rs +++ b/crates/ide/src/completion/complete_mod.rs @@ -1,35 +1,61 @@ //! Completes mod declarations. -use base_db::FileLoader; -use hir::ModuleSource; +use base_db::{SourceDatabaseExt, VfsPath}; +use hir::{Module, ModuleSource}; +use ide_db::RootDatabase; use super::{completion_context::CompletionContext, completion_item::Completions}; /// Complete mod declaration, i.e. `mod <|> ;` pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) { let module_names_for_import = ctx - .sema - // TODO kb this is wrong, since we need not the file module - .to_module_def(ctx.position.file_id) + .scope + .module() .and_then(|current_module| { - dbg!(current_module.name(ctx.db)); - dbg!(current_module.definition_source(ctx.db)); - dbg!(current_module.declaration_source(ctx.db)); - let mut zz = Vec::new(); - let mut vv = Some(current_module); - while let Some(ModuleSource::Module(_)) = - vv.map(|vv| vv.definition_source(ctx.db).value) - { - zz.push(current_module.name(ctx.db)); - vv = current_module.parent(ctx.db); - } - dbg!(zz); - let definition_source = current_module.definition_source(ctx.db); + let module_path = path_to_closest_containing_module_file(current_module, ctx.db); // TODO kb filter out declarations in possible_sudmobule_names // let declaration_source = current_module.declaration_source(ctx.db); - let module_definition_source_file = definition_source.file_id.original_file(ctx.db); - let mod_declaration_candidates = - ctx.db.possible_sudmobule_names(module_definition_source_file); + let module_definition_source_file = + current_module.definition_source(ctx.db).file_id.original_file(ctx.db); + + let source_root_id = ctx.db.file_source_root(module_definition_source_file); + let source_root = ctx.db.source_root(source_root_id); + let directory_to_look_for_submodules = source_root + .path_for_file(&module_definition_source_file) + .and_then(|module_file_path| get_directory_with_submodules(module_file_path))?; + + let mod_declaration_candidates = source_root + .iter() + .filter(|submodule_file| submodule_file != &module_definition_source_file) + .filter_map(|submodule_file| { + let submodule_path = source_root.path_for_file(&submodule_file)?; + if submodule_path.parent()? == directory_to_look_for_submodules { + submodule_path.file_name_and_extension() + } else { + None + } + }) + .filter_map(|file_name_and_extension| { + match file_name_and_extension { + // TODO kb wrong resolution for nested non-file modules (mod tests { mod <|> }) + // TODO kb in src/bin when a module is included into another, + // the included file gets "moved" into a directory below and now cannot add any other modules + ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => None, + (file_name, Some("rs")) => Some(file_name.to_owned()), + (subdirectory_name, None) => { + let mod_rs_path = directory_to_look_for_submodules + .join(subdirectory_name)? + .join("mod.rs")?; + if source_root.file_for_path(&mod_rs_path).is_some() { + Some(subdirectory_name.to_owned()) + } else { + None + } + } + _ => None, + } + }) + .collect::>(); dbg!(mod_declaration_candidates); // TODO kb exlude existing children from the candidates let existing_children = current_module.children(ctx.db).collect::>(); @@ -37,3 +63,51 @@ pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) { }) .unwrap_or_default(); } + +fn path_to_closest_containing_module_file( + current_module: Module, + db: &RootDatabase, +) -> Vec { + let mut path = Vec::new(); + + let mut current_module = Some(current_module); + while let Some(ModuleSource::Module(_)) = + current_module.map(|module| module.definition_source(db).value) + { + if let Some(module) = current_module { + path.insert(0, module); + current_module = module.parent(db); + } else { + current_module = None; + } + } + + path +} + +fn get_directory_with_submodules(module_file_path: &VfsPath) -> Option { + let module_directory_path = module_file_path.parent()?; + match module_file_path.file_name_and_extension()? { + ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => { + Some(module_directory_path) + } + (regular_rust_file_name, Some("rs")) => { + if matches!( + ( + module_directory_path + .parent() + .as_ref() + .and_then(|path| path.file_name_and_extension()), + module_directory_path.file_name_and_extension(), + ), + (Some(("src", None)), Some(("bin", None))) + ) { + // files in /src/bin/ can import each other directly + Some(module_directory_path) + } else { + module_directory_path.join(regular_rust_file_name) + } + } + _ => None, + } +} diff --git a/crates/ide/src/completion/completion_context.rs b/crates/ide/src/completion/completion_context.rs index 31886942a..47355d5dc 100644 --- a/crates/ide/src/completion/completion_context.rs +++ b/crates/ide/src/completion/completion_context.rs @@ -1,7 +1,7 @@ //! FIXME: write short doc here -use base_db::{FileLoader, SourceDatabase}; -use hir::{ModuleSource, Semantics, SemanticsScope, Type}; +use base_db::SourceDatabase; +use hir::{Semantics, SemanticsScope, Type}; use ide_db::RootDatabase; use syntax::{ algo::{find_covering_element, find_node_at_offset}, @@ -112,6 +112,7 @@ impl<'a> CompletionContext<'a> { }; let fake_ident_token = file_with_fake_ident.syntax().token_at_offset(position.offset).right_biased().unwrap(); + let krate = sema.to_module_def(position.file_id).map(|m| m.krate()); let original_token = original_file.syntax().token_at_offset(position.offset).left_biased()?; diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index 9f3be8601..70ada02f3 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs @@ -74,9 +74,6 @@ impl FileLoader for RootDatabase { fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } - fn possible_sudmobule_names(&self, module_file: FileId) -> Vec { - FileLoaderDelegate(self).possible_sudmobule_names(module_file) - } } impl salsa::Database for RootDatabase { -- cgit v1.2.3