move fuzzy source binding to a separete mode

This commit is contained in:
Aleksey Kladov 2018-12-05 13:16:20 +03:00
parent 7960c8b276
commit 4344264024
7 changed files with 121 additions and 131 deletions

View file

@ -6,16 +6,11 @@ use std::{
};
use ra_syntax::{
TextRange, TextUnit, SyntaxNodeRef,
TextRange, TextUnit,
ast::{self, AstNode, DocCommentsOwner, NameOwner},
};
use ra_db::FileId;
use crate::{
Cancelable,
DefLoc, DefKind, DefId, HirDatabase, SourceItemId,
Module,
};
use crate::{ DefId, HirDatabase };
pub use self::scope::FnScopes;
@ -32,49 +27,6 @@ impl Function {
Function { fn_id }
}
pub fn guess_from_source(
db: &impl HirDatabase,
file_id: FileId,
fn_def: ast::FnDef,
) -> Cancelable<Option<Function>> {
let module = ctry!(Module::guess_from_child_node(db, file_id, fn_def.syntax())?);
let file_items = db.file_items(file_id);
let item_id = file_items.id_of(fn_def.syntax());
let source_item_id = SourceItemId { file_id, item_id };
let def_loc = DefLoc {
kind: DefKind::Function,
source_root_id: module.source_root_id,
module_id: module.module_id,
source_item_id,
};
Ok(Some(Function::new(def_loc.id(db))))
}
pub fn guess_for_name_ref(
db: &impl HirDatabase,
file_id: FileId,
name_ref: ast::NameRef,
) -> Cancelable<Option<Function>> {
Function::guess_for_node(db, file_id, name_ref.syntax())
}
pub fn guess_for_bind_pat(
db: &impl HirDatabase,
file_id: FileId,
bind_pat: ast::BindPat,
) -> Cancelable<Option<Function>> {
Function::guess_for_node(db, file_id, bind_pat.syntax())
}
fn guess_for_node(
db: &impl HirDatabase,
file_id: FileId,
node: SyntaxNodeRef,
) -> Cancelable<Option<Function>> {
let fn_def = ctry!(node.ancestors().find_map(ast::FnDef::cast));
Function::guess_from_source(db, file_id, fn_def)
}
pub fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> {
db.fn_scopes(self.fn_id)
}

View file

@ -22,6 +22,7 @@ mod function;
mod module;
mod path;
mod arena;
pub mod source_binder;
use std::ops::Index;

View file

@ -3,14 +3,12 @@ pub(super) mod nameres;
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 ra_db::{SourceRootId, FileId, FilePosition, Cancelable};
use ra_db::{SourceRootId, FileId, Cancelable};
use relative_path::RelativePathBuf;
use crate::{
@ -30,68 +28,6 @@ pub struct Module {
}
impl Module {
/// Lookup `Module` 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 HirDatabase,
file_id: FileId,
) -> Cancelable<Option<Module>> {
let module_source = ModuleSource::new_file(db, file_id);
Module::guess_from_source(db, module_source)
}
/// Lookup `Module` 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 HirDatabase,
position: FilePosition,
) -> Cancelable<Option<Module>> {
let file = db.source_file(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(db, position.file_id, m),
_ => ModuleSource::new_file(db, position.file_id),
};
Module::guess_from_source(db, module_source)
}
pub fn guess_from_child_node(
db: &impl HirDatabase,
file_id: FileId,
node: SyntaxNodeRef,
) -> Cancelable<Option<Module>> {
let module_source = if let Some(m) = node
.ancestors()
.filter_map(ast::Module::cast)
.find(|it| !it.has_semi())
{
ModuleSource::new_inline(db, file_id, m)
} else {
ModuleSource::new_file(db, file_id)
};
Module::guess_from_source(db, module_source)
}
fn guess_from_source(
db: &impl HirDatabase,
module_source: ModuleSource,
) -> Cancelable<Option<Module>> {
let source_root_id = db.file_source_root(module_source.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(Module {
tree: module_tree,
source_root_id,
module_id,
}),
};
Ok(res)
}
pub(super) fn new(
db: &impl HirDatabase,
source_root_id: SourceRootId,
@ -225,7 +161,8 @@ impl ModuleTree {
.collect()
}
fn any_module_for_source(&self, source: ModuleSource) -> Option<ModuleId> {
//TODO: move to source binders?
pub(crate) fn any_module_for_source(&self, source: ModuleSource) -> Option<ModuleId> {
self.modules_for_source(source).pop()
}
}

View file

@ -363,7 +363,9 @@ mod tests {
fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
let (db, pos) = MockDatabase::with_position(fixture);
let source_root = db.file_source_root(pos.file_id);
let module = hir::Module::guess_from_position(&db, pos).unwrap().unwrap();
let module = hir::source_binder::module_from_position(&db, pos)
.unwrap()
.unwrap();
let module_id = module.module_id;
(db.item_map(source_root).unwrap(), module_id)
}

View file

@ -0,0 +1,94 @@
/// Lookup hir elements using position in the source code. This is a lossy
/// transformation: in general, a single source might correspond to several
/// modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on
/// modules.
///
/// So, this modules should not be used during hir construction, it exists
/// purely for "IDE needs".
use ra_db::{FileId, FilePosition, Cancelable};
use ra_editor::find_node_at_offset;
use ra_syntax::{
ast::{self, AstNode},
SyntaxNodeRef,
};
use crate::{
HirDatabase, Module, Function, SourceItemId,
module::ModuleSource,
DefKind, DefLoc
};
/// Locates the module by `FileId`. Picks topmost module in the file.
pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Cancelable<Option<Module>> {
let module_source = ModuleSource::new_file(db, file_id);
module_from_source(db, module_source)
}
/// Locates the module by position in the source code.
pub fn module_from_position(
db: &impl HirDatabase,
position: FilePosition,
) -> Cancelable<Option<Module>> {
let file = db.source_file(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(db, position.file_id, m),
_ => ModuleSource::new_file(db, position.file_id),
};
module_from_source(db, module_source)
}
/// Locates the module by child syntax element within the module
pub fn module_from_child_node(
db: &impl HirDatabase,
file_id: FileId,
child: SyntaxNodeRef,
) -> Cancelable<Option<Module>> {
let module_source = if let Some(m) = child
.ancestors()
.filter_map(ast::Module::cast)
.find(|it| !it.has_semi())
{
ModuleSource::new_inline(db, file_id, m)
} else {
ModuleSource::new_file(db, file_id)
};
module_from_source(db, module_source)
}
fn module_from_source(
db: &impl HirDatabase,
module_source: ModuleSource,
) -> Cancelable<Option<Module>> {
let source_root_id = db.file_source_root(module_source.file_id());
let module_tree = db.module_tree(source_root_id)?;
let module_id = ctry!(module_tree.any_module_for_source(module_source));
Ok(Some(Module::new(db, source_root_id, module_id)?))
}
pub fn function_from_source(
db: &impl HirDatabase,
file_id: FileId,
fn_def: ast::FnDef,
) -> Cancelable<Option<Function>> {
let module = ctry!(module_from_child_node(db, file_id, fn_def.syntax())?);
let file_items = db.file_items(file_id);
let item_id = file_items.id_of(fn_def.syntax());
let source_item_id = SourceItemId { file_id, item_id };
let def_loc = DefLoc {
kind: DefKind::Function,
source_root_id: module.source_root_id,
module_id: module.module_id,
source_item_id,
};
Ok(Some(Function::new(def_loc.id(db))))
}
pub fn function_from_child_node(
db: &impl HirDatabase,
file_id: FileId,
node: SyntaxNodeRef,
) -> Cancelable<Option<Function>> {
let fn_def = ctry!(node.ancestors().find_map(ast::FnDef::cast));
function_from_source(db, file_id, fn_def)
}