Skip to content

Commit cc43abc

Browse files
Less false positive completion candidates
1 parent 3fd6f45 commit cc43abc

File tree

1 file changed

+59
-44
lines changed

1 file changed

+59
-44
lines changed

crates/ide/src/completion/complete_mod.rs

Lines changed: 59 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,91 +3,106 @@
33
use base_db::{SourceDatabaseExt, VfsPath};
44
use hir::{Module, ModuleSource};
55
use ide_db::RootDatabase;
6+
use rustc_hash::FxHashSet;
67

78
use super::{completion_context::CompletionContext, completion_item::Completions};
89

910
/// Complete mod declaration, i.e. `mod <|> ;`
1011
pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
1112
let current_module = ctx.scope.module()?;
1213

13-
// TODO kb filter out declarations in possible_sudmobule_names
14-
// let declaration_source = current_module.declaration_source(ctx.db);
15-
let module_definition_source_file =
14+
let module_definition_file =
1615
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));
1817
let directory_to_look_for_submodules = directory_to_look_for_submodules(
1918
current_module,
2019
ctx.db,
21-
source_root.path_for_file(&module_definition_source_file)?,
20+
source_root.path_for_file(&module_definition_file)?,
2221
)?;
2322

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+
2433
let mod_declaration_candidates = source_root
2534
.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+
})
2739
.filter_map(|submodule_file| {
2840
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+
{
3044
submodule_path.file_name_and_extension()
3145
} else {
3246
None
3347
}
3448
})
35-
.filter_map(|file_name_and_extension| {
36-
match file_name_and_extension {
37-
// TODO kb in src/bin when a module is included into another,
38-
// the included file gets "moved" into a directory below and now cannot add any other modules
39-
("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => None,
40-
(file_name, Some("rs")) => Some(file_name.to_owned()),
41-
(subdirectory_name, None) => {
42-
let mod_rs_path =
43-
directory_to_look_for_submodules.join(subdirectory_name)?.join("mod.rs")?;
44-
if source_root.file_for_path(&mod_rs_path).is_some() {
45-
Some(subdirectory_name.to_owned())
46-
} else {
47-
None
48-
}
49+
.filter_map(|submodule_file_name_and_extension| match submodule_file_name_and_extension {
50+
(file_name, Some("rs")) => Some(file_name.to_owned()),
51+
(subdirectory_name, None) => {
52+
let mod_rs_path =
53+
directory_to_look_for_submodules.join(subdirectory_name)?.join("mod.rs")?;
54+
if source_root.file_for_path(&mod_rs_path).is_some() {
55+
Some(subdirectory_name.to_owned())
56+
} else {
57+
None
4958
}
50-
_ => None,
5159
}
60+
_ => None,
5261
})
62+
.filter(|name| !existing_mod_declarations.contains(name))
5363
.collect::<Vec<_>>();
5464
dbg!(mod_declaration_candidates);
5565

5666
// TODO kb exlude existing children from the candidates
57-
let existing_children = current_module.children(ctx.db).collect::<Vec<_>>();
5867

5968
Some(())
6069
}
6170

71+
fn 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+
6278
fn directory_to_look_for_submodules(
6379
module: Module,
6480
db: &RootDatabase,
6581
module_file_path: &VfsPath,
6682
) -> Option<VfsPath> {
6783
let module_directory_path = module_file_path.parent()?;
68-
69-
let base_directory = match module_file_path.file_name_and_extension()? {
70-
("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => {
84+
let base_directory = if is_special_rust_file_path(module_file_path) {
85+
Some(module_directory_path)
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
71100
Some(module_directory_path)
101+
} else {
102+
module_directory_path.join(regular_rust_file_name)
72103
}
73-
(regular_rust_file_name, Some("rs")) => {
74-
if matches!(
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,
104+
} else {
105+
None
91106
}?;
92107

93108
let mut resulting_path = base_directory;

0 commit comments

Comments
 (0)