Skip to content

Commit d1b993c

Browse files
bors[bot]matklad
andcommitted
Merge #255
255: Binders r=matklad a=matklad Binding sources to hir is a fuzzy operation, so let's move it to a special enclave in the source code. Co-authored-by: Aleksey Kladov <[email protected]>
2 parents 7960c8b + db45674 commit d1b993c

File tree

7 files changed

+125
-140
lines changed

7 files changed

+125
-140
lines changed

crates/ra_analysis/src/completion/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use ra_syntax::{
99
};
1010
use ra_db::SyntaxDatabase;
1111
use rustc_hash::{FxHashMap};
12+
use hir::source_binder;
1213

1314
use crate::{
1415
db,
@@ -36,7 +37,7 @@ pub(crate) fn completions(
3637
original_file.reparse(&edit)
3738
};
3839

39-
let module = ctry!(hir::Module::guess_from_position(db, position)?);
40+
let module = ctry!(source_binder::module_from_position(db, position)?);
4041

4142
let mut res = Vec::new();
4243
let mut has_completions = false;

crates/ra_analysis/src/imp.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_hash::FxHashSet;
1616
use salsa::{Database, ParallelDatabase};
1717
use hir::{
1818
self,
19+
source_binder,
1920
FnSignatureInfo,
2021
Problem,
2122
};
@@ -166,7 +167,7 @@ impl AnalysisImpl {
166167
/// This return `Vec`: a module may be included from several places. We
167168
/// don't handle this case yet though, so the Vec has length at most one.
168169
pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
169-
let descr = match hir::Module::guess_from_position(&*self.db, position)? {
170+
let descr = match source_binder::module_from_position(&*self.db, position)? {
170171
None => return Ok(Vec::new()),
171172
Some(it) => it,
172173
};
@@ -185,7 +186,7 @@ impl AnalysisImpl {
185186
}
186187
/// Returns `Vec` for the same reason as `parent_module`
187188
pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
188-
let descr = match hir::Module::guess_from_file_id(&*self.db, file_id)? {
189+
let descr = match source_binder::module_from_file_id(&*self.db, file_id)? {
189190
None => return Ok(Vec::new()),
190191
Some(it) => it,
191192
};
@@ -209,9 +210,11 @@ impl AnalysisImpl {
209210
let file = self.db.source_file(position.file_id);
210211
let syntax = file.syntax();
211212
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
212-
if let Some(fn_descr) =
213-
hir::Function::guess_for_name_ref(&*self.db, position.file_id, name_ref)?
214-
{
213+
if let Some(fn_descr) = source_binder::function_from_child_node(
214+
&*self.db,
215+
position.file_id,
216+
name_ref.syntax(),
217+
)? {
215218
let scope = fn_descr.scope(&*self.db);
216219
// First try to resolve the symbol locally
217220
if let Some(entry) = scope.resolve_local_name(name_ref) {
@@ -234,7 +237,7 @@ impl AnalysisImpl {
234237
if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
235238
if module.has_semi() {
236239
let parent_module =
237-
hir::Module::guess_from_file_id(&*self.db, position.file_id)?;
240+
source_binder::module_from_file_id(&*self.db, position.file_id)?;
238241
let child_name = module.name();
239242
match (parent_module, child_name) {
240243
(Some(parent_module), Some(child_name)) => {
@@ -282,18 +285,18 @@ impl AnalysisImpl {
282285
) -> Cancelable<Option<(ast::BindPat<'a>, hir::Function)>> {
283286
let syntax = source_file.syntax();
284287
if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) {
285-
let descr = ctry!(hir::Function::guess_for_bind_pat(
288+
let descr = ctry!(source_binder::function_from_child_node(
286289
db,
287290
position.file_id,
288-
binding
291+
binding.syntax(),
289292
)?);
290293
return Ok(Some((binding, descr)));
291294
};
292295
let name_ref = ctry!(find_node_at_offset::<ast::NameRef>(syntax, position.offset));
293-
let descr = ctry!(hir::Function::guess_for_name_ref(
296+
let descr = ctry!(source_binder::function_from_child_node(
294297
db,
295298
position.file_id,
296-
name_ref
299+
name_ref.syntax(),
297300
)?);
298301
let scope = descr.scope(db);
299302
let resolved = ctry!(scope.resolve_local_name(name_ref));
@@ -327,7 +330,7 @@ impl AnalysisImpl {
327330
fix: None,
328331
})
329332
.collect::<Vec<_>>();
330-
if let Some(m) = hir::Module::guess_from_file_id(&*self.db, file_id)? {
333+
if let Some(m) = source_binder::module_from_file_id(&*self.db, file_id)? {
331334
for (name_node, problem) in m.problems(&*self.db) {
332335
let diag = match problem {
333336
Problem::UnresolvedModule { candidate } => {
@@ -418,7 +421,7 @@ impl AnalysisImpl {
418421
if fs.kind == FN_DEF {
419422
let fn_file = self.db.source_file(fn_file_id);
420423
if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) {
421-
let descr = ctry!(hir::Function::guess_from_source(
424+
let descr = ctry!(source_binder::function_from_source(
422425
&*self.db, fn_file_id, fn_def
423426
)?);
424427
if let Some(descriptor) = descr.signature_info(&*self.db) {

crates/ra_hir/src/function/mod.rs

Lines changed: 2 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,11 @@ use std::{
66
};
77

88
use ra_syntax::{
9-
TextRange, TextUnit, SyntaxNodeRef,
9+
TextRange, TextUnit,
1010
ast::{self, AstNode, DocCommentsOwner, NameOwner},
1111
};
12-
use ra_db::FileId;
1312

14-
use crate::{
15-
Cancelable,
16-
DefLoc, DefKind, DefId, HirDatabase, SourceItemId,
17-
Module,
18-
};
13+
use crate::{ DefId, HirDatabase };
1914

2015
pub use self::scope::FnScopes;
2116

@@ -32,49 +27,6 @@ impl Function {
3227
Function { fn_id }
3328
}
3429

35-
pub fn guess_from_source(
36-
db: &impl HirDatabase,
37-
file_id: FileId,
38-
fn_def: ast::FnDef,
39-
) -> Cancelable<Option<Function>> {
40-
let module = ctry!(Module::guess_from_child_node(db, file_id, fn_def.syntax())?);
41-
let file_items = db.file_items(file_id);
42-
let item_id = file_items.id_of(fn_def.syntax());
43-
let source_item_id = SourceItemId { file_id, item_id };
44-
let def_loc = DefLoc {
45-
kind: DefKind::Function,
46-
source_root_id: module.source_root_id,
47-
module_id: module.module_id,
48-
source_item_id,
49-
};
50-
Ok(Some(Function::new(def_loc.id(db))))
51-
}
52-
53-
pub fn guess_for_name_ref(
54-
db: &impl HirDatabase,
55-
file_id: FileId,
56-
name_ref: ast::NameRef,
57-
) -> Cancelable<Option<Function>> {
58-
Function::guess_for_node(db, file_id, name_ref.syntax())
59-
}
60-
61-
pub fn guess_for_bind_pat(
62-
db: &impl HirDatabase,
63-
file_id: FileId,
64-
bind_pat: ast::BindPat,
65-
) -> Cancelable<Option<Function>> {
66-
Function::guess_for_node(db, file_id, bind_pat.syntax())
67-
}
68-
69-
fn guess_for_node(
70-
db: &impl HirDatabase,
71-
file_id: FileId,
72-
node: SyntaxNodeRef,
73-
) -> Cancelable<Option<Function>> {
74-
let fn_def = ctry!(node.ancestors().find_map(ast::FnDef::cast));
75-
Function::guess_from_source(db, file_id, fn_def)
76-
}
77-
7830
pub fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> {
7931
db.fn_scopes(self.fn_id)
8032
}

crates/ra_hir/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ mod function;
2222
mod module;
2323
mod path;
2424
mod arena;
25+
pub mod source_binder;
2526

2627
use std::ops::Index;
2728

crates/ra_hir/src/module/mod.rs

Lines changed: 6 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ pub(super) mod nameres;
33

44
use std::sync::Arc;
55

6-
use ra_editor::find_node_at_offset;
7-
86
use ra_syntax::{
97
algo::generate,
108
ast::{self, AstNode, NameOwner},
11-
SmolStr, SyntaxNode, SyntaxNodeRef,
9+
SmolStr, SyntaxNode,
1210
};
13-
use ra_db::{SourceRootId, FileId, FilePosition, Cancelable};
11+
use ra_db::{SourceRootId, FileId, Cancelable};
1412
use relative_path::RelativePathBuf;
1513

1614
use crate::{
@@ -30,68 +28,6 @@ pub struct Module {
3028
}
3129

3230
impl Module {
33-
/// Lookup `Module` by `FileId`. Note that this is inherently
34-
/// lossy transformation: in general, a single source might correspond to
35-
/// several modules.
36-
pub fn guess_from_file_id(
37-
db: &impl HirDatabase,
38-
file_id: FileId,
39-
) -> Cancelable<Option<Module>> {
40-
let module_source = ModuleSource::new_file(db, file_id);
41-
Module::guess_from_source(db, module_source)
42-
}
43-
44-
/// Lookup `Module` by position in the source code. Note that this
45-
/// is inherently lossy transformation: in general, a single source might
46-
/// correspond to several modules.
47-
pub fn guess_from_position(
48-
db: &impl HirDatabase,
49-
position: FilePosition,
50-
) -> Cancelable<Option<Module>> {
51-
let file = db.source_file(position.file_id);
52-
let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset)
53-
{
54-
Some(m) if !m.has_semi() => ModuleSource::new_inline(db, position.file_id, m),
55-
_ => ModuleSource::new_file(db, position.file_id),
56-
};
57-
Module::guess_from_source(db, module_source)
58-
}
59-
60-
pub fn guess_from_child_node(
61-
db: &impl HirDatabase,
62-
file_id: FileId,
63-
node: SyntaxNodeRef,
64-
) -> Cancelable<Option<Module>> {
65-
let module_source = if let Some(m) = node
66-
.ancestors()
67-
.filter_map(ast::Module::cast)
68-
.find(|it| !it.has_semi())
69-
{
70-
ModuleSource::new_inline(db, file_id, m)
71-
} else {
72-
ModuleSource::new_file(db, file_id)
73-
};
74-
Module::guess_from_source(db, module_source)
75-
}
76-
77-
fn guess_from_source(
78-
db: &impl HirDatabase,
79-
module_source: ModuleSource,
80-
) -> Cancelable<Option<Module>> {
81-
let source_root_id = db.file_source_root(module_source.file_id());
82-
let module_tree = db.module_tree(source_root_id)?;
83-
84-
let res = match module_tree.any_module_for_source(module_source) {
85-
None => None,
86-
Some(module_id) => Some(Module {
87-
tree: module_tree,
88-
source_root_id,
89-
module_id,
90-
}),
91-
};
92-
Ok(res)
93-
}
94-
9531
pub(super) fn new(
9632
db: &impl HirDatabase,
9733
source_root_id: SourceRootId,
@@ -217,16 +153,10 @@ impl ModuleTree {
217153
self.mods.iter().map(|(id, _)| id)
218154
}
219155

220-
fn modules_for_source(&self, source: ModuleSource) -> Vec<ModuleId> {
221-
self.mods
222-
.iter()
223-
.filter(|(_idx, it)| it.source == source)
224-
.map(|(idx, _)| idx)
225-
.collect()
226-
}
227-
228-
fn any_module_for_source(&self, source: ModuleSource) -> Option<ModuleId> {
229-
self.modules_for_source(source).pop()
156+
pub(crate) fn modules_with_sources<'a>(
157+
&'a self,
158+
) -> impl Iterator<Item = (ModuleId, ModuleSource)> + 'a {
159+
self.mods.iter().map(|(id, m)| (id, m.source))
230160
}
231161
}
232162

crates/ra_hir/src/module/nameres.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,9 @@ mod tests {
363363
fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
364364
let (db, pos) = MockDatabase::with_position(fixture);
365365
let source_root = db.file_source_root(pos.file_id);
366-
let module = hir::Module::guess_from_position(&db, pos).unwrap().unwrap();
366+
let module = hir::source_binder::module_from_position(&db, pos)
367+
.unwrap()
368+
.unwrap();
367369
let module_id = module.module_id;
368370
(db.item_map(source_root).unwrap(), module_id)
369371
}

crates/ra_hir/src/source_binder.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/// Lookup hir elements using position in the source code. This is a lossy
2+
/// transformation: in general, a single source might correspond to several
3+
/// modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on
4+
/// modules.
5+
///
6+
/// So, this modules should not be used during hir construction, it exists
7+
/// purely for "IDE needs".
8+
use ra_db::{FileId, FilePosition, Cancelable};
9+
use ra_editor::find_node_at_offset;
10+
use ra_syntax::{
11+
ast::{self, AstNode},
12+
SyntaxNodeRef,
13+
};
14+
15+
use crate::{
16+
HirDatabase, Module, Function, SourceItemId,
17+
module::ModuleSource,
18+
DefKind, DefLoc
19+
};
20+
21+
/// Locates the module by `FileId`. Picks topmost module in the file.
22+
pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Cancelable<Option<Module>> {
23+
let module_source = ModuleSource::new_file(db, file_id);
24+
module_from_source(db, module_source)
25+
}
26+
27+
/// Locates the module by position in the source code.
28+
pub fn module_from_position(
29+
db: &impl HirDatabase,
30+
position: FilePosition,
31+
) -> Cancelable<Option<Module>> {
32+
let file = db.source_file(position.file_id);
33+
let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) {
34+
Some(m) if !m.has_semi() => ModuleSource::new_inline(db, position.file_id, m),
35+
_ => ModuleSource::new_file(db, position.file_id),
36+
};
37+
module_from_source(db, module_source)
38+
}
39+
40+
/// Locates the module by child syntax element within the module
41+
pub fn module_from_child_node(
42+
db: &impl HirDatabase,
43+
file_id: FileId,
44+
child: SyntaxNodeRef,
45+
) -> Cancelable<Option<Module>> {
46+
let module_source = if let Some(m) = child
47+
.ancestors()
48+
.filter_map(ast::Module::cast)
49+
.find(|it| !it.has_semi())
50+
{
51+
ModuleSource::new_inline(db, file_id, m)
52+
} else {
53+
ModuleSource::new_file(db, file_id)
54+
};
55+
module_from_source(db, module_source)
56+
}
57+
58+
fn module_from_source(
59+
db: &impl HirDatabase,
60+
module_source: ModuleSource,
61+
) -> Cancelable<Option<Module>> {
62+
let source_root_id = db.file_source_root(module_source.file_id());
63+
let module_tree = db.module_tree(source_root_id)?;
64+
let m = module_tree
65+
.modules_with_sources()
66+
.find(|(_id, src)| src == &module_source);
67+
let module_id = ctry!(m).0;
68+
Ok(Some(Module::new(db, source_root_id, module_id)?))
69+
}
70+
71+
pub fn function_from_source(
72+
db: &impl HirDatabase,
73+
file_id: FileId,
74+
fn_def: ast::FnDef,
75+
) -> Cancelable<Option<Function>> {
76+
let module = ctry!(module_from_child_node(db, file_id, fn_def.syntax())?);
77+
let file_items = db.file_items(file_id);
78+
let item_id = file_items.id_of(fn_def.syntax());
79+
let source_item_id = SourceItemId { file_id, item_id };
80+
let def_loc = DefLoc {
81+
kind: DefKind::Function,
82+
source_root_id: module.source_root_id,
83+
module_id: module.module_id,
84+
source_item_id,
85+
};
86+
Ok(Some(Function::new(def_loc.id(db))))
87+
}
88+
89+
pub fn function_from_child_node(
90+
db: &impl HirDatabase,
91+
file_id: FileId,
92+
node: SyntaxNodeRef,
93+
) -> Cancelable<Option<Function>> {
94+
let fn_def = ctry!(node.ancestors().find_map(ast::FnDef::cast));
95+
function_from_source(db, file_id, fn_def)
96+
}

0 commit comments

Comments
 (0)