aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/source_binder.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/source_binder.rs')
-rw-r--r--crates/ra_hir/src/source_binder.rs124
1 files changed, 17 insertions, 107 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 4d895f0a1..296acc364 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -7,10 +7,9 @@
7/// purely for "IDE needs". 7/// purely for "IDE needs".
8use std::sync::Arc; 8use std::sync::Arc;
9 9
10use ra_db::{FileId, FilePosition}; 10use ra_db::FileId;
11use ra_syntax::{ 11use ra_syntax::{
12 algo::find_node_at_offset, 12 ast::{self, AstNode},
13 ast::{self, AstNode, NameOwner},
14 AstPtr, 13 AstPtr,
15 SyntaxKind::*, 14 SyntaxKind::*,
16 SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, 15 SyntaxNode, SyntaxNodePtr, TextRange, TextUnit,
@@ -28,119 +27,28 @@ use crate::{
28 path::known, 27 path::known,
29 resolve::{ScopeDef, TypeNs, ValueNs}, 28 resolve::{ScopeDef, TypeNs, ValueNs},
30 ty::method_resolution::implements_trait, 29 ty::method_resolution::implements_trait,
31 AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef, 30 AsName, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, MacroDef,
32 Module, Name, Path, Resolver, Static, Struct, Trait, Ty, 31 Module, Name, Path, Resolver, Static, Struct, Ty,
33}; 32};
34 33
35/// Locates the module by `FileId`. Picks topmost module in the file.
36pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Option<Module> {
37 module_from_source(db, file_id.into(), None)
38}
39
40/// Locates the child module by `mod child;` declaration.
41pub fn module_from_declaration(
42 db: &impl HirDatabase,
43 file_id: FileId,
44 decl: ast::Module,
45) -> Option<Module> {
46 let parent_module = module_from_file_id(db, file_id);
47 let child_name = decl.name();
48 match (parent_module, child_name) {
49 (Some(parent_module), Some(child_name)) => parent_module.child(db, &child_name.as_name()),
50 _ => None,
51 }
52}
53
54/// Locates the module by position in the source code.
55pub fn module_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Module> {
56 let parse = db.parse(position.file_id);
57 match &find_node_at_offset::<ast::Module>(parse.tree().syntax(), position.offset) {
58 Some(m) if !m.has_semi() => module_from_inline(db, position.file_id, m.clone()),
59 _ => module_from_file_id(db, position.file_id),
60 }
61}
62
63fn module_from_inline(
64 db: &impl HirDatabase,
65 file_id: FileId,
66 module: ast::Module,
67) -> Option<Module> {
68 assert!(!module.has_semi());
69 let file_id = file_id.into();
70 let ast_id_map = db.ast_id_map(file_id);
71 let item_id = ast_id_map.ast_id(&module).with_file_id(file_id);
72 module_from_source(db, file_id, Some(item_id))
73}
74
75/// Locates the module by child syntax element within the module
76pub fn module_from_child_node(
77 db: &impl HirDatabase,
78 file_id: FileId,
79 child: &SyntaxNode,
80) -> Option<Module> {
81 if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) {
82 module_from_inline(db, file_id, m)
83 } else {
84 module_from_file_id(db, file_id)
85 }
86}
87
88fn module_from_source(
89 db: &impl HirDatabase,
90 file_id: HirFileId,
91 decl_id: Option<AstId<ast::Module>>,
92) -> Option<Module> {
93 let source_root_id = db.file_source_root(file_id.as_original_file());
94 db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map(
95 |krate| {
96 let def_map = db.crate_def_map(krate);
97 let module_id = def_map.find_module_by_source(file_id, decl_id)?;
98 Some(Module { krate, module_id })
99 },
100 )
101}
102
103pub fn struct_from_module(
104 db: &impl HirDatabase,
105 module: Module,
106 struct_def: &ast::StructDef,
107) -> Struct {
108 let file_id = module.definition_source(db).file_id;
109 let ctx = LocationCtx::new(db, module, file_id);
110 Struct { id: ctx.to_def(struct_def) }
111}
112
113pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum {
114 let file_id = module.definition_source(db).file_id;
115 let ctx = LocationCtx::new(db, module, file_id);
116 Enum { id: ctx.to_def(enum_def) }
117}
118
119pub fn trait_from_module(
120 db: &impl HirDatabase,
121 module: Module,
122 trait_def: &ast::TraitDef,
123) -> Trait {
124 let file_id = module.definition_source(db).file_id;
125 let ctx = LocationCtx::new(db, module, file_id);
126 Trait { id: ctx.to_def(trait_def) }
127}
128
129fn try_get_resolver_for_node( 34fn try_get_resolver_for_node(
130 db: &impl HirDatabase, 35 db: &impl HirDatabase,
131 file_id: FileId, 36 file_id: FileId,
132 node: &SyntaxNode, 37 node: &SyntaxNode,
133) -> Option<Resolver> { 38) -> Option<Resolver> {
134 if let Some(module) = ast::Module::cast(node.clone()) { 39 if let Some(module) = ast::Module::cast(node.clone()) {
135 Some(module_from_declaration(db, file_id, module)?.resolver(db)) 40 let src = crate::Source { file_id: file_id.into(), ast: module };
136 } else if let Some(_) = ast::SourceFile::cast(node.clone()) { 41 Some(crate::Module::from_declaration(db, src)?.resolver(db))
137 Some(module_from_source(db, file_id.into(), None)?.resolver(db)) 42 } else if let Some(file) = ast::SourceFile::cast(node.clone()) {
43 let src =
44 crate::Source { file_id: file_id.into(), ast: crate::ModuleSource::SourceFile(file) };
45 Some(crate::Module::from_definition(db, src)?.resolver(db))
138 } else if let Some(s) = ast::StructDef::cast(node.clone()) { 46 } else if let Some(s) = ast::StructDef::cast(node.clone()) {
139 let module = module_from_child_node(db, file_id, s.syntax())?; 47 let src = crate::Source { file_id: file_id.into(), ast: s };
140 Some(struct_from_module(db, module, &s).resolver(db)) 48 Some(Struct::from_source(db, src)?.resolver(db))
141 } else if let Some(e) = ast::EnumDef::cast(node.clone()) { 49 } else if let Some(e) = ast::EnumDef::cast(node.clone()) {
142 let module = module_from_child_node(db, file_id, e.syntax())?; 50 let src = crate::Source { file_id: file_id.into(), ast: e };
143 Some(enum_from_module(db, module, &e).resolver(db)) 51 Some(Enum::from_source(db, src)?.resolver(db))
144 } else if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { 52 } else if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF {
145 Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db)) 53 Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db))
146 } else { 54 } else {
@@ -154,8 +62,10 @@ fn def_with_body_from_child_node(
154 file_id: FileId, 62 file_id: FileId,
155 node: &SyntaxNode, 63 node: &SyntaxNode,
156) -> Option<DefWithBody> { 64) -> Option<DefWithBody> {
157 let module = module_from_child_node(db, file_id, node)?; 65 let src = crate::ModuleSource::from_child_node(db, file_id, node);
66 let module = Module::from_definition(db, crate::Source { file_id: file_id.into(), ast: src })?;
158 let ctx = LocationCtx::new(db, module, file_id.into()); 67 let ctx = LocationCtx::new(db, module, file_id.into());
68
159 node.ancestors().find_map(|node| { 69 node.ancestors().find_map(|node| {
160 if let Some(def) = ast::FnDef::cast(node.clone()) { 70 if let Some(def) = ast::FnDef::cast(node.clone()) {
161 return Some(Function { id: ctx.to_def(&def) }.into()); 71 return Some(Function { id: ctx.to_def(&def) }.into());