aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/completion
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2020-09-07 22:00:00 +0100
committerKirill Bulatov <[email protected]>2020-09-09 23:42:20 +0100
commitcc43abcde87ed4a834f3b56a96ef165d8e4f0d86 (patch)
treebc99f40aeaf59042bbd64da1c002e6bcbf5ca198 /crates/ide/src/completion
parent3fd6f451417fee0e8d95d06fb298c94b22bca917 (diff)
Less false positive completion candidates
Diffstat (limited to 'crates/ide/src/completion')
-rw-r--r--crates/ide/src/completion/complete_mod.rs103
1 files changed, 59 insertions, 44 deletions
diff --git a/crates/ide/src/completion/complete_mod.rs b/crates/ide/src/completion/complete_mod.rs
index def8b8968..c5757a310 100644
--- a/crates/ide/src/completion/complete_mod.rs
+++ b/crates/ide/src/completion/complete_mod.rs
@@ -3,6 +3,7 @@
3use base_db::{SourceDatabaseExt, VfsPath}; 3use base_db::{SourceDatabaseExt, VfsPath};
4use hir::{Module, ModuleSource}; 4use hir::{Module, ModuleSource};
5use ide_db::RootDatabase; 5use ide_db::RootDatabase;
6use rustc_hash::FxHashSet;
6 7
7use super::{completion_context::CompletionContext, completion_item::Completions}; 8use super::{completion_context::CompletionContext, completion_item::Completions};
8 9
@@ -10,84 +11,98 @@ use super::{completion_context::CompletionContext, completion_item::Completions}
10pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 11pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
11 let current_module = ctx.scope.module()?; 12 let current_module = ctx.scope.module()?;
12 13
13 // TODO kb filter out declarations in possible_sudmobule_names 14 let module_definition_file =
14 // let declaration_source = current_module.declaration_source(ctx.db);
15 let module_definition_source_file =
16 current_module.definition_source(ctx.db).file_id.original_file(ctx.db); 15 current_module.definition_source(ctx.db).file_id.original_file(ctx.db);
17 let source_root = ctx.db.source_root(ctx.db.file_source_root(module_definition_source_file)); 16 let source_root = ctx.db.source_root(ctx.db.file_source_root(module_definition_file));
18 let directory_to_look_for_submodules = directory_to_look_for_submodules( 17 let directory_to_look_for_submodules = directory_to_look_for_submodules(
19 current_module, 18 current_module,
20 ctx.db, 19 ctx.db,
21 source_root.path_for_file(&module_definition_source_file)?, 20 source_root.path_for_file(&module_definition_file)?,
22 )?; 21 )?;
23 22
23 let existing_mod_declarations = current_module
24 .children(ctx.db)
25 .filter_map(|module| Some(module.name(ctx.db)?.to_string()))
26 .collect::<FxHashSet<_>>();
27
28 let module_declaration_file =
29 current_module.declaration_source(ctx.db).map(|module_declaration_source_file| {
30 module_declaration_source_file.file_id.original_file(ctx.db)
31 });
32
24 let mod_declaration_candidates = source_root 33 let mod_declaration_candidates = source_root
25 .iter() 34 .iter()
26 .filter(|submodule_file| submodule_file != &module_definition_source_file) 35 .filter(|submodule_candidate_file| submodule_candidate_file != &module_definition_file)
36 .filter(|submodule_candidate_file| {
37 Some(submodule_candidate_file) != module_declaration_file.as_ref()
38 })
27 .filter_map(|submodule_file| { 39 .filter_map(|submodule_file| {
28 let submodule_path = source_root.path_for_file(&submodule_file)?; 40 let submodule_path = source_root.path_for_file(&submodule_file)?;
29 if submodule_path.parent()? == directory_to_look_for_submodules { 41 if !is_special_rust_file_path(&submodule_path)
42 && submodule_path.parent()? == directory_to_look_for_submodules
43 {
30 submodule_path.file_name_and_extension() 44 submodule_path.file_name_and_extension()
31 } else { 45 } else {
32 None 46 None
33 } 47 }
34 }) 48 })
35 .filter_map(|file_name_and_extension| { 49 .filter_map(|submodule_file_name_and_extension| match submodule_file_name_and_extension {
36 match file_name_and_extension { 50 (file_name, Some("rs")) => Some(file_name.to_owned()),
37 // TODO kb in src/bin when a module is included into another, 51 (subdirectory_name, None) => {
38 // the included file gets "moved" into a directory below and now cannot add any other modules 52 let mod_rs_path =
39 ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => None, 53 directory_to_look_for_submodules.join(subdirectory_name)?.join("mod.rs")?;
40 (file_name, Some("rs")) => Some(file_name.to_owned()), 54 if source_root.file_for_path(&mod_rs_path).is_some() {
41 (subdirectory_name, None) => { 55 Some(subdirectory_name.to_owned())
42 let mod_rs_path = 56 } else {
43 directory_to_look_for_submodules.join(subdirectory_name)?.join("mod.rs")?; 57 None
44 if source_root.file_for_path(&mod_rs_path).is_some() {
45 Some(subdirectory_name.to_owned())
46 } else {
47 None
48 }
49 } 58 }
50 _ => None,
51 } 59 }
60 _ => None,
52 }) 61 })
62 .filter(|name| !existing_mod_declarations.contains(name))
53 .collect::<Vec<_>>(); 63 .collect::<Vec<_>>();
54 dbg!(mod_declaration_candidates); 64 dbg!(mod_declaration_candidates);
55 65
56 // TODO kb exlude existing children from the candidates 66 // TODO kb exlude existing children from the candidates
57 let existing_children = current_module.children(ctx.db).collect::<Vec<_>>();
58 67
59 Some(()) 68 Some(())
60} 69}
61 70
71fn is_special_rust_file_path(path: &VfsPath) -> bool {
72 matches!(
73 path.file_name_and_extension(),
74 Some(("mod", Some("rs"))) | Some(("lib", Some("rs"))) | Some(("main", Some("rs")))
75 )
76}
77
62fn directory_to_look_for_submodules( 78fn directory_to_look_for_submodules(
63 module: Module, 79 module: Module,
64 db: &RootDatabase, 80 db: &RootDatabase,
65 module_file_path: &VfsPath, 81 module_file_path: &VfsPath,
66) -> Option<VfsPath> { 82) -> Option<VfsPath> {
67 let module_directory_path = module_file_path.parent()?; 83 let module_directory_path = module_file_path.parent()?;
68 84 let base_directory = if is_special_rust_file_path(module_file_path) {
69 let base_directory = match module_file_path.file_name_and_extension()? { 85 Some(module_directory_path)
70 ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => { 86 } else if let (regular_rust_file_name, Some("rs")) =
87 module_file_path.file_name_and_extension()?
88 {
89 if matches!(
90 (
91 module_directory_path
92 .parent()
93 .as_ref()
94 .and_then(|path| path.file_name_and_extension()),
95 module_directory_path.file_name_and_extension(),
96 ),
97 (Some(("src", None)), Some(("bin", None)))
98 ) {
99 // files in /src/bin/ can import each other directly
71 Some(module_directory_path) 100 Some(module_directory_path)
101 } else {
102 module_directory_path.join(regular_rust_file_name)
72 } 103 }
73 (regular_rust_file_name, Some("rs")) => { 104 } else {
74 if matches!( 105 None
75 (
76 module_directory_path
77 .parent()
78 .as_ref()
79 .and_then(|path| path.file_name_and_extension()),
80 module_directory_path.file_name_and_extension(),
81 ),
82 (Some(("src", None)), Some(("bin", None)))
83 ) {
84 // files in /src/bin/ can import each other directly
85 Some(module_directory_path)
86 } else {
87 module_directory_path.join(regular_rust_file_name)
88 }
89 }
90 _ => None,
91 }?; 106 }?;
92 107
93 let mut resulting_path = base_directory; 108 let mut resulting_path = base_directory;