Use more OO API for parent module
This commit is contained in:
parent
099da13f53
commit
3b8d0c215a
@ -1,16 +1,90 @@
|
||||
pub(super) mod imp;
|
||||
pub(crate) mod scope;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use ra_editor::find_node_at_offset;
|
||||
|
||||
use ra_syntax::{
|
||||
ast::{self, AstNode, NameOwner},
|
||||
SmolStr, SyntaxNode, SyntaxNodeRef,
|
||||
};
|
||||
use relative_path::RelativePathBuf;
|
||||
|
||||
use crate::{db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId};
|
||||
use crate::{
|
||||
db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId, FilePosition, Cancelable,
|
||||
descriptors::DescriptorDatabase,
|
||||
};
|
||||
|
||||
pub(crate) use self::scope::ModuleScope;
|
||||
|
||||
/// `ModuleDescriptor` is API entry point to get all the information
|
||||
/// about a particular module.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ModuleDescriptor {
|
||||
tree: Arc<ModuleTree>,
|
||||
module_id: ModuleId,
|
||||
}
|
||||
|
||||
impl ModuleDescriptor {
|
||||
/// Lookup `ModuleDescriptor` by position in the source code. Note that this
|
||||
/// is inherently lossy transformation: in general, a single source might
|
||||
/// correspond to several modules.
|
||||
pub fn guess_from_position(
|
||||
db: &impl DescriptorDatabase,
|
||||
position: FilePosition,
|
||||
) -> Cancelable<Option<ModuleDescriptor>> {
|
||||
let source_root = db.file_source_root(position.file_id);
|
||||
let module_tree = db.module_tree(source_root)?;
|
||||
let file = db.file_syntax(position.file_id);
|
||||
let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset)
|
||||
{
|
||||
Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m),
|
||||
_ => ModuleSource::SourceFile(position.file_id),
|
||||
};
|
||||
let res = match module_tree.any_module_for_source(module_source) {
|
||||
None => None,
|
||||
Some(module_id) => Some(ModuleDescriptor {
|
||||
tree: module_tree,
|
||||
module_id,
|
||||
}),
|
||||
};
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Returns `mod foo;` or `mod foo {}` node whihc declared this module.
|
||||
/// Returns `None` for the root module
|
||||
pub fn parent_link_source(
|
||||
&self,
|
||||
db: &impl DescriptorDatabase,
|
||||
) -> Option<(FileId, ast::ModuleNode)> {
|
||||
let link = self.module_id.parent_link(&self.tree)?;
|
||||
let file_id = link.owner(&self.tree).source(&self.tree).file_id();
|
||||
let src = link.bind_source(&self.tree, db);
|
||||
Some((file_id, src))
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> Option<ModuleDescriptor> {
|
||||
let parent_id = self.module_id.parent(&self.tree)?;
|
||||
Some(ModuleDescriptor {
|
||||
tree: Arc::clone(&self.tree),
|
||||
module_id: parent_id,
|
||||
})
|
||||
}
|
||||
/// `name` is `None` for the crate's root module
|
||||
pub fn name(&self) -> Option<SmolStr> {
|
||||
let link = self.module_id.parent_link(&self.tree)?;
|
||||
Some(link.name(&self.tree))
|
||||
}
|
||||
pub fn child(&self, name: &str) -> Option<ModuleDescriptor> {
|
||||
let child_id = self.module_id.child(&self.tree, name)?;
|
||||
Some(ModuleDescriptor {
|
||||
tree: Arc::clone(&self.tree),
|
||||
module_id: child_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Phisically, rust source is organized as a set of files, but logically it is
|
||||
/// organized as a tree of modules. Usually, a single file corresponds to a
|
||||
/// single module, but it is not nessary the case.
|
||||
@ -136,6 +210,9 @@ impl LinkId {
|
||||
pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
|
||||
tree.link(self).owner
|
||||
}
|
||||
pub(crate) fn name(self, tree: &ModuleTree) -> SmolStr {
|
||||
tree.link(self).name.clone()
|
||||
}
|
||||
pub(crate) fn bind_source<'a>(
|
||||
self,
|
||||
tree: &ModuleTree,
|
||||
|
@ -21,7 +21,7 @@ use crate::{
|
||||
db::{self, FileSyntaxQuery, SyntaxDatabase},
|
||||
descriptors::{
|
||||
function::{FnDescriptor, FnId},
|
||||
module::{ModuleSource, ModuleTree, Problem},
|
||||
module::{ModuleDescriptor, ModuleSource, ModuleTree, Problem},
|
||||
DeclarationDescriptor, DescriptorDatabase,
|
||||
},
|
||||
input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE},
|
||||
@ -221,34 +221,22 @@ impl AnalysisImpl {
|
||||
self.db.module_tree(source_root)
|
||||
}
|
||||
pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
|
||||
let module_tree = self.module_tree(position.file_id)?;
|
||||
let file = self.db.file_syntax(position.file_id);
|
||||
let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset)
|
||||
{
|
||||
Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m),
|
||||
_ => ModuleSource::SourceFile(position.file_id),
|
||||
let descr = match ModuleDescriptor::guess_from_position(&*self.db, position)? {
|
||||
None => return Ok(Vec::new()),
|
||||
Some(it) => it,
|
||||
};
|
||||
|
||||
let res = module_tree
|
||||
.modules_for_source(module_source)
|
||||
.into_iter()
|
||||
.filter_map(|module_id| {
|
||||
let link = module_id.parent_link(&module_tree)?;
|
||||
let file_id = link.owner(&module_tree).source(&module_tree).file_id();
|
||||
let decl = link.bind_source(&module_tree, &*self.db);
|
||||
let decl = decl.borrowed();
|
||||
|
||||
let decl_name = decl.name().unwrap();
|
||||
|
||||
let sym = FileSymbol {
|
||||
name: decl_name.text(),
|
||||
node_range: decl_name.syntax().range(),
|
||||
kind: MODULE,
|
||||
};
|
||||
Some((file_id, sym))
|
||||
})
|
||||
.collect();
|
||||
Ok(res)
|
||||
let (file_id, decl) = match descr.parent_link_source(&*self.db) {
|
||||
None => return Ok(Vec::new()),
|
||||
Some(it) => it,
|
||||
};
|
||||
let decl = decl.borrowed();
|
||||
let decl_name = decl.name().unwrap();
|
||||
let sym = FileSymbol {
|
||||
name: decl_name.text(),
|
||||
node_range: decl_name.syntax().range(),
|
||||
kind: MODULE,
|
||||
};
|
||||
Ok(vec![(file_id, sym)])
|
||||
}
|
||||
pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
|
||||
let module_tree = self.module_tree(file_id)?;
|
||||
|
Loading…
x
Reference in New Issue
Block a user