aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/source_binder.rs43
-rw-r--r--crates/ra_hir_expand/src/lib.rs12
2 files changed, 35 insertions, 20 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index f08827ed3..540ddd0b5 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -91,7 +91,7 @@ fn def_with_body_from_child_node(
91#[derive(Debug)] 91#[derive(Debug)]
92pub struct SourceAnalyzer { 92pub struct SourceAnalyzer {
93 // FIXME: this doesn't handle macros at all 93 // FIXME: this doesn't handle macros at all
94 file_id: FileId, 94 file_id: HirFileId,
95 resolver: Resolver, 95 resolver: Resolver,
96 body_owner: Option<DefWithBody>, 96 body_owner: Option<DefWithBody>,
97 body_source_map: Option<Arc<BodySourceMap>>, 97 body_source_map: Option<Arc<BodySourceMap>>,
@@ -141,13 +141,16 @@ impl SourceAnalyzer {
141 node: &SyntaxNode, 141 node: &SyntaxNode,
142 offset: Option<TextUnit>, 142 offset: Option<TextUnit>,
143 ) -> SourceAnalyzer { 143 ) -> SourceAnalyzer {
144 let def_with_body = def_with_body_from_child_node(db, Source::new(file_id.into(), node)); 144 let node_source = Source::new(file_id.into(), node);
145 let def_with_body = def_with_body_from_child_node(db, node_source);
145 if let Some(def) = def_with_body { 146 if let Some(def) = def_with_body {
146 let source_map = def.body_source_map(db); 147 let source_map = def.body_source_map(db);
147 let scopes = def.expr_scopes(db); 148 let scopes = def.expr_scopes(db);
148 let scope = match offset { 149 let scope = match offset {
149 None => scope_for(&scopes, &source_map, file_id.into(), &node), 150 None => scope_for(&scopes, &source_map, node_source),
150 Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), 151 Some(offset) => {
152 scope_for_offset(&scopes, &source_map, Source::new(file_id.into(), offset))
153 }
151 }; 154 };
152 let resolver = expr::resolver_for_scope(db, def, scope); 155 let resolver = expr::resolver_for_scope(db, def, scope);
153 SourceAnalyzer { 156 SourceAnalyzer {
@@ -156,7 +159,7 @@ impl SourceAnalyzer {
156 body_source_map: Some(source_map), 159 body_source_map: Some(source_map),
157 infer: Some(def.infer(db)), 160 infer: Some(def.infer(db)),
158 scopes: Some(scopes), 161 scopes: Some(scopes),
159 file_id, 162 file_id: file_id.into(),
160 } 163 }
161 } else { 164 } else {
162 SourceAnalyzer { 165 SourceAnalyzer {
@@ -168,18 +171,18 @@ impl SourceAnalyzer {
168 body_source_map: None, 171 body_source_map: None,
169 infer: None, 172 infer: None,
170 scopes: None, 173 scopes: None,
171 file_id, 174 file_id: file_id.into(),
172 } 175 }
173 } 176 }
174 } 177 }
175 178
176 fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> { 179 fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> {
177 let src = Source { file_id: self.file_id.into(), ast: expr }; 180 let src = Source { file_id: self.file_id, ast: expr };
178 self.body_source_map.as_ref()?.node_expr(src) 181 self.body_source_map.as_ref()?.node_expr(src)
179 } 182 }
180 183
181 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> { 184 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
182 let src = Source { file_id: self.file_id.into(), ast: pat }; 185 let src = Source { file_id: self.file_id, ast: pat };
183 self.body_source_map.as_ref()?.node_pat(src) 186 self.body_source_map.as_ref()?.node_pat(src)
184 } 187 }
185 188
@@ -287,7 +290,7 @@ impl SourceAnalyzer {
287 let name = name_ref.as_name(); 290 let name = name_ref.as_name();
288 let source_map = self.body_source_map.as_ref()?; 291 let source_map = self.body_source_map.as_ref()?;
289 let scopes = self.scopes.as_ref()?; 292 let scopes = self.scopes.as_ref()?;
290 let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax())?; 293 let scope = scope_for(scopes, source_map, Source::new(self.file_id, name_ref.syntax()))?;
291 let entry = scopes.resolve_name_in_scope(scope, &name)?; 294 let entry = scopes.resolve_name_in_scope(scope, &name)?;
292 Some(ScopeEntryWithSyntax { 295 Some(ScopeEntryWithSyntax {
293 name: entry.name().clone(), 296 name: entry.name().clone(),
@@ -408,20 +411,19 @@ impl SourceAnalyzer {
408fn scope_for( 411fn scope_for(
409 scopes: &ExprScopes, 412 scopes: &ExprScopes,
410 source_map: &BodySourceMap, 413 source_map: &BodySourceMap,
411 file_id: HirFileId, 414 node: Source<&SyntaxNode>,
412 node: &SyntaxNode,
413) -> Option<ScopeId> { 415) -> Option<ScopeId> {
414 node.ancestors() 416 node.ast
417 .ancestors()
415 .filter_map(ast::Expr::cast) 418 .filter_map(ast::Expr::cast)
416 .filter_map(|it| source_map.node_expr(Source { file_id, ast: &it })) 419 .filter_map(|it| source_map.node_expr(Source::new(node.file_id, &it)))
417 .find_map(|it| scopes.scope_for(it)) 420 .find_map(|it| scopes.scope_for(it))
418} 421}
419 422
420fn scope_for_offset( 423fn scope_for_offset(
421 scopes: &ExprScopes, 424 scopes: &ExprScopes,
422 source_map: &BodySourceMap, 425 source_map: &BodySourceMap,
423 file_id: HirFileId, 426 offset: Source<TextUnit>,
424 offset: TextUnit,
425) -> Option<ScopeId> { 427) -> Option<ScopeId> {
426 scopes 428 scopes
427 .scope_by_expr() 429 .scope_by_expr()
@@ -429,7 +431,7 @@ fn scope_for_offset(
429 .filter_map(|(id, scope)| { 431 .filter_map(|(id, scope)| {
430 let source = source_map.expr_syntax(*id)?; 432 let source = source_map.expr_syntax(*id)?;
431 // FIXME: correctly handle macro expansion 433 // FIXME: correctly handle macro expansion
432 if source.file_id != file_id { 434 if source.file_id != offset.file_id {
433 return None; 435 return None;
434 } 436 }
435 let syntax_node_ptr = 437 let syntax_node_ptr =
@@ -438,9 +440,14 @@ fn scope_for_offset(
438 }) 440 })
439 // find containing scope 441 // find containing scope
440 .min_by_key(|(ptr, _scope)| { 442 .min_by_key(|(ptr, _scope)| {
441 (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len()) 443 (
444 !(ptr.range().start() <= offset.ast && offset.ast <= ptr.range().end()),
445 ptr.range().len(),
446 )
447 })
448 .map(|(ptr, scope)| {
449 adjust(scopes, source_map, ptr, offset.file_id, offset.ast).unwrap_or(*scope)
442 }) 450 })
443 .map(|(ptr, scope)| adjust(scopes, source_map, ptr, file_id, offset).unwrap_or(*scope))
444} 451}
445 452
446// XXX: during completion, cursor might be outside of any particular 453// XXX: during completion, cursor might be outside of any particular
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 437d73e94..26531cb05 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -223,9 +223,12 @@ impl<N: AstNode> AstId<N> {
223 } 223 }
224} 224}
225 225
226/// FIXME: https://github.com/matklad/with ?
226#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 227#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
227pub struct Source<T> { 228pub struct Source<T> {
228 pub file_id: HirFileId, 229 pub file_id: HirFileId,
230 // FIXME: this stores all kind of things, not only `ast`.
231 // There should be a better name...
229 pub ast: T, 232 pub ast: T,
230} 233}
231 234
@@ -234,11 +237,16 @@ impl<T> Source<T> {
234 Source { file_id, ast } 237 Source { file_id, ast }
235 } 238 }
236 239
240 // Similarly, naming here is stupid...
241 pub fn with_ast<U>(&self, ast: U) -> Source<U> {
242 Source::new(self.file_id, ast)
243 }
244
237 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { 245 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
238 Source { file_id: self.file_id, ast: f(self.ast) } 246 Source::new(self.file_id, f(self.ast))
239 } 247 }
240 pub fn as_ref(&self) -> Source<&T> { 248 pub fn as_ref(&self) -> Source<&T> {
241 Source { file_id: self.file_id, ast: &self.ast } 249 self.with_ast(&self.ast)
242 } 250 }
243 pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode { 251 pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
244 db.parse_or_expand(self.file_id).expect("source created from invalid file") 252 db.parse_or_expand(self.file_id).expect("source created from invalid file")