From 4e683d7af1d752f2d7bc6e2ed4d6b85405bc84a8 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 14:52:10 +0300 Subject: [PATCH 01/11] Add ModId --- crates/ra_analysis/src/loc2id.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/crates/ra_analysis/src/loc2id.rs b/crates/ra_analysis/src/loc2id.rs index 8eaa249971..53bf609fa3 100644 --- a/crates/ra_analysis/src/loc2id.rs +++ b/crates/ra_analysis/src/loc2id.rs @@ -72,17 +72,26 @@ pub(crate) trait NumericId: Clone + Eq + Hash { fn to_u32(self) -> u32; } +macro_rules! impl_numeric_id { + ($id:ident) => { + impl NumericId for $id { + fn from_u32(id: u32) -> Self { + $id(id) + } + fn to_u32(self) -> u32 { + self.0 + } + } + }; +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct FnId(u32); +impl_numeric_id!(FnId); -impl NumericId for FnId { - fn from_u32(id: u32) -> FnId { - FnId(id) - } - fn to_u32(self) -> u32 { - self.0 - } -} +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct ModId(u32); +impl_numeric_id!(ModId); pub(crate) trait IdDatabase: salsa::Database { fn id_maps(&self) -> &IdMaps; From 099da13f531c84a7c69fbf5eed6a658bf64b531b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 14:58:01 +0300 Subject: [PATCH 02/11] Make some queries private Convention: we prefix private queries with `_` until salsa support real visibility. --- crates/ra_analysis/src/db.rs | 4 ++-- .../ra_analysis/src/descriptors/function/imp.rs | 2 +- crates/ra_analysis/src/descriptors/mod.rs | 17 +++++++++-------- .../ra_analysis/src/descriptors/module/imp.rs | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index d78b6afb94..8133b78753 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs @@ -85,10 +85,10 @@ salsa::database_storage! { } impl DescriptorDatabase { fn module_tree() for ModuleTreeQuery; - fn module_descriptor() for SubmodulesQuery; fn module_scope() for ModuleScopeQuery; - fn fn_syntax() for FnSyntaxQuery; fn fn_scopes() for FnScopesQuery; + fn _fn_syntax() for FnSyntaxQuery; + fn _submodules() for SubmodulesQuery; } } } diff --git a/crates/ra_analysis/src/descriptors/function/imp.rs b/crates/ra_analysis/src/descriptors/function/imp.rs index a7257acf9a..e09deba0f3 100644 --- a/crates/ra_analysis/src/descriptors/function/imp.rs +++ b/crates/ra_analysis/src/descriptors/function/imp.rs @@ -15,7 +15,7 @@ pub(crate) fn fn_syntax(db: &impl DescriptorDatabase, fn_id: FnId) -> FnDefNode } pub(crate) fn fn_scopes(db: &impl DescriptorDatabase, fn_id: FnId) -> Arc { - let syntax = db.fn_syntax(fn_id); + let syntax = db._fn_syntax(fn_id); let res = FnScopes::new(syntax.borrowed()); Arc::new(res) } diff --git a/crates/ra_analysis/src/descriptors/mod.rs b/crates/ra_analysis/src/descriptors/mod.rs index d602c4e04e..f47ac49c5a 100644 --- a/crates/ra_analysis/src/descriptors/mod.rs +++ b/crates/ra_analysis/src/descriptors/mod.rs @@ -24,23 +24,24 @@ salsa::query_group! { type ModuleTreeQuery; use fn module::imp::module_tree; } - fn submodules(source: ModuleSource) -> Cancelable>> { - type SubmodulesQuery; - use fn module::imp::submodules; - } fn module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable> { type ModuleScopeQuery; use fn module::imp::module_scope; } - fn fn_syntax(fn_id: FnId) -> FnDefNode { + fn fn_scopes(fn_id: FnId) -> Arc { + type FnScopesQuery; + use fn function::imp::fn_scopes; + } + + fn _fn_syntax(fn_id: FnId) -> FnDefNode { type FnSyntaxQuery; // Don't retain syntax trees in memory storage volatile; use fn function::imp::fn_syntax; } - fn fn_scopes(fn_id: FnId) -> Arc { - type FnScopesQuery; - use fn function::imp::fn_scopes; + 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 ade96ddc09..ec0885938e 100644 --- a/crates/ra_analysis/src/descriptors/module/imp.rs +++ b/crates/ra_analysis/src/descriptors/module/imp.rs @@ -155,7 +155,7 @@ fn build_subtree( parent, children: Vec::new(), }); - for sub in db.submodules(source)?.iter() { + for sub in db._submodules(source)?.iter() { let link = tree.push_link(LinkData { name: sub.name().clone(), owner: id, From 3b8d0c215a922eaea182d4d72f232a534de21e33 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 16:21:02 +0300 Subject: [PATCH 03/11] Use more OO API for parent module --- .../ra_analysis/src/descriptors/module/mod.rs | 79 ++++++++++++++++++- crates/ra_analysis/src/imp.rs | 44 ++++------- 2 files changed, 94 insertions(+), 29 deletions(-) diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 055a56b54d..d62826ee30 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, diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 812fed32d9..c0bed04bfa 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -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> { - 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::(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> { let module_tree = self.module_tree(file_id)?; From d475e3b29f1783682b2ac78459e38668bb9f8c14 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 16:24:47 +0300 Subject: [PATCH 04/11] Make LikdId private --- crates/ra_analysis/src/descriptors/module/mod.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index d62826ee30..8a75e11be4 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -142,7 +142,7 @@ impl crate::loc2id::NumericId for ModuleId { } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub(crate) struct LinkId(u32); +struct LinkId(u32); #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub enum Problem { @@ -159,7 +159,7 @@ impl ModuleId { pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource { tree.module(self).source } - pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option { + fn parent_link(self, tree: &ModuleTree) -> Option { tree.module(self).parent } pub(crate) fn parent(self, tree: &ModuleTree) -> Option { @@ -207,17 +207,13 @@ impl ModuleId { } impl LinkId { - pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId { + fn owner(self, tree: &ModuleTree) -> ModuleId { tree.link(self).owner } - pub(crate) fn name(self, tree: &ModuleTree) -> SmolStr { + fn name(self, tree: &ModuleTree) -> SmolStr { tree.link(self).name.clone() } - pub(crate) fn bind_source<'a>( - self, - tree: &ModuleTree, - db: &impl SyntaxDatabase, - ) -> ast::ModuleNode { + fn bind_source<'a>(self, tree: &ModuleTree, db: &impl SyntaxDatabase) -> ast::ModuleNode { let owner = self.owner(tree); match owner.source(tree).resolve(db) { ModuleSourceNode::SourceFile(root) => { From 0ab3c65d9819765016c926df4aca634b5be8344c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 16:40:15 +0300 Subject: [PATCH 05/11] Use OO API in crate_for --- .../ra_analysis/src/descriptors/module/mod.rs | 37 ++++++++++++++++++- crates/ra_analysis/src/imp.rs | 25 ++++++++----- 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 8a75e11be4..16faea94e9 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use ra_editor::find_node_at_offset; use ra_syntax::{ + algo::generate, ast::{self, AstNode, NameOwner}, SmolStr, SyntaxNode, SyntaxNodeRef, }; @@ -27,6 +28,16 @@ pub(crate) struct ModuleDescriptor { } impl ModuleDescriptor { + /// Lookup `ModuleDescriptor` by `FileId`. Note that this is inherently + /// lossy transformation: in general, a single source might correspond to + /// several modules. + pub fn guess_from_file_id( + db: &impl DescriptorDatabase, + file_id: FileId, + ) -> Cancelable> { + ModuleDescriptor::guess_from_source(db, file_id, ModuleSource::SourceFile(file_id)) + } + /// 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. @@ -34,14 +45,23 @@ impl ModuleDescriptor { 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), }; + ModuleDescriptor::guess_from_source(db, position.file_id, module_source) + } + + fn guess_from_source( + db: &impl DescriptorDatabase, + file_id: FileId, + module_source: ModuleSource, + ) -> Cancelable> { + let source_root = db.file_source_root(file_id); + let module_tree = db.module_tree(source_root)?; + let res = match module_tree.any_module_for_source(module_source) { None => None, Some(module_id) => Some(ModuleDescriptor { @@ -64,6 +84,11 @@ impl ModuleDescriptor { Some((file_id, src)) } + pub fn source(&self) -> ModuleSource { + self.module_id.source(&self.tree) + } + + /// Parent module. Returns `None` if this is a root module. pub fn parent(&self) -> Option { let parent_id = self.module_id.parent(&self.tree)?; Some(ModuleDescriptor { @@ -71,6 +96,14 @@ impl ModuleDescriptor { module_id: parent_id, }) } + + /// The root of the tree this module is part of + pub fn crate_root(&self) -> ModuleDescriptor { + generate(Some(self.clone()), |it| it.parent()) + .last() + .unwrap() + } + /// `name` is `None` for the crate's root module pub fn name(&self) -> Option { let link = self.module_id.parent_link(&self.tree)?; diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index c0bed04bfa..49b8637564 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -220,6 +220,8 @@ impl AnalysisImpl { let source_root = self.db.file_source_root(file_id); self.db.module_tree(source_root) } + /// This return `Vec`: a module may be inclucded from several places. + /// We don't handle this case yet though, so the Vec has length at most one. pub fn parent_module(&self, position: FilePosition) -> Cancelable> { let descr = match ModuleDescriptor::guess_from_position(&*self.db, position)? { None => return Ok(Vec::new()), @@ -238,18 +240,21 @@ impl AnalysisImpl { }; Ok(vec![(file_id, sym)]) } + /// Returns `Vec` for the same reason as `parent_module` pub fn crate_for(&self, file_id: FileId) -> Cancelable> { - let module_tree = self.module_tree(file_id)?; - let crate_graph = self.db.crate_graph(); - let res = module_tree - .modules_for_source(ModuleSource::SourceFile(file_id)) - .into_iter() - .map(|it| it.root(&module_tree)) - .filter_map(|it| it.source(&module_tree).as_file()) - .filter_map(|it| crate_graph.crate_id_for_crate_root(it)) - .collect(); + let descr = match ModuleDescriptor::guess_from_file_id(&*self.db, file_id)? { + None => return Ok(Vec::new()), + Some(it) => it, + }; + let root = descr.crate_root(); + let file_id = root + .source() + .as_file() + .expect("root module always has a file as a source"); - Ok(res) + let crate_graph = self.db.crate_graph(); + let crate_id = crate_graph.crate_id_for_crate_root(file_id); + Ok(crate_id.into_iter().collect()) } pub fn crate_root(&self, crate_id: CrateId) -> FileId { self.db.crate_graph().crate_roots[&crate_id] From 21508cfb2f5452c6f19ab0e615a6c61cb28154c8 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 16:55:35 +0300 Subject: [PATCH 06/11] Use OO API instead of resolve_module --- .../ra_analysis/src/descriptors/module/mod.rs | 13 +---- crates/ra_analysis/src/imp.rs | 58 ++++++------------- 2 files changed, 19 insertions(+), 52 deletions(-) diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 16faea94e9..d0560244a1 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -165,15 +165,6 @@ enum ModuleSourceNode { #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] pub(crate) struct ModuleId(u32); -impl crate::loc2id::NumericId for ModuleId { - fn from_u32(id: u32) -> Self { - ModuleId(id) - } - fn to_u32(self) -> u32 { - self.0 - } -} - #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] struct LinkId(u32); @@ -189,13 +180,13 @@ pub enum Problem { } impl ModuleId { - pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource { + fn source(self, tree: &ModuleTree) -> ModuleSource { tree.module(self).source } fn parent_link(self, tree: &ModuleTree) -> Option { tree.module(self).parent } - pub(crate) fn parent(self, tree: &ModuleTree) -> Option { + fn parent(self, tree: &ModuleTree) -> Option { let link = self.parent_link(tree)?; Some(tree.link(link).owner) } diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 49b8637564..1bbf0cb6da 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -266,7 +266,6 @@ impl AnalysisImpl { &self, position: FilePosition, ) -> Cancelable> { - let module_tree = self.module_tree(position.file_id)?; let file = self.db.file_syntax(position.file_id); let syntax = file.syntax(); if let Some(name_ref) = find_node_at_offset::(syntax, position.offset) { @@ -292,25 +291,23 @@ impl AnalysisImpl { if let Some(name) = find_node_at_offset::(syntax, position.offset) { if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { if module.has_semi() { - let file_ids = self.resolve_module(&*module_tree, position.file_id, module); - - let res = file_ids - .into_iter() - .map(|id| { - let name = module - .name() - .map(|n| n.text()) - .unwrap_or_else(|| SmolStr::new("")); - let symbol = FileSymbol { - name, - node_range: TextRange::offset_len(0.into(), 0.into()), - kind: MODULE, - }; - (id, symbol) - }) - .collect(); - - return Ok(res); + let parent_module = + ModuleDescriptor::guess_from_file_id(&*self.db, position.file_id)?; + let child_name = module.name(); + match (parent_module, child_name) { + (Some(parent_module), Some(child_name)) => { + if let Some(child) = parent_module.child(&child_name.text()) { + let file_id = child.source().file_id(); + let symbol = FileSymbol { + name: child_name.text(), + node_range: TextRange::offset_len(0.into(), 0.into()), + kind: MODULE, + }; + return Ok(vec![(file_id, symbol)]); + } + } + _ => (), + } } } } @@ -519,27 +516,6 @@ impl AnalysisImpl { query.limit(4); self.world_symbols(query) } - - fn resolve_module( - &self, - module_tree: &ModuleTree, - file_id: FileId, - module: ast::Module, - ) -> Vec { - let name = match module.name() { - Some(name) => name.text(), - None => return Vec::new(), - }; - let module_id = match module_tree.any_module_for_source(ModuleSource::SourceFile(file_id)) { - Some(id) => id, - None => return Vec::new(), - }; - module_id - .child(module_tree, name.as_str()) - .and_then(|it| it.source(&module_tree).as_file()) - .into_iter() - .collect() - } } impl SourceChange { From 0dd26a2f5b7dab38ee0813e314e2bde269dd5883 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 17:08:40 +0300 Subject: [PATCH 07/11] Use OO module API in completion --- crates/ra_analysis/src/completion/mod.rs | 25 +++-------- .../src/completion/reference_completion.rs | 31 +++++-------- .../ra_analysis/src/descriptors/module/mod.rs | 43 +++++++------------ 3 files changed, 31 insertions(+), 68 deletions(-) diff --git a/crates/ra_analysis/src/completion/mod.rs b/crates/ra_analysis/src/completion/mod.rs index 2e082705ea..5e3ee79dd8 100644 --- a/crates/ra_analysis/src/completion/mod.rs +++ b/crates/ra_analysis/src/completion/mod.rs @@ -2,7 +2,6 @@ mod reference_completion; use ra_editor::find_node_at_offset; use ra_syntax::{ - algo::find_leaf_at_offset, algo::visit::{visitor_ctx, VisitorCtx}, ast, AstNode, AtomEdit, @@ -12,8 +11,9 @@ use rustc_hash::{FxHashMap}; use crate::{ db::{self, SyntaxDatabase}, - descriptors::{DescriptorDatabase, module::ModuleSource}, - input::{FilesDatabase}, + descriptors::{ + module::{ModuleDescriptor} + }, Cancelable, FilePosition }; @@ -38,14 +38,7 @@ pub(crate) fn completions( original_file.reparse(&edit) }; - let leaf = match find_leaf_at_offset(original_file.syntax(), position.offset).left_biased() { - None => return Ok(None), - Some(it) => it, - }; - let source_root_id = db.file_source_root(position.file_id); - let module_tree = db.module_tree(source_root_id)?; - let module_source = ModuleSource::for_node(position.file_id, leaf); - let module_id = match module_tree.any_module_for_source(module_source) { + let module = match ModuleDescriptor::guess_from_position(db, position)? { None => return Ok(None), Some(it) => it, }; @@ -55,15 +48,7 @@ pub(crate) fn completions( // First, let's try to complete a reference to some declaration. if let Some(name_ref) = find_node_at_offset::(file.syntax(), position.offset) { has_completions = true; - reference_completion::completions( - &mut res, - db, - source_root_id, - &module_tree, - module_id, - &file, - name_ref, - )?; + reference_completion::completions(&mut res, db, &module, &file, name_ref)?; // special case, `trait T { fn foo(i_am_a_name_ref) {} }` if is_node::(name_ref.syntax()) { param_completions(name_ref.syntax(), &mut res); diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs index 6c5fd0be6c..c94d9af75a 100644 --- a/crates/ra_analysis/src/completion/reference_completion.rs +++ b/crates/ra_analysis/src/completion/reference_completion.rs @@ -9,20 +9,16 @@ use ra_syntax::{ use crate::{ db::RootDatabase, - input::{SourceRootId}, completion::CompletionItem, - descriptors::module::{ModuleId, ModuleTree}, + descriptors::module::{ModuleDescriptor}, descriptors::function::FnScopes, - descriptors::DescriptorDatabase, Cancelable }; pub(super) fn completions( acc: &mut Vec, db: &RootDatabase, - source_root_id: SourceRootId, - module_tree: &ModuleTree, - module_id: ModuleId, + module: &ModuleDescriptor, file: &SourceFileNode, name_ref: ast::NameRef, ) -> Cancelable<()> { @@ -40,7 +36,7 @@ pub(super) fn completions( complete_expr_snippets(acc); } - let module_scope = db.module_scope(source_root_id, module_id)?; + let module_scope = module.scope(db)?; acc.extend( module_scope .entries() @@ -56,9 +52,7 @@ pub(super) fn completions( }), ); } - NameRefKind::CratePath(path) => { - complete_path(acc, db, source_root_id, module_tree, module_id, path)? - } + NameRefKind::CratePath(path) => complete_path(acc, db, module, path)?, NameRefKind::BareIdentInMod => { let name_range = name_ref.syntax().range(); let top_node = name_ref @@ -171,16 +165,14 @@ fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec, db: &RootDatabase, - source_root_id: SourceRootId, - module_tree: &ModuleTree, - module_id: ModuleId, + module: &ModuleDescriptor, crate_path: Vec, ) -> Cancelable<()> { - let target_module_id = match find_target_module(module_tree, module_id, crate_path) { + let target_module = match find_target_module(module, crate_path) { None => return Ok(()), Some(it) => it, }; - let module_scope = db.module_scope(source_root_id, target_module_id)?; + let module_scope = target_module.scope(db)?; let completions = module_scope.entries().iter().map(|entry| CompletionItem { label: entry.name().to_string(), lookup: None, @@ -191,14 +183,13 @@ fn complete_path( } fn find_target_module( - module_tree: &ModuleTree, - module_id: ModuleId, + module: &ModuleDescriptor, mut crate_path: Vec, -) -> Option { +) -> Option { crate_path.pop(); - let mut target_module = module_id.root(&module_tree); + let mut target_module = module.crate_root(); for name in crate_path { - target_module = target_module.child(module_tree, name.text().as_str())?; + target_module = target_module.child(name.text().as_str())?; } Some(target_module) } diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index d0560244a1..a894025eda 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -15,6 +15,7 @@ use relative_path::RelativePathBuf; use crate::{ db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId, FilePosition, Cancelable, descriptors::DescriptorDatabase, + input::SourceRootId }; pub(crate) use self::scope::ModuleScope; @@ -24,6 +25,7 @@ pub(crate) use self::scope::ModuleScope; #[derive(Debug, Clone)] pub(crate) struct ModuleDescriptor { tree: Arc, + source_root_id: SourceRootId, module_id: ModuleId, } @@ -59,13 +61,14 @@ impl ModuleDescriptor { file_id: FileId, module_source: ModuleSource, ) -> Cancelable> { - let source_root = db.file_source_root(file_id); - let module_tree = db.module_tree(source_root)?; + let source_root_id = db.file_source_root(file_id); + let module_tree = db.module_tree(source_root_id)?; let res = match module_tree.any_module_for_source(module_source) { None => None, Some(module_id) => Some(ModuleDescriptor { tree: module_tree, + source_root_id, module_id, }), }; @@ -92,8 +95,8 @@ impl ModuleDescriptor { 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, + ..self.clone() }) } @@ -109,13 +112,20 @@ impl ModuleDescriptor { let link = self.module_id.parent_link(&self.tree)?; Some(link.name(&self.tree)) } + + /// Finds a child module with the specified name. 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, + ..self.clone() }) } + + /// Returns a `ModuleScope`: a set of items, visible in this module. + pub fn scope(&self, db: &impl DescriptorDatabase) -> Cancelable> { + db.module_scope(self.source_root_id, self.module_id) + } } /// Phisically, rust source is organized as a set of files, but logically it is @@ -190,20 +200,7 @@ impl ModuleId { let link = self.parent_link(tree)?; Some(tree.link(link).owner) } - pub(crate) fn root(self, tree: &ModuleTree) -> ModuleId { - let mut curr = self; - let mut i = 0; - while let Some(next) = curr.parent(tree) { - curr = next; - i += 1; - // simplistic cycle detection - if i > 100 { - return self; - } - } - curr - } - pub(crate) fn child(self, tree: &ModuleTree, name: &str) -> Option { + fn child(self, tree: &ModuleTree, name: &str) -> Option { let link = tree .module(self) .children @@ -260,16 +257,6 @@ struct ModuleData { } impl ModuleSource { - pub(crate) fn for_node(file_id: FileId, node: SyntaxNodeRef) -> ModuleSource { - for node in node.ancestors() { - if let Some(m) = ast::Module::cast(node) { - if !m.has_semi() { - return ModuleSource::new_inline(file_id, m); - } - } - } - ModuleSource::SourceFile(file_id) - } pub(crate) fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource { assert!(!module.has_semi()); let ptr = SyntaxPtr::new(file_id, module.syntax()); From a300fb68e25ea0cbf2cfba38968a40674cd4c805 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 17:16:33 +0300 Subject: [PATCH 08/11] Make most of modules impl private --- crates/ra_analysis/src/descriptors/mod.rs | 16 ++++++++-------- crates/ra_analysis/src/descriptors/module/imp.rs | 2 +- crates/ra_analysis/src/descriptors/module/mod.rs | 12 ++++++++---- crates/ra_analysis/src/imp.rs | 11 +++-------- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/crates/ra_analysis/src/descriptors/mod.rs b/crates/ra_analysis/src/descriptors/mod.rs index f47ac49c5a..a8489f89c6 100644 --- a/crates/ra_analysis/src/descriptors/mod.rs +++ b/crates/ra_analysis/src/descriptors/mod.rs @@ -20,19 +20,19 @@ use crate::{ salsa::query_group! { pub(crate) trait DescriptorDatabase: SyntaxDatabase + IdDatabase { - fn module_tree(source_root_id: SourceRootId) -> Cancelable> { - type ModuleTreeQuery; - use fn module::imp::module_tree; - } - fn module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable> { - type ModuleScopeQuery; - use fn module::imp::module_scope; - } fn fn_scopes(fn_id: FnId) -> Arc { type FnScopesQuery; use fn function::imp::fn_scopes; } + fn _module_tree(source_root_id: SourceRootId) -> Cancelable> { + type ModuleTreeQuery; + use fn module::imp::module_tree; + } + fn _module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable> { + type ModuleScopeQuery; + use fn module::imp::module_scope; + } fn _fn_syntax(fn_id: FnId) -> FnDefNode { type FnSyntaxQuery; // Don't retain syntax trees in memory diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs index ec0885938e..defe87216c 100644 --- a/crates/ra_analysis/src/descriptors/module/imp.rs +++ b/crates/ra_analysis/src/descriptors/module/imp.rs @@ -86,7 +86,7 @@ pub(crate) fn module_scope( source_root_id: SourceRootId, module_id: ModuleId, ) -> Cancelable> { - let tree = db.module_tree(source_root_id)?; + let tree = db._module_tree(source_root_id)?; let source = module_id.source(&tree).resolve(db); let res = match source { ModuleSourceNode::SourceFile(it) => ModuleScope::new(it.borrowed().items()), diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index a894025eda..ff7afe16e9 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -8,7 +8,7 @@ use ra_editor::find_node_at_offset; use ra_syntax::{ algo::generate, ast::{self, AstNode, NameOwner}, - SmolStr, SyntaxNode, SyntaxNodeRef, + SmolStr, SyntaxNode, }; use relative_path::RelativePathBuf; @@ -62,7 +62,7 @@ impl ModuleDescriptor { module_source: ModuleSource, ) -> Cancelable> { let source_root_id = db.file_source_root(file_id); - let module_tree = db.module_tree(source_root_id)?; + let module_tree = db._module_tree(source_root_id)?; let res = match module_tree.any_module_for_source(module_source) { None => None, @@ -124,7 +124,11 @@ impl ModuleDescriptor { /// Returns a `ModuleScope`: a set of items, visible in this module. pub fn scope(&self, db: &impl DescriptorDatabase) -> Cancelable> { - db.module_scope(self.source_root_id, self.module_id) + db._module_scope(self.source_root_id, self.module_id) + } + + pub fn problems(&self, db: &impl DescriptorDatabase) -> Vec<(SyntaxNode, Problem)> { + self.module_id.problems(&self.tree, db) } } @@ -209,7 +213,7 @@ impl ModuleId { .find(|it| it.name == name)?; Some(*link.points_to.first()?) } - pub(crate) fn problems( + fn problems( self, tree: &ModuleTree, db: &impl SyntaxDatabase, diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 1bbf0cb6da..61296215c8 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -21,7 +21,7 @@ use crate::{ db::{self, FileSyntaxQuery, SyntaxDatabase}, descriptors::{ function::{FnDescriptor, FnId}, - module::{ModuleDescriptor, ModuleSource, ModuleTree, Problem}, + module::{ModuleDescriptor, Problem}, DeclarationDescriptor, DescriptorDatabase, }, input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, @@ -216,10 +216,6 @@ impl AnalysisImpl { .sweep(salsa::SweepStrategy::default().discard_values()); Ok(query.search(&buf)) } - fn module_tree(&self, file_id: FileId) -> Cancelable> { - let source_root = self.db.file_source_root(file_id); - self.db.module_tree(source_root) - } /// This return `Vec`: a module may be inclucded from several places. /// We don't handle this case yet though, so the Vec has length at most one. pub fn parent_module(&self, position: FilePosition) -> Cancelable> { @@ -354,7 +350,6 @@ impl AnalysisImpl { } pub fn diagnostics(&self, file_id: FileId) -> Cancelable> { - let module_tree = self.module_tree(file_id)?; let syntax = self.db.file_syntax(file_id); let mut res = ra_editor::diagnostics(&syntax) @@ -365,8 +360,8 @@ impl AnalysisImpl { fix: None, }) .collect::>(); - if let Some(m) = module_tree.any_module_for_source(ModuleSource::SourceFile(file_id)) { - for (name_node, problem) in m.problems(&module_tree, &*self.db) { + if let Some(m) = ModuleDescriptor::guess_from_file_id(&*self.db, file_id)? { + for (name_node, problem) in m.problems(&*self.db) { let diag = match problem { Problem::UnresolvedModule { candidate } => { let create_file = FileSystemEdit::CreateFile { From 1913bedc2ec51c5ac44c6b72dd8e84b05026c694 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 17:18:52 +0300 Subject: [PATCH 09/11] Make more stuff private --- crates/ra_analysis/src/descriptors/module/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index ff7afe16e9..aab792e288 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -146,7 +146,7 @@ pub(crate) struct ModuleTree { } impl ModuleTree { - pub(crate) fn modules_for_source(&self, source: ModuleSource) -> Vec { + fn modules_for_source(&self, source: ModuleSource) -> Vec { self.mods .iter() .enumerate() @@ -155,7 +155,7 @@ impl ModuleTree { .collect() } - pub(crate) fn any_module_for_source(&self, source: ModuleSource) -> Option { + fn any_module_for_source(&self, source: ModuleSource) -> Option { self.modules_for_source(source).pop() } } @@ -261,7 +261,7 @@ struct ModuleData { } impl ModuleSource { - pub(crate) fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource { + fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource { assert!(!module.has_semi()); let ptr = SyntaxPtr::new(file_id, module.syntax()); ModuleSource::Module(ptr) From 8fc51501e06661e0a096ac6363ccb82d604c933a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 17:23:17 +0300 Subject: [PATCH 10/11] Remove ModId --- crates/ra_analysis/src/descriptors/module/mod.rs | 6 +----- crates/ra_analysis/src/loc2id.rs | 4 ---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index aab792e288..047454cffe 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -213,11 +213,7 @@ impl ModuleId { .find(|it| it.name == name)?; Some(*link.points_to.first()?) } - fn problems( - self, - tree: &ModuleTree, - db: &impl SyntaxDatabase, - ) -> Vec<(SyntaxNode, Problem)> { + fn problems(self, tree: &ModuleTree, db: &impl SyntaxDatabase) -> Vec<(SyntaxNode, Problem)> { tree.module(self) .children .iter() diff --git a/crates/ra_analysis/src/loc2id.rs b/crates/ra_analysis/src/loc2id.rs index 53bf609fa3..8c297156a6 100644 --- a/crates/ra_analysis/src/loc2id.rs +++ b/crates/ra_analysis/src/loc2id.rs @@ -89,10 +89,6 @@ macro_rules! impl_numeric_id { pub(crate) struct FnId(u32); impl_numeric_id!(FnId); -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct ModId(u32); -impl_numeric_id!(ModId); - pub(crate) trait IdDatabase: salsa::Database { fn id_maps(&self) -> &IdMaps; } From a2fdb41ace4de7737a3ba0e4ef5e68d0a41e924d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 17:33:27 +0300 Subject: [PATCH 11/11] fix typo --- crates/ra_analysis/src/imp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 61296215c8..e1493bdaa0 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -216,8 +216,8 @@ impl AnalysisImpl { .sweep(salsa::SweepStrategy::default().discard_values()); Ok(query.search(&buf)) } - /// This return `Vec`: a module may be inclucded from several places. - /// We don't handle this case yet though, so the Vec has length at most one. + /// This return `Vec`: a module may be included from several places. We + /// don't handle this case yet though, so the Vec has length at most one. pub fn parent_module(&self, position: FilePosition) -> Cancelable> { let descr = match ModuleDescriptor::guess_from_position(&*self.db, position)? { None => return Ok(Vec::new()),