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.rs119
1 files changed, 70 insertions, 49 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 662d3f880..f0ed8e2b2 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -11,13 +11,12 @@ use hir_def::{
11 expr::{ExprId, PatId}, 11 expr::{ExprId, PatId},
12 path::known, 12 path::known,
13}; 13};
14use hir_expand::{name::AsName, Source}; 14use hir_expand::{name::AsName, AstId, MacroCallId, MacroCallLoc, MacroFileKind, Source};
15use ra_db::FileId;
16use ra_syntax::{ 15use ra_syntax::{
17 ast::{self, AstNode}, 16 ast::{self, AstNode},
18 match_ast, AstPtr, 17 match_ast, AstPtr,
19 SyntaxKind::*, 18 SyntaxKind::*,
20 SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, 19 SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit,
21}; 20};
22 21
23use crate::{ 22use crate::{
@@ -30,52 +29,45 @@ use crate::{
30 HirFileId, Local, MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty, 29 HirFileId, Local, MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty,
31}; 30};
32 31
33fn try_get_resolver_for_node( 32fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -> Option<Resolver> {
34 db: &impl HirDatabase,
35 file_id: FileId,
36 node: &SyntaxNode,
37) -> Option<Resolver> {
38 match_ast! { 33 match_ast! {
39 match node { 34 match (node.ast) {
40 ast::Module(it) => { 35 ast::Module(it) => {
41 let src = crate::Source { file_id: file_id.into(), ast: it }; 36 let src = node.with_ast(it);
42 Some(crate::Module::from_declaration(db, src)?.resolver(db)) 37 Some(crate::Module::from_declaration(db, src)?.resolver(db))
43 }, 38 },
44 ast::SourceFile(it) => { 39 ast::SourceFile(it) => {
45 let src = 40 let src = node.with_ast(crate::ModuleSource::SourceFile(it));
46 crate::Source { file_id: file_id.into(), ast: crate::ModuleSource::SourceFile(it) };
47 Some(crate::Module::from_definition(db, src)?.resolver(db)) 41 Some(crate::Module::from_definition(db, src)?.resolver(db))
48 }, 42 },
49 ast::StructDef(it) => { 43 ast::StructDef(it) => {
50 let src = crate::Source { file_id: file_id.into(), ast: it }; 44 let src = node.with_ast(it);
51 Some(Struct::from_source(db, src)?.resolver(db)) 45 Some(Struct::from_source(db, src)?.resolver(db))
52 }, 46 },
53 ast::EnumDef(it) => { 47 ast::EnumDef(it) => {
54 let src = crate::Source { file_id: file_id.into(), ast: it }; 48 let src = node.with_ast(it);
55 Some(Enum::from_source(db, src)?.resolver(db)) 49 Some(Enum::from_source(db, src)?.resolver(db))
56 }, 50 },
57 _ => { 51 _ => match node.ast.kind() {
58 if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { 52 FN_DEF | CONST_DEF | STATIC_DEF => {
59 Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db)) 53 Some(def_with_body_from_child_node(db, node)?.resolver(db))
60 } else {
61 // FIXME add missing cases
62 None
63 } 54 }
64 }, 55 // FIXME add missing cases
56 _ => None
57 }
65 } 58 }
66 } 59 }
67} 60}
68 61
69fn def_with_body_from_child_node( 62fn def_with_body_from_child_node(
70 db: &impl HirDatabase, 63 db: &impl HirDatabase,
71 file_id: FileId, 64 child: Source<&SyntaxNode>,
72 node: &SyntaxNode,
73) -> Option<DefWithBody> { 65) -> Option<DefWithBody> {
74 let src = crate::ModuleSource::from_child_node(db, file_id, node); 66 let module_source = crate::ModuleSource::from_child_node(db, child);
75 let module = Module::from_definition(db, crate::Source { file_id: file_id.into(), ast: src })?; 67 let module = Module::from_definition(db, Source::new(child.file_id, module_source))?;
76 let ctx = LocationCtx::new(db, module.id, file_id.into()); 68 let ctx = LocationCtx::new(db, module.id, child.file_id);
77 69
78 node.ancestors().find_map(|node| { 70 child.ast.ancestors().find_map(|node| {
79 match_ast! { 71 match_ast! {
80 match node { 72 match node {
81 ast::FnDef(def) => { Some(Function {id: ctx.to_def(&def) }.into()) }, 73 ast::FnDef(def) => { Some(Function {id: ctx.to_def(&def) }.into()) },
@@ -91,8 +83,7 @@ fn def_with_body_from_child_node(
91/// original source files. It should not be used inside the HIR itself. 83/// original source files. It should not be used inside the HIR itself.
92#[derive(Debug)] 84#[derive(Debug)]
93pub struct SourceAnalyzer { 85pub struct SourceAnalyzer {
94 // FIXME: this doesn't handle macros at all 86 file_id: HirFileId,
95 file_id: FileId,
96 resolver: Resolver, 87 resolver: Resolver,
97 body_owner: Option<DefWithBody>, 88 body_owner: Option<DefWithBody>,
98 body_source_map: Option<Arc<BodySourceMap>>, 89 body_source_map: Option<Arc<BodySourceMap>>,
@@ -135,20 +126,38 @@ pub struct ReferenceDescriptor {
135 pub name: String, 126 pub name: String,
136} 127}
137 128
129pub struct Expansion {
130 macro_call_id: MacroCallId,
131}
132
133impl Expansion {
134 pub fn map_token_down(
135 &self,
136 db: &impl HirDatabase,
137 token: Source<&SyntaxToken>,
138 ) -> Option<Source<SyntaxToken>> {
139 let exp_info = self.file_id().expansion_info(db)?;
140 exp_info.map_token_down(token)
141 }
142
143 fn file_id(&self) -> HirFileId {
144 self.macro_call_id.as_file(MacroFileKind::Items)
145 }
146}
147
138impl SourceAnalyzer { 148impl SourceAnalyzer {
139 pub fn new( 149 pub fn new(
140 db: &impl HirDatabase, 150 db: &impl HirDatabase,
141 file_id: FileId, 151 node: Source<&SyntaxNode>,
142 node: &SyntaxNode,
143 offset: Option<TextUnit>, 152 offset: Option<TextUnit>,
144 ) -> SourceAnalyzer { 153 ) -> SourceAnalyzer {
145 let def_with_body = def_with_body_from_child_node(db, file_id, node); 154 let def_with_body = def_with_body_from_child_node(db, node);
146 if let Some(def) = def_with_body { 155 if let Some(def) = def_with_body {
147 let source_map = def.body_source_map(db); 156 let source_map = def.body_source_map(db);
148 let scopes = def.expr_scopes(db); 157 let scopes = def.expr_scopes(db);
149 let scope = match offset { 158 let scope = match offset {
150 None => scope_for(&scopes, &source_map, file_id.into(), &node), 159 None => scope_for(&scopes, &source_map, node),
151 Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), 160 Some(offset) => scope_for_offset(&scopes, &source_map, node.with_ast(offset)),
152 }; 161 };
153 let resolver = expr::resolver_for_scope(db, def, scope); 162 let resolver = expr::resolver_for_scope(db, def, scope);
154 SourceAnalyzer { 163 SourceAnalyzer {
@@ -157,30 +166,31 @@ impl SourceAnalyzer {
157 body_source_map: Some(source_map), 166 body_source_map: Some(source_map),
158 infer: Some(def.infer(db)), 167 infer: Some(def.infer(db)),
159 scopes: Some(scopes), 168 scopes: Some(scopes),
160 file_id, 169 file_id: node.file_id,
161 } 170 }
162 } else { 171 } else {
163 SourceAnalyzer { 172 SourceAnalyzer {
164 resolver: node 173 resolver: node
174 .ast
165 .ancestors() 175 .ancestors()
166 .find_map(|node| try_get_resolver_for_node(db, file_id, &node)) 176 .find_map(|it| try_get_resolver_for_node(db, node.with_ast(&it)))
167 .unwrap_or_default(), 177 .unwrap_or_default(),
168 body_owner: None, 178 body_owner: None,
169 body_source_map: None, 179 body_source_map: None,
170 infer: None, 180 infer: None,
171 scopes: None, 181 scopes: None,
172 file_id, 182 file_id: node.file_id,
173 } 183 }
174 } 184 }
175 } 185 }
176 186
177 fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> { 187 fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> {
178 let src = Source { file_id: self.file_id.into(), ast: expr }; 188 let src = Source { file_id: self.file_id, ast: expr };
179 self.body_source_map.as_ref()?.node_expr(src) 189 self.body_source_map.as_ref()?.node_expr(src)
180 } 190 }
181 191
182 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> { 192 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
183 let src = Source { file_id: self.file_id.into(), ast: pat }; 193 let src = Source { file_id: self.file_id, ast: pat };
184 self.body_source_map.as_ref()?.node_pat(src) 194 self.body_source_map.as_ref()?.node_pat(src)
185 } 195 }
186 196
@@ -288,7 +298,7 @@ impl SourceAnalyzer {
288 let name = name_ref.as_name(); 298 let name = name_ref.as_name();
289 let source_map = self.body_source_map.as_ref()?; 299 let source_map = self.body_source_map.as_ref()?;
290 let scopes = self.scopes.as_ref()?; 300 let scopes = self.scopes.as_ref()?;
291 let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax())?; 301 let scope = scope_for(scopes, source_map, Source::new(self.file_id, name_ref.syntax()))?;
292 let entry = scopes.resolve_name_in_scope(scope, &name)?; 302 let entry = scopes.resolve_name_in_scope(scope, &name)?;
293 Some(ScopeEntryWithSyntax { 303 Some(ScopeEntryWithSyntax {
294 name: entry.name().clone(), 304 name: entry.name().clone(),
@@ -395,6 +405,13 @@ impl SourceAnalyzer {
395 implements_trait(&canonical_ty, db, &self.resolver, krate, std_future_trait) 405 implements_trait(&canonical_ty, db, &self.resolver, krate, std_future_trait)
396 } 406 }
397 407
408 pub fn expand(&self, db: &impl HirDatabase, macro_call: &ast::MacroCall) -> Option<Expansion> {
409 let def = self.resolve_macro_call(db, macro_call)?.id;
410 let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(macro_call));
411 let macro_call_loc = MacroCallLoc { def, ast_id };
412 Some(Expansion { macro_call_id: db.intern_macro(macro_call_loc) })
413 }
414
398 #[cfg(test)] 415 #[cfg(test)]
399 pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> { 416 pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> {
400 self.body_source_map.clone().unwrap() 417 self.body_source_map.clone().unwrap()
@@ -409,20 +426,19 @@ impl SourceAnalyzer {
409fn scope_for( 426fn scope_for(
410 scopes: &ExprScopes, 427 scopes: &ExprScopes,
411 source_map: &BodySourceMap, 428 source_map: &BodySourceMap,
412 file_id: HirFileId, 429 node: Source<&SyntaxNode>,
413 node: &SyntaxNode,
414) -> Option<ScopeId> { 430) -> Option<ScopeId> {
415 node.ancestors() 431 node.ast
432 .ancestors()
416 .filter_map(ast::Expr::cast) 433 .filter_map(ast::Expr::cast)
417 .filter_map(|it| source_map.node_expr(Source { file_id, ast: &it })) 434 .filter_map(|it| source_map.node_expr(Source::new(node.file_id, &it)))
418 .find_map(|it| scopes.scope_for(it)) 435 .find_map(|it| scopes.scope_for(it))
419} 436}
420 437
421fn scope_for_offset( 438fn scope_for_offset(
422 scopes: &ExprScopes, 439 scopes: &ExprScopes,
423 source_map: &BodySourceMap, 440 source_map: &BodySourceMap,
424 file_id: HirFileId, 441 offset: Source<TextUnit>,
425 offset: TextUnit,
426) -> Option<ScopeId> { 442) -> Option<ScopeId> {
427 scopes 443 scopes
428 .scope_by_expr() 444 .scope_by_expr()
@@ -430,7 +446,7 @@ fn scope_for_offset(
430 .filter_map(|(id, scope)| { 446 .filter_map(|(id, scope)| {
431 let source = source_map.expr_syntax(*id)?; 447 let source = source_map.expr_syntax(*id)?;
432 // FIXME: correctly handle macro expansion 448 // FIXME: correctly handle macro expansion
433 if source.file_id != file_id { 449 if source.file_id != offset.file_id {
434 return None; 450 return None;
435 } 451 }
436 let syntax_node_ptr = 452 let syntax_node_ptr =
@@ -439,9 +455,14 @@ fn scope_for_offset(
439 }) 455 })
440 // find containing scope 456 // find containing scope
441 .min_by_key(|(ptr, _scope)| { 457 .min_by_key(|(ptr, _scope)| {
442 (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len()) 458 (
459 !(ptr.range().start() <= offset.ast && offset.ast <= ptr.range().end()),
460 ptr.range().len(),
461 )
462 })
463 .map(|(ptr, scope)| {
464 adjust(scopes, source_map, ptr, offset.file_id, offset.ast).unwrap_or(*scope)
443 }) 465 })
444 .map(|(ptr, scope)| adjust(scopes, source_map, ptr, file_id, offset).unwrap_or(*scope))
445} 466}
446 467
447// XXX: during completion, cursor might be outside of any particular 468// XXX: during completion, cursor might be outside of any particular