mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Merge #234
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:
commit
713c3ea30b
9 changed files with 233 additions and 203 deletions
|
@ -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::<ast::NameRef>(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::<ast::Param>(name_ref.syntax()) {
|
||||
param_completions(name_ref.syntax(), &mut res);
|
||||
|
|
|
@ -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<CompletionItem>,
|
||||
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<Completi
|
|||
fn complete_path(
|
||||
acc: &mut Vec<CompletionItem>,
|
||||
db: &RootDatabase,
|
||||
source_root_id: SourceRootId,
|
||||
module_tree: &ModuleTree,
|
||||
module_id: ModuleId,
|
||||
module: &ModuleDescriptor,
|
||||
crate_path: Vec<ast::NameRef>,
|
||||
) -> 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<ast::NameRef>,
|
||||
) -> Option<ModuleId> {
|
||||
) -> Option<ModuleDescriptor> {
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
let syntax = db.fn_syntax(fn_id);
|
||||
let syntax = db._fn_syntax(fn_id);
|
||||
let res = FnScopes::new(syntax.borrowed());
|
||||
Arc::new(res)
|
||||
}
|
||||
|
|
|
@ -20,27 +20,28 @@ use crate::{
|
|||
|
||||
salsa::query_group! {
|
||||
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;
|
||||
use fn module::imp::module_tree;
|
||||
}
|
||||
fn submodules(source: ModuleSource) -> Cancelable<Arc<Vec<module::imp::Submodule>>> {
|
||||
type SubmodulesQuery;
|
||||
use fn module::imp::submodules;
|
||||
}
|
||||
fn module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleScope>> {
|
||||
fn _module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleScope>> {
|
||||
type ModuleScopeQuery;
|
||||
use fn module::imp::module_scope;
|
||||
}
|
||||
fn fn_syntax(fn_id: FnId) -> FnDefNode {
|
||||
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<FnScopes> {
|
||||
type FnScopesQuery;
|
||||
use fn function::imp::fn_scopes;
|
||||
fn _submodules(source: ModuleSource) -> Cancelable<Arc<Vec<module::imp::Submodule>>> {
|
||||
type SubmodulesQuery;
|
||||
use fn module::imp::submodules;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ pub(crate) fn module_scope(
|
|||
source_root_id: SourceRootId,
|
||||
module_id: ModuleId,
|
||||
) -> 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 res = match source {
|
||||
ModuleSourceNode::SourceFile(it) => ModuleScope::new(it.borrowed().items()),
|
||||
|
@ -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,
|
||||
|
|
|
@ -1,16 +1,137 @@
|
|||
pub(super) mod imp;
|
||||
pub(crate) mod scope;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
/// `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
|
||||
/// organized as a tree of modules. Usually, a single file corresponds to a
|
||||
/// single module, but it is not nessary the case.
|
||||
|
@ -25,7 +146,7 @@ pub(crate) struct 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
|
||||
.iter()
|
||||
.enumerate()
|
||||
|
@ -34,7 +155,7 @@ impl ModuleTree {
|
|||
.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()
|
||||
}
|
||||
}
|
||||
|
@ -58,17 +179,8 @@ 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)]
|
||||
pub(crate) struct LinkId(u32);
|
||||
struct LinkId(u32);
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub enum Problem {
|
||||
|
@ -82,30 +194,17 @@ pub enum Problem {
|
|||
}
|
||||
|
||||
impl ModuleId {
|
||||
pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource {
|
||||
fn source(self, tree: &ModuleTree) -> ModuleSource {
|
||||
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
|
||||
}
|
||||
pub(crate) fn parent(self, tree: &ModuleTree) -> Option<ModuleId> {
|
||||
fn parent(self, tree: &ModuleTree) -> Option<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<ModuleId> {
|
||||
fn child(self, tree: &ModuleTree, name: &str) -> Option<ModuleId> {
|
||||
let link = tree
|
||||
.module(self)
|
||||
.children
|
||||
|
@ -114,11 +213,7 @@ impl ModuleId {
|
|||
.find(|it| it.name == name)?;
|
||||
Some(*link.points_to.first()?)
|
||||
}
|
||||
pub(crate) 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()
|
||||
|
@ -133,14 +228,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 bind_source<'a>(
|
||||
self,
|
||||
tree: &ModuleTree,
|
||||
db: &impl SyntaxDatabase,
|
||||
) -> ast::ModuleNode {
|
||||
fn name(self, tree: &ModuleTree) -> SmolStr {
|
||||
tree.link(self).name.clone()
|
||||
}
|
||||
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) => {
|
||||
|
@ -163,17 +257,7 @@ 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 {
|
||||
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)
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::{
|
|||
db::{self, FileSyntaxQuery, SyntaxDatabase},
|
||||
descriptors::{
|
||||
function::{FnDescriptor, FnId},
|
||||
module::{ModuleSource, ModuleTree, Problem},
|
||||
module::{ModuleDescriptor, Problem},
|
||||
DeclarationDescriptor, DescriptorDatabase,
|
||||
},
|
||||
input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE},
|
||||
|
@ -216,52 +216,41 @@ impl AnalysisImpl {
|
|||
.sweep(salsa::SweepStrategy::default().discard_values());
|
||||
Ok(query.search(&buf))
|
||||
}
|
||||
fn module_tree(&self, file_id: FileId) -> Cancelable<Arc<ModuleTree>> {
|
||||
let source_root = self.db.file_source_root(file_id);
|
||||
self.db.module_tree(source_root)
|
||||
}
|
||||
/// 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<Vec<(FileId, FileSymbol)>> {
|
||||
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::<ast::Module>(file.syntax(), position.offset)
|
||||
{
|
||||
Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m),
|
||||
_ => ModuleSource::SourceFile(position.file_id),
|
||||
let 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)])
|
||||
}
|
||||
/// Returns `Vec` for the same reason as `parent_module`
|
||||
pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
|
||||
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]
|
||||
|
@ -273,7 +262,6 @@ impl AnalysisImpl {
|
|||
&self,
|
||||
position: FilePosition,
|
||||
) -> Cancelable<Vec<(FileId, FileSymbol)>> {
|
||||
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::<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(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)]);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -364,7 +350,6 @@ impl AnalysisImpl {
|
|||
}
|
||||
|
||||
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 mut res = ra_editor::diagnostics(&syntax)
|
||||
|
@ -375,8 +360,8 @@ impl AnalysisImpl {
|
|||
fix: None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
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 {
|
||||
|
@ -526,27 +511,6 @@ impl AnalysisImpl {
|
|||
query.limit(4);
|
||||
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 {
|
||||
|
|
|
@ -72,17 +72,22 @@ 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 NumericId for FnId {
|
||||
fn from_u32(id: u32) -> FnId {
|
||||
FnId(id)
|
||||
}
|
||||
fn to_u32(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
impl_numeric_id!(FnId);
|
||||
|
||||
pub(crate) trait IdDatabase: salsa::Database {
|
||||
fn id_maps(&self) -> &IdMaps;
|
||||
|
|
Loading…
Reference in a new issue