From 3b8d0c215a922eaea182d4d72f232a534de21e33 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 16:21:02 +0300 Subject: Use more OO API for parent module --- crates/ra_analysis/src/descriptors/module/mod.rs | 79 +++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) (limited to 'crates/ra_analysis/src/descriptors') diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 055a56b54..d62826ee3 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -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, + 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> { + 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::(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 { + 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 { + let link = self.module_id.parent_link(&self.tree)?; + Some(link.name(&self.tree)) + } + pub fn child(&self, name: &str) -> Option { + 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, -- cgit v1.2.3