mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 13:25:09 +00:00
Use more OO API for parent module
This commit is contained in:
parent
099da13f53
commit
3b8d0c215a
2 changed files with 94 additions and 29 deletions
|
@ -1,16 +1,90 @@
|
||||||
pub(super) mod imp;
|
pub(super) mod imp;
|
||||||
pub(crate) mod scope;
|
pub(crate) mod scope;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ra_editor::find_node_at_offset;
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
ast::{self, AstNode, NameOwner},
|
ast::{self, AstNode, NameOwner},
|
||||||
SmolStr, SyntaxNode, SyntaxNodeRef,
|
SmolStr, SyntaxNode, SyntaxNodeRef,
|
||||||
};
|
};
|
||||||
use relative_path::RelativePathBuf;
|
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;
|
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
|
/// 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
|
/// organized as a tree of modules. Usually, a single file corresponds to a
|
||||||
/// single module, but it is not nessary the case.
|
/// single module, but it is not nessary the case.
|
||||||
|
@ -136,6 +210,9 @@ impl LinkId {
|
||||||
pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
|
pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
|
||||||
tree.link(self).owner
|
tree.link(self).owner
|
||||||
}
|
}
|
||||||
|
pub(crate) fn name(self, tree: &ModuleTree) -> SmolStr {
|
||||||
|
tree.link(self).name.clone()
|
||||||
|
}
|
||||||
pub(crate) fn bind_source<'a>(
|
pub(crate) fn bind_source<'a>(
|
||||||
self,
|
self,
|
||||||
tree: &ModuleTree,
|
tree: &ModuleTree,
|
||||||
|
|
|
@ -21,7 +21,7 @@ use crate::{
|
||||||
db::{self, FileSyntaxQuery, SyntaxDatabase},
|
db::{self, FileSyntaxQuery, SyntaxDatabase},
|
||||||
descriptors::{
|
descriptors::{
|
||||||
function::{FnDescriptor, FnId},
|
function::{FnDescriptor, FnId},
|
||||||
module::{ModuleSource, ModuleTree, Problem},
|
module::{ModuleDescriptor, ModuleSource, ModuleTree, Problem},
|
||||||
DeclarationDescriptor, DescriptorDatabase,
|
DeclarationDescriptor, DescriptorDatabase,
|
||||||
},
|
},
|
||||||
input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE},
|
input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE},
|
||||||
|
@ -221,34 +221,22 @@ impl AnalysisImpl {
|
||||||
self.db.module_tree(source_root)
|
self.db.module_tree(source_root)
|
||||||
}
|
}
|
||||||
pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
|
pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
|
||||||
let module_tree = self.module_tree(position.file_id)?;
|
let descr = match ModuleDescriptor::guess_from_position(&*self.db, position)? {
|
||||||
let file = self.db.file_syntax(position.file_id);
|
None => return Ok(Vec::new()),
|
||||||
let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset)
|
Some(it) => it,
|
||||||
{
|
};
|
||||||
Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m),
|
let (file_id, decl) = match descr.parent_link_source(&*self.db) {
|
||||||
_ => ModuleSource::SourceFile(position.file_id),
|
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 = decl.borrowed();
|
||||||
|
|
||||||
let decl_name = decl.name().unwrap();
|
let decl_name = decl.name().unwrap();
|
||||||
|
|
||||||
let sym = FileSymbol {
|
let sym = FileSymbol {
|
||||||
name: decl_name.text(),
|
name: decl_name.text(),
|
||||||
node_range: decl_name.syntax().range(),
|
node_range: decl_name.syntax().range(),
|
||||||
kind: MODULE,
|
kind: MODULE,
|
||||||
};
|
};
|
||||||
Some((file_id, sym))
|
Ok(vec![(file_id, sym)])
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
|
pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
|
||||||
let module_tree = self.module_tree(file_id)?;
|
let module_tree = self.module_tree(file_id)?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue