mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
Return multiple modules in parent_module
This commit is contained in:
parent
f2c39d0cdf
commit
2e3c156b0e
5 changed files with 76 additions and 35 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -486,6 +486,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"profile",
|
"profile",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
|
"smallvec",
|
||||||
"stdx",
|
"stdx",
|
||||||
"syntax",
|
"syntax",
|
||||||
"tt",
|
"tt",
|
||||||
|
|
|
@ -15,6 +15,7 @@ rustc-hash = "1.1.0"
|
||||||
either = "1.5.3"
|
either = "1.5.3"
|
||||||
arrayvec = "0.5.1"
|
arrayvec = "0.5.1"
|
||||||
itertools = "0.10.0"
|
itertools = "0.10.0"
|
||||||
|
smallvec = "1.4.0"
|
||||||
|
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
syntax = { path = "../syntax", version = "0.0.0" }
|
syntax = { path = "../syntax", version = "0.0.0" }
|
||||||
|
|
|
@ -259,6 +259,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_module_def(&self, file: FileId) -> Option<Module> {
|
pub fn to_module_def(&self, file: FileId) -> Option<Module> {
|
||||||
|
self.imp.to_module_def(file).next()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
|
||||||
self.imp.to_module_def(file)
|
self.imp.to_module_def(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,8 +541,8 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
f(&mut ctx)
|
f(&mut ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_module_def(&self, file: FileId) -> Option<Module> {
|
fn to_module_def(&self, file: FileId) -> impl Iterator<Item = Module> {
|
||||||
self.with_ctx(|ctx| ctx.file_to_def(file)).map(Module::from)
|
self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
|
fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
|
||||||
|
|
|
@ -12,6 +12,7 @@ use hir_def::{
|
||||||
};
|
};
|
||||||
use hir_expand::{name::AsName, AstId, MacroDefKind};
|
use hir_expand::{name::AsName, AstId, MacroDefKind};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
use smallvec::SmallVec;
|
||||||
use stdx::impl_from;
|
use stdx::impl_from;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, NameOwner},
|
ast::{self, NameOwner},
|
||||||
|
@ -28,14 +29,19 @@ pub(super) struct SourceToDefCtx<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SourceToDefCtx<'_, '_> {
|
impl SourceToDefCtx<'_, '_> {
|
||||||
pub(super) fn file_to_def(&mut self, file: FileId) -> Option<ModuleId> {
|
pub(super) fn file_to_def(&mut self, file: FileId) -> SmallVec<[ModuleId; 1]> {
|
||||||
let _p = profile::span("SourceBinder::to_module_def");
|
let _p = profile::span("SourceBinder::to_module_def");
|
||||||
self.db.relevant_crates(file).iter().find_map(|&crate_id| {
|
let mut mods = SmallVec::new();
|
||||||
|
for &crate_id in self.db.relevant_crates(file).iter() {
|
||||||
// FIXME: inner items
|
// FIXME: inner items
|
||||||
let crate_def_map = self.db.crate_def_map(crate_id);
|
let crate_def_map = self.db.crate_def_map(crate_id);
|
||||||
let local_id = crate_def_map.modules_for_file(file).next()?;
|
mods.extend(
|
||||||
Some(crate_def_map.module_id(local_id))
|
crate_def_map
|
||||||
})
|
.modules_for_file(file)
|
||||||
|
.map(|local_id| crate_def_map.module_id(local_id)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
mods
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> {
|
pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> {
|
||||||
|
@ -55,7 +61,7 @@ impl SourceToDefCtx<'_, '_> {
|
||||||
Some(parent_declaration) => self.module_to_def(parent_declaration),
|
Some(parent_declaration) => self.module_to_def(parent_declaration),
|
||||||
None => {
|
None => {
|
||||||
let file_id = src.file_id.original_file(self.db.upcast());
|
let file_id = src.file_id.original_file(self.db.upcast());
|
||||||
self.file_to_def(file_id)
|
self.file_to_def(file_id).get(0).copied()
|
||||||
}
|
}
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
@ -185,7 +191,7 @@ impl SourceToDefCtx<'_, '_> {
|
||||||
) -> Option<MacroDefId> {
|
) -> Option<MacroDefId> {
|
||||||
let kind = MacroDefKind::Declarative;
|
let kind = MacroDefKind::Declarative;
|
||||||
let file_id = src.file_id.original_file(self.db.upcast());
|
let file_id = src.file_id.original_file(self.db.upcast());
|
||||||
let krate = self.file_to_def(file_id)?.krate();
|
let krate = self.file_to_def(file_id).get(0).copied()?.krate();
|
||||||
let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
|
let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
|
||||||
let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast()));
|
let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast()));
|
||||||
Some(MacroDefId { krate, ast_id, kind, local_inner: false })
|
Some(MacroDefId { krate, ast_id, kind, local_inner: false })
|
||||||
|
@ -245,7 +251,7 @@ impl SourceToDefCtx<'_, '_> {
|
||||||
return Some(res);
|
return Some(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
let def = self.file_to_def(src.file_id.original_file(self.db.upcast()))?;
|
let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?;
|
||||||
Some(def.into())
|
Some(def.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use hir::Semantics;
|
use hir::Semantics;
|
||||||
use ide_db::base_db::{CrateId, FileId, FilePosition};
|
use ide_db::base_db::{CrateId, FileId, FilePosition};
|
||||||
use ide_db::RootDatabase;
|
use ide_db::RootDatabase;
|
||||||
|
use itertools::Itertools;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::find_node_at_offset,
|
algo::find_node_at_offset,
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
|
@ -18,8 +19,7 @@ use crate::NavigationTarget;
|
||||||
// | VS Code | **Rust Analyzer: Locate parent module**
|
// | VS Code | **Rust Analyzer: Locate parent module**
|
||||||
// |===
|
// |===
|
||||||
|
|
||||||
/// This returns `Vec` because a module may be included from several places. We
|
/// This returns `Vec` because a module may be included from several places.
|
||||||
/// don't handle this case yet though, so the Vec has length at most one.
|
|
||||||
pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> {
|
pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> {
|
||||||
let sema = Semantics::new(db);
|
let sema = Semantics::new(db);
|
||||||
let source_file = sema.parse(position.file_id);
|
let source_file = sema.parse(position.file_id);
|
||||||
|
@ -37,27 +37,23 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let module = match module {
|
match module {
|
||||||
Some(module) => sema.to_def(&module),
|
Some(module) => sema
|
||||||
None => sema.to_module_def(position.file_id),
|
.to_def(&module)
|
||||||
};
|
.into_iter()
|
||||||
let module = match module {
|
.map(|module| NavigationTarget::from_module_to_decl(db, module))
|
||||||
None => return Vec::new(),
|
.collect(),
|
||||||
Some(it) => it,
|
None => sema
|
||||||
};
|
.to_module_defs(position.file_id)
|
||||||
let nav = NavigationTarget::from_module_to_decl(db, module);
|
.map(|module| NavigationTarget::from_module_to_decl(db, module))
|
||||||
vec![nav]
|
.collect(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `Vec` for the same reason as `parent_module`
|
/// Returns `Vec` for the same reason as `parent_module`
|
||||||
pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
|
pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
|
||||||
let sema = Semantics::new(db);
|
let sema = Semantics::new(db);
|
||||||
let module = match sema.to_module_def(file_id) {
|
sema.to_module_defs(file_id).map(|module| module.krate().into()).unique().collect()
|
||||||
Some(it) => it,
|
|
||||||
None => return Vec::new(),
|
|
||||||
};
|
|
||||||
let krate = module.krate();
|
|
||||||
vec![krate.into()]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -67,11 +63,13 @@ mod tests {
|
||||||
use crate::fixture;
|
use crate::fixture;
|
||||||
|
|
||||||
fn check(ra_fixture: &str) {
|
fn check(ra_fixture: &str) {
|
||||||
let (analysis, position, expected) = fixture::nav_target_annotation(ra_fixture);
|
let (analysis, position, expected) = fixture::annotations(ra_fixture);
|
||||||
let mut navs = analysis.parent_module(position).unwrap();
|
let navs = analysis.parent_module(position).unwrap();
|
||||||
assert_eq!(navs.len(), 1);
|
let navs = navs
|
||||||
let nav = navs.pop().unwrap();
|
.iter()
|
||||||
assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() });
|
.map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
assert_eq!(expected.into_iter().map(|(fr, _)| fr).collect::<Vec<_>>(), navs);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -120,15 +118,46 @@ mod foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_resolve_crate_root() {
|
fn test_resolve_multi_parent_module() {
|
||||||
let (analysis, file_id) = fixture::file(
|
check(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
//- /main.rs
|
||||||
mod foo;
|
mod foo;
|
||||||
|
//^^^
|
||||||
|
#[path = "foo.rs"]
|
||||||
|
mod bar;
|
||||||
|
//^^^
|
||||||
//- /foo.rs
|
//- /foo.rs
|
||||||
$0
|
$0
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_resolve_crate_root() {
|
||||||
|
let (analysis, file_id) = fixture::file(
|
||||||
|
r#"
|
||||||
|
//- /foo.rs
|
||||||
|
$0
|
||||||
|
//- /main.rs
|
||||||
|
mod foo;
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1);
|
assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_resolve_multi_parent_crate() {
|
||||||
|
let (analysis, file_id) = fixture::file(
|
||||||
|
r#"
|
||||||
|
//- /baz.rs
|
||||||
|
$0
|
||||||
|
//- /foo.rs crate:foo
|
||||||
|
mod baz;
|
||||||
|
//- /bar.rs crate:bar
|
||||||
|
mod baz;
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
assert_eq!(analysis.crate_for(file_id).unwrap().len(), 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue