mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-16 01:38:13 +00:00
Use OO module API in completion
This commit is contained in:
parent
21508cfb2f
commit
0dd26a2f5b
3 changed files with 31 additions and 68 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)
|
||||
}
|
||||
|
|
|
@ -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<ModuleTree>,
|
||||
source_root_id: SourceRootId,
|
||||
module_id: ModuleId,
|
||||
}
|
||||
|
||||
|
@ -59,13 +61,14 @@ impl ModuleDescriptor {
|
|||
file_id: FileId,
|
||||
module_source: ModuleSource,
|
||||
) -> Cancelable<Option<ModuleDescriptor>> {
|
||||
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<ModuleDescriptor> {
|
||||
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<ModuleDescriptor> {
|
||||
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<Arc<ModuleScope>> {
|
||||
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<ModuleId> {
|
||||
fn child(self, tree: &ModuleTree, name: &str) -> Option<ModuleId> {
|
||||
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());
|
||||
|
|
Loading…
Reference in a new issue