mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Merge #246
246: Resolve path r=matklad a=matklad Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
9f08341aa4
7 changed files with 99 additions and 33 deletions
|
@ -38,10 +38,7 @@ pub(crate) fn completions(
|
||||||
original_file.reparse(&edit)
|
original_file.reparse(&edit)
|
||||||
};
|
};
|
||||||
|
|
||||||
let module = match ModuleDescriptor::guess_from_position(db, position)? {
|
let module = ctry!(ModuleDescriptor::guess_from_position(db, position)?);
|
||||||
None => return Ok(None),
|
|
||||||
Some(it) => it,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
let mut has_completions = false;
|
let mut has_completions = false;
|
||||||
|
|
|
@ -13,6 +13,7 @@ use crate::{
|
||||||
descriptors::{
|
descriptors::{
|
||||||
module::{ModuleDescriptor},
|
module::{ModuleDescriptor},
|
||||||
function::FnScopes,
|
function::FnScopes,
|
||||||
|
Def,
|
||||||
Path,
|
Path,
|
||||||
},
|
},
|
||||||
Cancelable
|
Cancelable
|
||||||
|
@ -42,8 +43,7 @@ pub(super) fn completions(
|
||||||
let module_scope = module.scope(db)?;
|
let module_scope = module.scope(db)?;
|
||||||
acc.extend(
|
acc.extend(
|
||||||
module_scope
|
module_scope
|
||||||
.items
|
.entries()
|
||||||
.iter()
|
|
||||||
.filter(|(_name, res)| {
|
.filter(|(_name, res)| {
|
||||||
// Don't expose this item
|
// Don't expose this item
|
||||||
match res.import {
|
match res.import {
|
||||||
|
@ -157,19 +157,20 @@ fn complete_path(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
path.segments.pop();
|
path.segments.pop();
|
||||||
let target_module = match module.resolve_path(path) {
|
let def_id = match module.resolve_path(db, path)? {
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
};
|
};
|
||||||
|
let target_module = match def_id.resolve(db)? {
|
||||||
|
Def::Module(it) => it,
|
||||||
|
Def::Item => return Ok(()),
|
||||||
|
};
|
||||||
let module_scope = target_module.scope(db)?;
|
let module_scope = target_module.scope(db)?;
|
||||||
let completions = module_scope
|
let completions = module_scope.entries().map(|(name, _res)| CompletionItem {
|
||||||
.items
|
label: name.to_string(),
|
||||||
.iter()
|
lookup: None,
|
||||||
.map(|(name, _res)| CompletionItem {
|
snippet: None,
|
||||||
label: name.to_string(),
|
});
|
||||||
lookup: None,
|
|
||||||
snippet: None,
|
|
||||||
});
|
|
||||||
acc.extend(completions);
|
acc.extend(completions);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,12 @@ use crate::{
|
||||||
FileId,
|
FileId,
|
||||||
db::SyntaxDatabase,
|
db::SyntaxDatabase,
|
||||||
descriptors::function::{resolve_local_name, FnId, FnScopes},
|
descriptors::function::{resolve_local_name, FnId, FnScopes},
|
||||||
descriptors::module::{ModuleId, ModuleTree, ModuleSource, nameres::{ItemMap, InputModuleItems, FileItems}},
|
descriptors::module::{
|
||||||
|
ModuleId, ModuleTree, ModuleSource, ModuleDescriptor,
|
||||||
|
nameres::{ItemMap, InputModuleItems, FileItems}
|
||||||
|
},
|
||||||
input::SourceRootId,
|
input::SourceRootId,
|
||||||
loc2id::IdDatabase,
|
loc2id::{IdDatabase, DefId, DefLoc},
|
||||||
syntax_ptr::LocalSyntaxPtr,
|
syntax_ptr::LocalSyntaxPtr,
|
||||||
Cancelable,
|
Cancelable,
|
||||||
};
|
};
|
||||||
|
@ -67,6 +70,25 @@ salsa::query_group! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) enum Def {
|
||||||
|
Module(ModuleDescriptor),
|
||||||
|
Item,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DefId {
|
||||||
|
pub(crate) fn resolve(self, db: &impl DescriptorDatabase) -> Cancelable<Def> {
|
||||||
|
let loc = db.id_maps().def_loc(self);
|
||||||
|
let res = match loc {
|
||||||
|
DefLoc::Module { id, source_root } => {
|
||||||
|
let descr = ModuleDescriptor::new(db, source_root, id)?;
|
||||||
|
Def::Module(descr)
|
||||||
|
}
|
||||||
|
DefLoc::Item { .. } => Def::Item,
|
||||||
|
};
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ReferenceDescriptor {
|
pub struct ReferenceDescriptor {
|
||||||
pub range: TextRange,
|
pub range: TextRange,
|
||||||
|
|
|
@ -17,6 +17,7 @@ use crate::{
|
||||||
descriptors::{Path, PathKind, DescriptorDatabase},
|
descriptors::{Path, PathKind, DescriptorDatabase},
|
||||||
input::SourceRootId,
|
input::SourceRootId,
|
||||||
arena::{Arena, Id},
|
arena::{Arena, Id},
|
||||||
|
loc2id::{DefLoc, DefId},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use self::nameres::ModuleScope;
|
pub(crate) use self::nameres::ModuleScope;
|
||||||
|
@ -76,6 +77,20 @@ impl ModuleDescriptor {
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn new(
|
||||||
|
db: &impl DescriptorDatabase,
|
||||||
|
source_root_id: SourceRootId,
|
||||||
|
module_id: ModuleId,
|
||||||
|
) -> Cancelable<ModuleDescriptor> {
|
||||||
|
let module_tree = db._module_tree(source_root_id)?;
|
||||||
|
let res = ModuleDescriptor {
|
||||||
|
tree: module_tree,
|
||||||
|
source_root_id,
|
||||||
|
module_id,
|
||||||
|
};
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `mod foo;` or `mod foo {}` node whihc declared this module.
|
/// Returns `mod foo;` or `mod foo {}` node whihc declared this module.
|
||||||
/// Returns `None` for the root module
|
/// Returns `None` for the root module
|
||||||
pub fn parent_link_source(
|
pub fn parent_link_source(
|
||||||
|
@ -117,6 +132,14 @@ impl ModuleDescriptor {
|
||||||
Some(link.name(&self.tree))
|
Some(link.name(&self.tree))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn def_id(&self, db: &impl DescriptorDatabase) -> DefId {
|
||||||
|
let def_loc = DefLoc::Module {
|
||||||
|
id: self.module_id,
|
||||||
|
source_root: self.source_root_id,
|
||||||
|
};
|
||||||
|
db.id_maps().def_id(def_loc)
|
||||||
|
}
|
||||||
|
|
||||||
/// Finds a child module with the specified name.
|
/// Finds a child module with the specified name.
|
||||||
pub fn child(&self, name: &str) -> Option<ModuleDescriptor> {
|
pub fn child(&self, name: &str) -> Option<ModuleDescriptor> {
|
||||||
let child_id = self.module_id.child(&self.tree, name)?;
|
let child_id = self.module_id.child(&self.tree, name)?;
|
||||||
|
@ -133,17 +156,28 @@ impl ModuleDescriptor {
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_path(&self, path: Path) -> Option<ModuleDescriptor> {
|
pub(crate) fn resolve_path(
|
||||||
|
&self,
|
||||||
|
db: &impl DescriptorDatabase,
|
||||||
|
path: Path,
|
||||||
|
) -> Cancelable<Option<DefId>> {
|
||||||
let mut curr = match path.kind {
|
let mut curr = match path.kind {
|
||||||
PathKind::Crate => self.crate_root(),
|
PathKind::Crate => self.crate_root(),
|
||||||
PathKind::Self_ | PathKind::Plain => self.clone(),
|
PathKind::Self_ | PathKind::Plain => self.clone(),
|
||||||
PathKind::Super => self.parent()?,
|
PathKind::Super => ctry!(self.parent()),
|
||||||
};
|
|
||||||
let segments = path.segments;
|
|
||||||
for name in segments {
|
|
||||||
curr = curr.child(&name)?;
|
|
||||||
}
|
}
|
||||||
Some(curr)
|
.def_id(db);
|
||||||
|
|
||||||
|
let segments = path.segments;
|
||||||
|
for name in segments.iter() {
|
||||||
|
let module = match db.id_maps().def_loc(curr) {
|
||||||
|
DefLoc::Module { id, source_root } => ModuleDescriptor::new(db, source_root, id)?,
|
||||||
|
_ => return Ok(None),
|
||||||
|
};
|
||||||
|
let scope = module.scope(db)?;
|
||||||
|
curr = ctry!(ctry!(scope.get(&name)).def_id);
|
||||||
|
}
|
||||||
|
Ok(Some(curr))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn problems(&self, db: &impl DescriptorDatabase) -> Vec<(SyntaxNode, Problem)> {
|
pub fn problems(&self, db: &impl DescriptorDatabase) -> Vec<(SyntaxNode, Problem)> {
|
||||||
|
|
|
@ -103,7 +103,16 @@ pub(crate) struct ItemMap {
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq, Eq, Clone)]
|
#[derive(Debug, Default, PartialEq, Eq, Clone)]
|
||||||
pub(crate) struct ModuleScope {
|
pub(crate) struct ModuleScope {
|
||||||
pub(crate) items: FxHashMap<SmolStr, Resolution>,
|
items: FxHashMap<SmolStr, Resolution>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleScope {
|
||||||
|
pub(crate) fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a SmolStr, &Resolution)> + 'a {
|
||||||
|
self.items.iter()
|
||||||
|
}
|
||||||
|
pub(crate) fn get(&self, name: &SmolStr) -> Option<&Resolution> {
|
||||||
|
self.items.get(name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A set of items and imports declared inside a module, without relation to
|
/// A set of items and imports declared inside a module, without relation to
|
||||||
|
|
|
@ -450,14 +450,8 @@ impl AnalysisImpl {
|
||||||
let syntax = file.syntax();
|
let syntax = file.syntax();
|
||||||
|
|
||||||
// Find the calling expression and it's NameRef
|
// Find the calling expression and it's NameRef
|
||||||
let calling_node = match FnCallNode::with_node(syntax, position.offset) {
|
let calling_node = ctry!(FnCallNode::with_node(syntax, position.offset));
|
||||||
Some(node) => node,
|
let name_ref = ctry!(calling_node.name_ref());
|
||||||
None => return Ok(None),
|
|
||||||
};
|
|
||||||
let name_ref = match calling_node.name_ref() {
|
|
||||||
Some(name) => name,
|
|
||||||
None => return Ok(None),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Resolve the function's NameRef (NOTE: this isn't entirely accurate).
|
// Resolve the function's NameRef (NOTE: this isn't entirely accurate).
|
||||||
let file_symbols = self.index_resolve(name_ref)?;
|
let file_symbols = self.index_resolve(name_ref)?;
|
||||||
|
|
|
@ -9,6 +9,15 @@ extern crate relative_path;
|
||||||
extern crate rustc_hash;
|
extern crate rustc_hash;
|
||||||
extern crate salsa;
|
extern crate salsa;
|
||||||
|
|
||||||
|
macro_rules! ctry {
|
||||||
|
($expr:expr) => {
|
||||||
|
match $expr {
|
||||||
|
None => return Ok(None),
|
||||||
|
Some(it) => it,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
mod arena;
|
mod arena;
|
||||||
mod db;
|
mod db;
|
||||||
mod loc2id;
|
mod loc2id;
|
||||||
|
|
Loading…
Reference in a new issue