From cd878658d3072ee0741cd04c16d330e7d5907f94 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 4 Nov 2018 20:07:25 +0300 Subject: [PATCH 1/6] Introduce modules_from_source fn --- crates/ra_analysis/src/descriptors/module/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index e22489fc105..4e871d16da5 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -25,15 +25,19 @@ pub(crate) struct ModuleTree { } impl ModuleTree { - pub(crate) fn modules_for_file(&self, file_id: FileId) -> Vec { + pub(crate) fn modules_for_source(&self, source: ModuleSource) -> Vec { self.mods .iter() .enumerate() - .filter(|(_idx, it)| it.source.is_file(file_id)) + .filter(|(_idx, it)| it.source == source) .map(|(idx, _)| ModuleId(idx as u32)) .collect() } + pub(crate) fn modules_for_file(&self, file_id: FileId) -> Vec { + self.modules_for_source(ModuleSource::File(file_id)) + } + pub(crate) fn any_module_for_file(&self, file_id: FileId) -> Option { self.modules_for_file(file_id).pop() } @@ -178,10 +182,6 @@ impl ModuleSource { } } } - - fn is_file(self, file_id: FileId) -> bool { - self.as_file() == Some(file_id) - } } #[derive(Hash, Debug, PartialEq, Eq)] From 88a15d10d543c09ef66a9f105c3dcdb5011abbee Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 4 Nov 2018 20:21:20 +0300 Subject: [PATCH 2/6] use module_for_source --- crates/ra_analysis/src/completion.rs | 4 ++-- crates/ra_analysis/src/descriptors/module/mod.rs | 8 ++------ crates/ra_analysis/src/imp.rs | 8 ++++---- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/crates/ra_analysis/src/completion.rs b/crates/ra_analysis/src/completion.rs index 6667c06e7d9..766df1d962e 100644 --- a/crates/ra_analysis/src/completion.rs +++ b/crates/ra_analysis/src/completion.rs @@ -11,7 +11,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; use crate::{ db::{self, SyntaxDatabase}, descriptors::function::FnScopes, - descriptors::module::{ModuleId, ModuleScope, ModuleTree}, + descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource}, descriptors::DescriptorDatabase, input::FilesDatabase, Cancelable, FileId, @@ -35,7 +35,7 @@ pub(crate) fn resolve_based_completion( let source_root_id = db.file_source_root(file_id); let file = db.file_syntax(file_id); let module_tree = db.module_tree(source_root_id)?; - let module_id = match module_tree.any_module_for_file(file_id) { + let module_id = match module_tree.any_module_for_source(ModuleSource::File(file_id)) { None => return Ok(None), Some(it) => it, }; diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 4e871d16da5..13bab0087f9 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -34,12 +34,8 @@ impl ModuleTree { .collect() } - pub(crate) fn modules_for_file(&self, file_id: FileId) -> Vec { - self.modules_for_source(ModuleSource::File(file_id)) - } - - pub(crate) fn any_module_for_file(&self, file_id: FileId) -> Option { - self.modules_for_file(file_id).pop() + pub(crate) fn any_module_for_source(&self, source: ModuleSource) -> Option { + self.modules_for_source(source).pop() } } diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 4f337d1631c..823ac9bdd81 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -224,7 +224,7 @@ impl AnalysisImpl { let module_tree = self.module_tree(file_id)?; let res = module_tree - .modules_for_file(file_id) + .modules_for_source(ModuleSource::File(file_id)) .into_iter() .filter_map(|module_id| { let link = module_id.parent_link(&module_tree)?; @@ -252,7 +252,7 @@ impl AnalysisImpl { let module_tree = self.module_tree(file_id)?; let crate_graph = self.db.crate_graph(); let res = module_tree - .modules_for_file(file_id) + .modules_for_source(ModuleSource::File(file_id)) .into_iter() .map(|it| it.root(&module_tree)) .filter_map(|it| it.source(&module_tree).as_file()) @@ -376,7 +376,7 @@ impl AnalysisImpl { fix: None, }) .collect::>(); - if let Some(m) = module_tree.any_module_for_file(file_id) { + if let Some(m) = module_tree.any_module_for_source(ModuleSource::File(file_id)) { for (name_node, problem) in m.problems(&module_tree, &*self.db) { let diag = match problem { Problem::UnresolvedModule { candidate } => { @@ -539,7 +539,7 @@ impl AnalysisImpl { Some(name) => name.text(), None => return Vec::new(), }; - let module_id = match module_tree.any_module_for_file(file_id) { + let module_id = match module_tree.any_module_for_source(ModuleSource::File(file_id)) { Some(id) => id, None => return Vec::new(), }; From e0b21b98996b8296942c23864c711b2c1078178a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 4 Nov 2018 20:38:50 +0300 Subject: [PATCH 3/6] submodules works with module sources --- crates/ra_analysis/src/descriptors/mod.rs | 4 +-- .../ra_analysis/src/descriptors/module/imp.rs | 29 ++++++++++++------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/crates/ra_analysis/src/descriptors/mod.rs b/crates/ra_analysis/src/descriptors/mod.rs index eaeef54c1e6..775949a88a8 100644 --- a/crates/ra_analysis/src/descriptors/mod.rs +++ b/crates/ra_analysis/src/descriptors/mod.rs @@ -11,7 +11,7 @@ use ra_syntax::{ use crate::{ db::SyntaxDatabase, descriptors::function::{resolve_local_name, FnId, FnScopes}, - descriptors::module::{ModuleId, ModuleScope, ModuleTree}, + descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource}, input::SourceRootId, syntax_ptr::LocalSyntaxPtr, Cancelable, FileId, @@ -23,7 +23,7 @@ salsa::query_group! { type ModuleTreeQuery; use fn module::imp::module_tree; } - fn submodules(file_id: FileId) -> Cancelable>> { + fn submodules(source: ModuleSource) -> Cancelable>> { type SubmodulesQuery; use fn module::imp::submodules; } diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs index 3a010ecf54e..b9cd8173941 100644 --- a/crates/ra_analysis/src/descriptors/module/imp.rs +++ b/crates/ra_analysis/src/descriptors/module/imp.rs @@ -19,14 +19,25 @@ use super::{ ModuleTree, Problem, }; +#[derive(Clone, Hash, PartialEq, Eq, Debug)] +pub(crate) struct Submodule { + name: SmolStr +} + pub(crate) fn submodules( db: &impl DescriptorDatabase, - file_id: FileId, -) -> Cancelable>> { + source: ModuleSource, +) -> Cancelable>> { db::check_canceled(db)?; + let file_id = match source { + ModuleSource::File(it) => it, + _ => unimplemented!(), + }; let file = db.file_syntax(file_id); let root = file.ast(); - let submodules = modules(root).map(|(name, _)| name).collect(); + let submodules = modules(root) + .map(|(name, _)| Submodule { name }) + .collect(); Ok(Arc::new(submodules)) } @@ -66,11 +77,6 @@ pub(crate) fn module_tree( Ok(Arc::new(res)) } -#[derive(Clone, Hash, PartialEq, Eq, Debug)] -pub struct Submodule { - pub name: SmolStr, -} - fn create_module_tree<'a>( db: &impl DescriptorDatabase, source_root: SourceRootId, @@ -118,10 +124,11 @@ fn build_subtree( parent, children: Vec::new(), }); - for name in db.submodules(file_id)?.iter() { - let (points_to, problem) = resolve_submodule(file_id, name, &source_root.file_resolver); + for sub in db.submodules(ModuleSource::File(file_id))?.iter() { + let name = sub.name.clone(); + let (points_to, problem) = resolve_submodule(file_id, &name, &source_root.file_resolver); let link = tree.push_link(LinkData { - name: name.clone(), + name, owner: id, points_to: Vec::new(), problem: None, From 17a88928f49f31b9b076ef66d57354f45032be56 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 5 Nov 2018 13:08:52 +0300 Subject: [PATCH 4/6] collect all submodules --- crates/ra_analysis/src/descriptors/mod.rs | 4 +- .../ra_analysis/src/descriptors/module/imp.rs | 46 +++++++++++-------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/crates/ra_analysis/src/descriptors/mod.rs b/crates/ra_analysis/src/descriptors/mod.rs index 775949a88a8..56bde38492c 100644 --- a/crates/ra_analysis/src/descriptors/mod.rs +++ b/crates/ra_analysis/src/descriptors/mod.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use ra_syntax::{ ast::{self, AstNode, FnDefNode}, - SmolStr, TextRange, + TextRange, }; use crate::{ @@ -14,7 +14,7 @@ use crate::{ descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource}, input::SourceRootId, syntax_ptr::LocalSyntaxPtr, - Cancelable, FileId, + Cancelable, }; salsa::query_group! { diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs index b9cd8173941..d67ffa9de21 100644 --- a/crates/ra_analysis/src/descriptors/module/imp.rs +++ b/crates/ra_analysis/src/descriptors/module/imp.rs @@ -21,7 +21,7 @@ use super::{ #[derive(Clone, Hash, PartialEq, Eq, Debug)] pub(crate) struct Submodule { - name: SmolStr + name: SmolStr, } pub(crate) fn submodules( @@ -29,26 +29,36 @@ pub(crate) fn submodules( source: ModuleSource, ) -> Cancelable>> { db::check_canceled(db)?; - let file_id = match source { - ModuleSource::File(it) => it, - _ => unimplemented!(), + let submodules = match source.resolve(db) { + ModuleSourceNode::Root(it) => collect_submodules(it.ast()), + ModuleSourceNode::Inline(it) => it + .ast() + .item_list() + .map(collect_submodules) + .unwrap_or_else(Vec::new), }; - let file = db.file_syntax(file_id); - let root = file.ast(); - let submodules = modules(root) - .map(|(name, _)| Submodule { name }) - .collect(); - Ok(Arc::new(submodules)) + return Ok(Arc::new(submodules)); + + fn collect_submodules<'a>(root: impl ast::ModuleItemOwner<'a>) -> Vec { + modules(root) + .filter(|(_, m)| m.has_semi()) + .map(|(name, _)| Submodule { name }) + .collect() + } } -pub(crate) fn modules(root: ast::Root<'_>) -> impl Iterator)> { - root.modules().filter_map(|module| { - let name = module.name()?.text(); - if !module.has_semi() { - return None; - } - Some((name, module)) - }) +pub(crate) fn modules<'a>( + root: impl ast::ModuleItemOwner<'a>, +) -> impl Iterator)> { + root.items() + .filter_map(|item| match item { + ast::ModuleItem::Module(m) => Some(m), + _ => None, + }) + .filter_map(|module| { + let name = module.name()?.text(); + Some((name, module)) + }) } pub(crate) fn module_scope( From 44d891938493cc32efd2e44d81bc76cc3bc391c0 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 5 Nov 2018 13:23:37 +0300 Subject: [PATCH 5/6] Submodule is enum --- .../ra_analysis/src/descriptors/module/imp.rs | 77 ++++++++++++++----- .../ra_analysis/src/descriptors/module/mod.rs | 7 ++ crates/ra_analysis/src/syntax_ptr.rs | 4 + 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs index d67ffa9de21..257a323edf1 100644 --- a/crates/ra_analysis/src/descriptors/module/imp.rs +++ b/crates/ra_analysis/src/descriptors/module/imp.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use ra_syntax::{ - ast::{self, ModuleItemOwner, NameOwner}, + ast::{self, ModuleItemOwner, NameOwner, AstNode}, SmolStr, }; use relative_path::RelativePathBuf; @@ -12,6 +12,7 @@ use crate::{ descriptors::DescriptorDatabase, input::{SourceRoot, SourceRootId}, Cancelable, FileId, FileResolverImp, + syntax_ptr::SyntaxPtr, }; use super::{ @@ -20,8 +21,18 @@ use super::{ }; #[derive(Clone, Hash, PartialEq, Eq, Debug)] -pub(crate) struct Submodule { - name: SmolStr, +pub(crate) enum Submodule { + Declaration(SmolStr), + Definition(SmolStr, SyntaxPtr), +} + +impl Submodule { + fn name(&self) -> &SmolStr { + match self { + Submodule::Declaration(name) => name, + Submodule::Definition(name, _) => name, + } + } } pub(crate) fn submodules( @@ -29,20 +40,29 @@ pub(crate) fn submodules( source: ModuleSource, ) -> Cancelable>> { db::check_canceled(db)?; + let file_id = source.file_id(); let submodules = match source.resolve(db) { - ModuleSourceNode::Root(it) => collect_submodules(it.ast()), + ModuleSourceNode::Root(it) => collect_submodules(file_id, it.ast()), ModuleSourceNode::Inline(it) => it .ast() .item_list() - .map(collect_submodules) + .map(|it| collect_submodules(file_id, it)) .unwrap_or_else(Vec::new), }; return Ok(Arc::new(submodules)); - fn collect_submodules<'a>(root: impl ast::ModuleItemOwner<'a>) -> Vec { + fn collect_submodules<'a>( + file_id: FileId, + root: impl ast::ModuleItemOwner<'a>, + ) -> Vec { modules(root) - .filter(|(_, m)| m.has_semi()) - .map(|(name, _)| Submodule { name }) + .map(|(name, m)| { + if m.has_semi() { + Submodule::Declaration(name) + } else { + Submodule::Definition(name, SyntaxPtr::new(file_id, m.syntax())) + } + }) .collect() } } @@ -135,25 +155,40 @@ fn build_subtree( children: Vec::new(), }); for sub in db.submodules(ModuleSource::File(file_id))?.iter() { - let name = sub.name.clone(); - let (points_to, problem) = resolve_submodule(file_id, &name, &source_root.file_resolver); let link = tree.push_link(LinkData { - name, + name: sub.name().clone(), owner: id, points_to: Vec::new(), problem: None, }); - let points_to = points_to - .into_iter() - .map(|file_id| match roots.remove(&file_id) { - Some(module_id) => { - tree.module_mut(module_id).parent = Some(link); - Ok(module_id) - } - None => build_subtree(db, source_root, tree, visited, roots, Some(link), file_id), - }) - .collect::>>()?; + let (points_to, problem) = match sub { + Submodule::Declaration(name) => { + let (points_to, problem) = + resolve_submodule(file_id, &name, &source_root.file_resolver); + let points_to = points_to + .into_iter() + .map(|file_id| match roots.remove(&file_id) { + Some(module_id) => { + tree.module_mut(module_id).parent = Some(link); + Ok(module_id) + } + None => build_subtree( + db, + source_root, + tree, + visited, + roots, + Some(link), + file_id, + ), + }) + .collect::>>()?; + (points_to, problem) + } + Submodule::Definition(..) => continue, + }; + tree.link_mut(link).points_to = points_to; tree.link_mut(link).problem = problem; } diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 13bab0087f9..8464b0618a0 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -164,6 +164,13 @@ impl ModuleSource { } } + fn file_id(self) -> FileId { + match self { + ModuleSource::File(f) => f, + ModuleSource::Inline(ptr) => ptr.file_id(), + } + } + fn resolve(self, db: &impl SyntaxDatabase) -> ModuleSourceNode { match self { ModuleSource::File(file_id) => { diff --git a/crates/ra_analysis/src/syntax_ptr.rs b/crates/ra_analysis/src/syntax_ptr.rs index 4db1529c2c4..4afb1fc9303 100644 --- a/crates/ra_analysis/src/syntax_ptr.rs +++ b/crates/ra_analysis/src/syntax_ptr.rs @@ -22,6 +22,10 @@ impl SyntaxPtr { let local = LocalSyntaxPtr::new(node); SyntaxPtr { file_id, local } } + + pub(crate) fn file_id(self) -> FileId { + self.file_id + } } /// A pionter to a syntax node inside a file. From 6bbcfca7aec6408cf27415ae6f965adc472d6f18 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 5 Nov 2018 14:10:20 +0300 Subject: [PATCH 6/6] Fully add inline modules to module tree --- .../ra_analysis/src/descriptors/module/imp.rs | 49 +++++++++++++------ .../ra_analysis/src/descriptors/module/mod.rs | 12 +++-- crates/ra_analysis/src/imp.rs | 27 +++++----- crates/ra_analysis/src/lib.rs | 8 ++- crates/ra_analysis/tests/tests.rs | 23 ++++++++- .../ra_lsp_server/src/main_loop/handlers.rs | 8 +-- crates/ra_lsp_server/src/req.rs | 2 +- editors/code/src/commands/on_enter.ts | 6 +-- editors/code/src/commands/parent_module.ts | 11 +++-- 9 files changed, 99 insertions(+), 47 deletions(-) diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs index 257a323edf1..b3b1f1f2166 100644 --- a/crates/ra_analysis/src/descriptors/module/imp.rs +++ b/crates/ra_analysis/src/descriptors/module/imp.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use ra_syntax::{ - ast::{self, ModuleItemOwner, NameOwner, AstNode}, + ast::{self, ModuleItemOwner, NameOwner}, SmolStr, }; use relative_path::RelativePathBuf; @@ -12,7 +12,6 @@ use crate::{ descriptors::DescriptorDatabase, input::{SourceRoot, SourceRootId}, Cancelable, FileId, FileResolverImp, - syntax_ptr::SyntaxPtr, }; use super::{ @@ -23,7 +22,7 @@ use super::{ #[derive(Clone, Hash, PartialEq, Eq, Debug)] pub(crate) enum Submodule { Declaration(SmolStr), - Definition(SmolStr, SyntaxPtr), + Definition(SmolStr, ModuleSource), } impl Submodule { @@ -60,7 +59,8 @@ pub(crate) fn submodules( if m.has_semi() { Submodule::Declaration(name) } else { - Submodule::Definition(name, SyntaxPtr::new(file_id, m.syntax())) + let src = ModuleSource::new_inline(file_id, m); + Submodule::Definition(name, src) } }) .collect() @@ -121,7 +121,8 @@ fn create_module_tree<'a>( let source_root = db.source_root(source_root); for &file_id in source_root.files.iter() { - if visited.contains(&file_id) { + let source = ModuleSource::File(file_id); + if visited.contains(&source) { continue; // TODO: use explicit crate_roots here } assert!(!roots.contains_key(&file_id)); @@ -132,7 +133,7 @@ fn create_module_tree<'a>( &mut visited, &mut roots, None, - file_id, + source, )?; roots.insert(file_id, module_id); } @@ -143,18 +144,18 @@ fn build_subtree( db: &impl DescriptorDatabase, source_root: &SourceRoot, tree: &mut ModuleTree, - visited: &mut FxHashSet, + visited: &mut FxHashSet, roots: &mut FxHashMap, parent: Option, - file_id: FileId, + source: ModuleSource, ) -> Cancelable { - visited.insert(file_id); + visited.insert(source); let id = tree.push_mod(ModuleData { - source: ModuleSource::File(file_id), + source, parent, children: Vec::new(), }); - for sub in db.submodules(ModuleSource::File(file_id))?.iter() { + for sub in db.submodules(source)?.iter() { let link = tree.push_link(LinkData { name: sub.name().clone(), owner: id, @@ -165,7 +166,7 @@ fn build_subtree( let (points_to, problem) = match sub { Submodule::Declaration(name) => { let (points_to, problem) = - resolve_submodule(file_id, &name, &source_root.file_resolver); + resolve_submodule(source, &name, &source_root.file_resolver); let points_to = points_to .into_iter() .map(|file_id| match roots.remove(&file_id) { @@ -180,13 +181,24 @@ fn build_subtree( visited, roots, Some(link), - file_id, + ModuleSource::File(file_id), ), }) .collect::>>()?; (points_to, problem) } - Submodule::Definition(..) => continue, + Submodule::Definition(_name, submodule_source) => { + let points_to = build_subtree( + db, + source_root, + tree, + visited, + roots, + Some(link), + *submodule_source, + )?; + (vec![points_to], None) + } }; tree.link_mut(link).points_to = points_to; @@ -196,10 +208,17 @@ fn build_subtree( } fn resolve_submodule( - file_id: FileId, + source: ModuleSource, name: &SmolStr, file_resolver: &FileResolverImp, ) -> (Vec, Option) { + let file_id = match source { + ModuleSource::File(it) => it, + ModuleSource::Inline(..) => { + // TODO + return (Vec::new(), None); + } + }; let mod_name = file_resolver.file_stem(file_id); let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main"; diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 8464b0618a0..3d799ba05d2 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -142,9 +142,7 @@ impl LinkId { .1; ast.into() } - ModuleSourceNode::Inline(..) => { - unimplemented!("https://github.com/rust-analyzer/rust-analyzer/issues/181") - } + ModuleSourceNode::Inline(it) => it, } } } @@ -157,6 +155,12 @@ struct ModuleData { } impl ModuleSource { + pub(crate) fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource { + assert!(!module.has_semi()); + let ptr = SyntaxPtr::new(file_id, module.syntax()); + ModuleSource::Inline(ptr) + } + pub(crate) fn as_file(self) -> Option { match self { ModuleSource::File(f) => Some(f), @@ -164,7 +168,7 @@ impl ModuleSource { } } - fn file_id(self) -> FileId { + pub(crate) fn file_id(self) -> FileId { match self { ModuleSource::File(f) => f, ModuleSource::Inline(ptr) => ptr.file_id(), diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 823ac9bdd81..704648b595c 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -220,27 +220,32 @@ impl AnalysisImpl { let source_root = self.db.file_source_root(file_id); self.db.module_tree(source_root) } - pub fn parent_module(&self, file_id: FileId) -> Cancelable> { + pub fn parent_module( + &self, + file_id: FileId, + offset: TextUnit, + ) -> Cancelable> { let module_tree = self.module_tree(file_id)?; + let file = self.db.file_syntax(file_id); + let module_source = match find_node_at_offset::(file.syntax(), offset) { + Some(m) if !m.has_semi() => ModuleSource::new_inline(file_id, m), + _ => ModuleSource::File(file_id), + }; let res = module_tree - .modules_for_source(ModuleSource::File(file_id)) + .modules_for_source(module_source) .into_iter() .filter_map(|module_id| { let link = module_id.parent_link(&module_tree)?; - let file_id = match link.owner(&module_tree).source(&module_tree) { - ModuleSource::File(file_id) => file_id, - ModuleSource::Inline(..) => { - //TODO: https://github.com/rust-analyzer/rust-analyzer/issues/181 - return None; - } - }; + let file_id = link.owner(&module_tree).source(&module_tree).file_id(); let decl = link.bind_source(&module_tree, &*self.db); let decl = decl.ast(); + let decl_name = decl.name().unwrap(); + let sym = FileSymbol { - name: decl.name().unwrap().text(), - node_range: decl.syntax().range(), + name: decl_name.text(), + node_range: decl_name.syntax().range(), kind: MODULE, }; Some((file_id, sym)) diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 4e4c65f0847..fee382151ad 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs @@ -263,8 +263,12 @@ impl Analysis { ) -> Cancelable> { Ok(self.imp.find_all_refs(file_id, offset)) } - pub fn parent_module(&self, file_id: FileId) -> Cancelable> { - self.imp.parent_module(file_id) + pub fn parent_module( + &self, + file_id: FileId, + offset: TextUnit, + ) -> Cancelable> { + self.imp.parent_module(file_id, offset) } pub fn crate_for(&self, file_id: FileId) -> Cancelable> { self.imp.crate_for(file_id) diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs index c2754c8e484..7f7bb8e6bd9 100644 --- a/crates/ra_analysis/tests/tests.rs +++ b/crates/ra_analysis/tests/tests.rs @@ -92,9 +92,28 @@ fn test_resolve_parent_module() { <|>// empty ", ); - let symbols = analysis.parent_module(pos.file_id).unwrap(); + let symbols = analysis.parent_module(pos.file_id, pos.offset).unwrap(); assert_eq_dbg( - r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#, + r#"[(FileId(1), FileSymbol { name: "foo", node_range: [4; 7), kind: MODULE })]"#, + &symbols, + ); +} + +#[test] +fn test_resolve_parent_module_for_inline() { + let (analysis, pos) = analysis_and_position( + " + //- /lib.rs + mod foo { + mod bar { + mod baz { <|> } + } + } + ", + ); + let symbols = analysis.parent_module(pos.file_id, pos.offset).unwrap(); + assert_eq_dbg( + r#"[(FileId(1), FileSymbol { name: "bar", node_range: [18; 21), kind: MODULE })]"#, &symbols, ); } diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index c853ff65309..2219a003654 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -218,11 +218,13 @@ pub fn handle_goto_definition( pub fn handle_parent_module( world: ServerWorld, - params: TextDocumentIdentifier, + params: req::TextDocumentPositionParams, ) -> Result> { - let file_id = params.try_conv_with(&world)?; + let file_id = params.text_document.try_conv_with(&world)?; + let line_index = world.analysis().file_line_index(file_id); + let offset = params.position.conv_with(&line_index); let mut res = Vec::new(); - for (file_id, symbol) in world.analysis().parent_module(file_id)? { + for (file_id, symbol) in world.analysis().parent_module(file_id, offset)? { let line_index = world.analysis().file_line_index(file_id); let location = to_location(file_id, symbol.node_range, &world, &line_index)?; res.push(location); diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs index 9d911912d9a..fcb7e94e16a 100644 --- a/crates/ra_lsp_server/src/req.rs +++ b/crates/ra_lsp_server/src/req.rs @@ -93,7 +93,7 @@ pub struct Decoration { pub enum ParentModule {} impl Request for ParentModule { - type Params = TextDocumentIdentifier; + type Params = TextDocumentPositionParams; type Result = Vec; const METHOD: &'static str = "m/parentModule"; } diff --git a/editors/code/src/commands/on_enter.ts b/editors/code/src/commands/on_enter.ts index fe6aca63d97..64401b68401 100644 --- a/editors/code/src/commands/on_enter.ts +++ b/editors/code/src/commands/on_enter.ts @@ -6,10 +6,6 @@ import { SourceChange } from './apply_source_change'; -interface OnEnterParams { - textDocument: lc.TextDocumentIdentifier; - position: lc.Position; -} export async function handle(event: { text: string }): Promise { const editor = vscode.window.activeTextEditor; @@ -20,7 +16,7 @@ export async function handle(event: { text: string }): Promise { ) { return false; } - const request: OnEnterParams = { + const request: lc.TextDocumentPositionParams = { textDocument: { uri: editor.document.uri.toString() }, position: Server.client.code2ProtocolConverter.asPosition( editor.selection.active diff --git a/editors/code/src/commands/parent_module.ts b/editors/code/src/commands/parent_module.ts index 4bb92eb96a7..806c3d34c12 100644 --- a/editors/code/src/commands/parent_module.ts +++ b/editors/code/src/commands/parent_module.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode'; -import { Location, TextDocumentIdentifier } from 'vscode-languageclient'; +import * as lc from 'vscode-languageclient'; import { Server } from '../server'; export async function handle() { @@ -8,10 +8,13 @@ export async function handle() { if (editor == null || editor.document.languageId !== 'rust') { return; } - const request: TextDocumentIdentifier = { - uri: editor.document.uri.toString() + const request: lc.TextDocumentPositionParams = { + textDocument: { uri: editor.document.uri.toString() }, + position: Server.client.code2ProtocolConverter.asPosition( + editor.selection.active + ) }; - const response = await Server.client.sendRequest( + const response = await Server.client.sendRequest( 'm/parentModule', request );