234: Global module r=matklad a=matklad

This series of commits re-introdces `ModuleDescriptor` as one stop shop for all information about a module.

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2018-11-20 14:33:54 +00:00
commit 713c3ea30b
9 changed files with 233 additions and 203 deletions

View file

@ -2,7 +2,6 @@ mod reference_completion;
use ra_editor::find_node_at_offset; use ra_editor::find_node_at_offset;
use ra_syntax::{ use ra_syntax::{
algo::find_leaf_at_offset,
algo::visit::{visitor_ctx, VisitorCtx}, algo::visit::{visitor_ctx, VisitorCtx},
ast, ast,
AstNode, AtomEdit, AstNode, AtomEdit,
@ -12,8 +11,9 @@ use rustc_hash::{FxHashMap};
use crate::{ use crate::{
db::{self, SyntaxDatabase}, db::{self, SyntaxDatabase},
descriptors::{DescriptorDatabase, module::ModuleSource}, descriptors::{
input::{FilesDatabase}, module::{ModuleDescriptor}
},
Cancelable, FilePosition Cancelable, FilePosition
}; };
@ -38,14 +38,7 @@ pub(crate) fn completions(
original_file.reparse(&edit) original_file.reparse(&edit)
}; };
let leaf = match find_leaf_at_offset(original_file.syntax(), position.offset).left_biased() { let module = match ModuleDescriptor::guess_from_position(db, position)? {
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) {
None => return Ok(None), None => return Ok(None),
Some(it) => it, Some(it) => it,
}; };
@ -55,15 +48,7 @@ pub(crate) fn completions(
// First, let's try to complete a reference to some declaration. // First, let's try to complete a reference to some declaration.
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) { if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
has_completions = true; has_completions = true;
reference_completion::completions( reference_completion::completions(&mut res, db, &module, &file, name_ref)?;
&mut res,
db,
source_root_id,
&module_tree,
module_id,
&file,
name_ref,
)?;
// special case, `trait T { fn foo(i_am_a_name_ref) {} }` // special case, `trait T { fn foo(i_am_a_name_ref) {} }`
if is_node::<ast::Param>(name_ref.syntax()) { if is_node::<ast::Param>(name_ref.syntax()) {
param_completions(name_ref.syntax(), &mut res); param_completions(name_ref.syntax(), &mut res);

View file

@ -9,20 +9,16 @@ use ra_syntax::{
use crate::{ use crate::{
db::RootDatabase, db::RootDatabase,
input::{SourceRootId},
completion::CompletionItem, completion::CompletionItem,
descriptors::module::{ModuleId, ModuleTree}, descriptors::module::{ModuleDescriptor},
descriptors::function::FnScopes, descriptors::function::FnScopes,
descriptors::DescriptorDatabase,
Cancelable Cancelable
}; };
pub(super) fn completions( pub(super) fn completions(
acc: &mut Vec<CompletionItem>, acc: &mut Vec<CompletionItem>,
db: &RootDatabase, db: &RootDatabase,
source_root_id: SourceRootId, module: &ModuleDescriptor,
module_tree: &ModuleTree,
module_id: ModuleId,
file: &SourceFileNode, file: &SourceFileNode,
name_ref: ast::NameRef, name_ref: ast::NameRef,
) -> Cancelable<()> { ) -> Cancelable<()> {
@ -40,7 +36,7 @@ pub(super) fn completions(
complete_expr_snippets(acc); complete_expr_snippets(acc);
} }
let module_scope = db.module_scope(source_root_id, module_id)?; let module_scope = module.scope(db)?;
acc.extend( acc.extend(
module_scope module_scope
.entries() .entries()
@ -56,9 +52,7 @@ pub(super) fn completions(
}), }),
); );
} }
NameRefKind::CratePath(path) => { NameRefKind::CratePath(path) => complete_path(acc, db, module, path)?,
complete_path(acc, db, source_root_id, module_tree, module_id, path)?
}
NameRefKind::BareIdentInMod => { NameRefKind::BareIdentInMod => {
let name_range = name_ref.syntax().range(); let name_range = name_ref.syntax().range();
let top_node = name_ref let top_node = name_ref
@ -171,16 +165,14 @@ fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<Completi
fn complete_path( fn complete_path(
acc: &mut Vec<CompletionItem>, acc: &mut Vec<CompletionItem>,
db: &RootDatabase, db: &RootDatabase,
source_root_id: SourceRootId, module: &ModuleDescriptor,
module_tree: &ModuleTree,
module_id: ModuleId,
crate_path: Vec<ast::NameRef>, crate_path: Vec<ast::NameRef>,
) -> Cancelable<()> { ) -> 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(()), None => return Ok(()),
Some(it) => it, 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 { let completions = module_scope.entries().iter().map(|entry| CompletionItem {
label: entry.name().to_string(), label: entry.name().to_string(),
lookup: None, lookup: None,
@ -191,14 +183,13 @@ fn complete_path(
} }
fn find_target_module( fn find_target_module(
module_tree: &ModuleTree, module: &ModuleDescriptor,
module_id: ModuleId,
mut crate_path: Vec<ast::NameRef>, mut crate_path: Vec<ast::NameRef>,
) -> Option<ModuleId> { ) -> Option<ModuleDescriptor> {
crate_path.pop(); crate_path.pop();
let mut target_module = module_id.root(&module_tree); let mut target_module = module.crate_root();
for name in crate_path { 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) Some(target_module)
} }

View file

@ -85,10 +85,10 @@ salsa::database_storage! {
} }
impl DescriptorDatabase { impl DescriptorDatabase {
fn module_tree() for ModuleTreeQuery; fn module_tree() for ModuleTreeQuery;
fn module_descriptor() for SubmodulesQuery;
fn module_scope() for ModuleScopeQuery; fn module_scope() for ModuleScopeQuery;
fn fn_syntax() for FnSyntaxQuery;
fn fn_scopes() for FnScopesQuery; fn fn_scopes() for FnScopesQuery;
fn _fn_syntax() for FnSyntaxQuery;
fn _submodules() for SubmodulesQuery;
} }
} }
} }

View file

@ -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<FnScopes> { pub(crate) fn fn_scopes(db: &impl DescriptorDatabase, fn_id: FnId) -> Arc<FnScopes> {
let syntax = db.fn_syntax(fn_id); let syntax = db._fn_syntax(fn_id);
let res = FnScopes::new(syntax.borrowed()); let res = FnScopes::new(syntax.borrowed());
Arc::new(res) Arc::new(res)
} }

View file

@ -20,27 +20,28 @@ use crate::{
salsa::query_group! { salsa::query_group! {
pub(crate) trait DescriptorDatabase: SyntaxDatabase + IdDatabase { pub(crate) trait DescriptorDatabase: SyntaxDatabase + IdDatabase {
fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> { fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> {
type FnScopesQuery;
use fn function::imp::fn_scopes;
}
fn _module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> {
type ModuleTreeQuery; type ModuleTreeQuery;
use fn module::imp::module_tree; use fn module::imp::module_tree;
} }
fn submodules(source: ModuleSource) -> Cancelable<Arc<Vec<module::imp::Submodule>>> { fn _module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleScope>> {
type SubmodulesQuery;
use fn module::imp::submodules;
}
fn module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleScope>> {
type ModuleScopeQuery; type ModuleScopeQuery;
use fn module::imp::module_scope; use fn module::imp::module_scope;
} }
fn fn_syntax(fn_id: FnId) -> FnDefNode { fn _fn_syntax(fn_id: FnId) -> FnDefNode {
type FnSyntaxQuery; type FnSyntaxQuery;
// Don't retain syntax trees in memory // Don't retain syntax trees in memory
storage volatile; storage volatile;
use fn function::imp::fn_syntax; use fn function::imp::fn_syntax;
} }
fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> { fn _submodules(source: ModuleSource) -> Cancelable<Arc<Vec<module::imp::Submodule>>> {
type FnScopesQuery; type SubmodulesQuery;
use fn function::imp::fn_scopes; use fn module::imp::submodules;
} }
} }
} }

View file

@ -86,7 +86,7 @@ pub(crate) fn module_scope(
source_root_id: SourceRootId, source_root_id: SourceRootId,
module_id: ModuleId, module_id: ModuleId,
) -> Cancelable<Arc<ModuleScope>> { ) -> Cancelable<Arc<ModuleScope>> {
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 source = module_id.source(&tree).resolve(db);
let res = match source { let res = match source {
ModuleSourceNode::SourceFile(it) => ModuleScope::new(it.borrowed().items()), ModuleSourceNode::SourceFile(it) => ModuleScope::new(it.borrowed().items()),
@ -155,7 +155,7 @@ fn build_subtree(
parent, parent,
children: Vec::new(), children: Vec::new(),
}); });
for sub in db.submodules(source)?.iter() { for sub in db._submodules(source)?.iter() {
let link = tree.push_link(LinkData { let link = tree.push_link(LinkData {
name: sub.name().clone(), name: sub.name().clone(),
owner: id, owner: id,

View file

@ -1,16 +1,137 @@
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::{
algo::generate,
ast::{self, AstNode, NameOwner}, ast::{self, AstNode, NameOwner},
SmolStr, SyntaxNode, SyntaxNodeRef, SmolStr, SyntaxNode,
}; };
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,
input::SourceRootId
};
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>,
source_root_id: SourceRootId,
module_id: ModuleId,
}
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<Option<ModuleDescriptor>> {
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.
pub fn guess_from_position(
db: &impl DescriptorDatabase,
position: FilePosition,
) -> Cancelable<Option<ModuleDescriptor>> {
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),
};
ModuleDescriptor::guess_from_source(db, position.file_id, module_source)
}
fn guess_from_source(
db: &impl DescriptorDatabase,
file_id: FileId,
module_source: ModuleSource,
) -> Cancelable<Option<ModuleDescriptor>> {
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,
}),
};
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 source(&self) -> ModuleSource {
self.module_id.source(&self.tree)
}
/// Parent module. Returns `None` if this is a root module.
pub fn parent(&self) -> Option<ModuleDescriptor> {
let parent_id = self.module_id.parent(&self.tree)?;
Some(ModuleDescriptor {
module_id: parent_id,
..self.clone()
})
}
/// 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<SmolStr> {
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<ModuleDescriptor> {
let child_id = self.module_id.child(&self.tree, name)?;
Some(ModuleDescriptor {
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<Arc<ModuleScope>> {
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)
}
}
/// 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.
@ -25,7 +146,7 @@ pub(crate) struct ModuleTree {
} }
impl ModuleTree { impl ModuleTree {
pub(crate) fn modules_for_source(&self, source: ModuleSource) -> Vec<ModuleId> { fn modules_for_source(&self, source: ModuleSource) -> Vec<ModuleId> {
self.mods self.mods
.iter() .iter()
.enumerate() .enumerate()
@ -34,7 +155,7 @@ impl ModuleTree {
.collect() .collect()
} }
pub(crate) fn any_module_for_source(&self, source: ModuleSource) -> Option<ModuleId> { fn any_module_for_source(&self, source: ModuleSource) -> Option<ModuleId> {
self.modules_for_source(source).pop() self.modules_for_source(source).pop()
} }
} }
@ -58,17 +179,8 @@ enum ModuleSourceNode {
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub(crate) struct ModuleId(u32); 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)] #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub(crate) struct LinkId(u32); struct LinkId(u32);
#[derive(Clone, Debug, Hash, PartialEq, Eq)] #[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Problem { pub enum Problem {
@ -82,30 +194,17 @@ pub enum Problem {
} }
impl ModuleId { impl ModuleId {
pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource { fn source(self, tree: &ModuleTree) -> ModuleSource {
tree.module(self).source tree.module(self).source
} }
pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> {
tree.module(self).parent tree.module(self).parent
} }
pub(crate) fn parent(self, tree: &ModuleTree) -> Option<ModuleId> { fn parent(self, tree: &ModuleTree) -> Option<ModuleId> {
let link = self.parent_link(tree)?; let link = self.parent_link(tree)?;
Some(tree.link(link).owner) Some(tree.link(link).owner)
} }
pub(crate) fn root(self, tree: &ModuleTree) -> ModuleId { fn child(self, tree: &ModuleTree, name: &str) -> Option<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<ModuleId> {
let link = tree let link = tree
.module(self) .module(self)
.children .children
@ -114,11 +213,7 @@ impl ModuleId {
.find(|it| it.name == name)?; .find(|it| it.name == name)?;
Some(*link.points_to.first()?) Some(*link.points_to.first()?)
} }
pub(crate) fn problems( fn problems(self, tree: &ModuleTree, db: &impl SyntaxDatabase) -> Vec<(SyntaxNode, Problem)> {
self,
tree: &ModuleTree,
db: &impl SyntaxDatabase,
) -> Vec<(SyntaxNode, Problem)> {
tree.module(self) tree.module(self)
.children .children
.iter() .iter()
@ -133,14 +228,13 @@ impl ModuleId {
} }
impl LinkId { impl LinkId {
pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId { fn owner(self, tree: &ModuleTree) -> ModuleId {
tree.link(self).owner tree.link(self).owner
} }
pub(crate) fn bind_source<'a>( fn name(self, tree: &ModuleTree) -> SmolStr {
self, tree.link(self).name.clone()
tree: &ModuleTree, }
db: &impl SyntaxDatabase, fn bind_source<'a>(self, tree: &ModuleTree, db: &impl SyntaxDatabase) -> ast::ModuleNode {
) -> ast::ModuleNode {
let owner = self.owner(tree); let owner = self.owner(tree);
match owner.source(tree).resolve(db) { match owner.source(tree).resolve(db) {
ModuleSourceNode::SourceFile(root) => { ModuleSourceNode::SourceFile(root) => {
@ -163,17 +257,7 @@ struct ModuleData {
} }
impl ModuleSource { impl ModuleSource {
pub(crate) fn for_node(file_id: FileId, node: SyntaxNodeRef) -> ModuleSource { fn new_inline(file_id: FileId, module: ast::Module) -> 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()); assert!(!module.has_semi());
let ptr = SyntaxPtr::new(file_id, module.syntax()); let ptr = SyntaxPtr::new(file_id, module.syntax());
ModuleSource::Module(ptr) ModuleSource::Module(ptr)

View file

@ -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, Problem},
DeclarationDescriptor, DescriptorDatabase, DeclarationDescriptor, DescriptorDatabase,
}, },
input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE},
@ -216,52 +216,41 @@ impl AnalysisImpl {
.sweep(salsa::SweepStrategy::default().discard_values()); .sweep(salsa::SweepStrategy::default().discard_values());
Ok(query.search(&buf)) Ok(query.search(&buf))
} }
fn module_tree(&self, file_id: FileId) -> Cancelable<Arc<ModuleTree>> { /// This return `Vec`: a module may be included from several places. We
let source_root = self.db.file_source_root(file_id); /// don't handle this case yet though, so the Vec has length at most one.
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),
_ => ModuleSource::SourceFile(position.file_id),
}; };
let (file_id, decl) = match descr.parent_link_source(&*self.db) {
let res = module_tree None => return Ok(Vec::new()),
.modules_for_source(module_source) Some(it) => it,
.into_iter() };
.filter_map(|module_id| { let decl = decl.borrowed();
let link = module_id.parent_link(&module_tree)?; let decl_name = decl.name().unwrap();
let file_id = link.owner(&module_tree).source(&module_tree).file_id(); let sym = FileSymbol {
let decl = link.bind_source(&module_tree, &*self.db); name: decl_name.text(),
let decl = decl.borrowed(); node_range: decl_name.syntax().range(),
kind: MODULE,
let decl_name = decl.name().unwrap(); };
Ok(vec![(file_id, sym)])
let sym = FileSymbol {
name: decl_name.text(),
node_range: decl_name.syntax().range(),
kind: MODULE,
};
Some((file_id, sym))
})
.collect();
Ok(res)
} }
/// Returns `Vec` for the same reason as `parent_module`
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 descr = match ModuleDescriptor::guess_from_file_id(&*self.db, file_id)? {
let crate_graph = self.db.crate_graph(); None => return Ok(Vec::new()),
let res = module_tree Some(it) => it,
.modules_for_source(ModuleSource::SourceFile(file_id)) };
.into_iter() let root = descr.crate_root();
.map(|it| it.root(&module_tree)) let file_id = root
.filter_map(|it| it.source(&module_tree).as_file()) .source()
.filter_map(|it| crate_graph.crate_id_for_crate_root(it)) .as_file()
.collect(); .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 { pub fn crate_root(&self, crate_id: CrateId) -> FileId {
self.db.crate_graph().crate_roots[&crate_id] self.db.crate_graph().crate_roots[&crate_id]
@ -273,7 +262,6 @@ impl AnalysisImpl {
&self, &self,
position: FilePosition, position: FilePosition,
) -> Cancelable<Vec<(FileId, FileSymbol)>> { ) -> Cancelable<Vec<(FileId, FileSymbol)>> {
let module_tree = self.module_tree(position.file_id)?;
let file = self.db.file_syntax(position.file_id); let file = self.db.file_syntax(position.file_id);
let syntax = file.syntax(); let syntax = file.syntax();
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
@ -299,25 +287,23 @@ impl AnalysisImpl {
if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
if module.has_semi() { if module.has_semi() {
let file_ids = self.resolve_module(&*module_tree, position.file_id, module); let parent_module =
ModuleDescriptor::guess_from_file_id(&*self.db, position.file_id)?;
let res = file_ids let child_name = module.name();
.into_iter() match (parent_module, child_name) {
.map(|id| { (Some(parent_module), Some(child_name)) => {
let name = module if let Some(child) = parent_module.child(&child_name.text()) {
.name() let file_id = child.source().file_id();
.map(|n| n.text()) let symbol = FileSymbol {
.unwrap_or_else(|| SmolStr::new("")); name: child_name.text(),
let symbol = FileSymbol { node_range: TextRange::offset_len(0.into(), 0.into()),
name, kind: MODULE,
node_range: TextRange::offset_len(0.into(), 0.into()), };
kind: MODULE, return Ok(vec![(file_id, symbol)]);
}; }
(id, symbol) }
}) _ => (),
.collect(); }
return Ok(res);
} }
} }
} }
@ -364,7 +350,6 @@ impl AnalysisImpl {
} }
pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> {
let module_tree = self.module_tree(file_id)?;
let syntax = self.db.file_syntax(file_id); let syntax = self.db.file_syntax(file_id);
let mut res = ra_editor::diagnostics(&syntax) let mut res = ra_editor::diagnostics(&syntax)
@ -375,8 +360,8 @@ impl AnalysisImpl {
fix: None, fix: None,
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if let Some(m) = module_tree.any_module_for_source(ModuleSource::SourceFile(file_id)) { if let Some(m) = ModuleDescriptor::guess_from_file_id(&*self.db, file_id)? {
for (name_node, problem) in m.problems(&module_tree, &*self.db) { for (name_node, problem) in m.problems(&*self.db) {
let diag = match problem { let diag = match problem {
Problem::UnresolvedModule { candidate } => { Problem::UnresolvedModule { candidate } => {
let create_file = FileSystemEdit::CreateFile { let create_file = FileSystemEdit::CreateFile {
@ -526,27 +511,6 @@ impl AnalysisImpl {
query.limit(4); query.limit(4);
self.world_symbols(query) self.world_symbols(query)
} }
fn resolve_module(
&self,
module_tree: &ModuleTree,
file_id: FileId,
module: ast::Module,
) -> Vec<FileId> {
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 { impl SourceChange {

View file

@ -72,17 +72,22 @@ pub(crate) trait NumericId: Clone + Eq + Hash {
fn to_u32(self) -> u32; 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)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct FnId(u32); 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
}
}
pub(crate) trait IdDatabase: salsa::Database { pub(crate) trait IdDatabase: salsa::Database {
fn id_maps(&self) -> &IdMaps; fn id_maps(&self) -> &IdMaps;