aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/body
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/body')
-rw-r--r--crates/ra_hir_def/src/body/lower.rs151
-rw-r--r--crates/ra_hir_def/src/body/scope.rs140
2 files changed, 196 insertions, 95 deletions
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index f159f80af..a7e2e0982 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -27,6 +27,7 @@ use crate::{
27 LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, 27 LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
28 }, 28 },
29 item_scope::BuiltinShadowMode, 29 item_scope::BuiltinShadowMode,
30 item_tree::{ItemTree, ItemTreeId, ItemTreeNode},
30 path::{GenericArgs, Path}, 31 path::{GenericArgs, Path},
31 type_ref::{Mutability, Rawness, TypeRef}, 32 type_ref::{Mutability, Rawness, TypeRef},
32 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, 33 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId,
@@ -35,6 +36,8 @@ use crate::{
35 36
36use super::{ExprSource, PatSource}; 37use super::{ExprSource, PatSource};
37use ast::AstChildren; 38use ast::AstChildren;
39use rustc_hash::FxHashMap;
40use std::{any::type_name, sync::Arc};
38 41
39pub(crate) struct LowerCtx { 42pub(crate) struct LowerCtx {
40 hygiene: Hygiene, 43 hygiene: Hygiene,
@@ -60,10 +63,10 @@ pub(super) fn lower(
60 params: Option<ast::ParamList>, 63 params: Option<ast::ParamList>,
61 body: Option<ast::Expr>, 64 body: Option<ast::Expr>,
62) -> (Body, BodySourceMap) { 65) -> (Body, BodySourceMap) {
66 let item_tree = db.item_tree(expander.current_file_id);
63 ExprCollector { 67 ExprCollector {
64 db, 68 db,
65 def, 69 def,
66 expander,
67 source_map: BodySourceMap::default(), 70 source_map: BodySourceMap::default(),
68 body: Body { 71 body: Body {
69 exprs: Arena::default(), 72 exprs: Arena::default(),
@@ -72,6 +75,12 @@ pub(super) fn lower(
72 body_expr: dummy_expr_id(), 75 body_expr: dummy_expr_id(),
73 item_scope: Default::default(), 76 item_scope: Default::default(),
74 }, 77 },
78 item_trees: {
79 let mut map = FxHashMap::default();
80 map.insert(expander.current_file_id, item_tree);
81 map
82 },
83 expander,
75 } 84 }
76 .collect(params, body) 85 .collect(params, body)
77} 86}
@@ -82,6 +91,8 @@ struct ExprCollector<'a> {
82 expander: Expander, 91 expander: Expander,
83 body: Body, 92 body: Body,
84 source_map: BodySourceMap, 93 source_map: BodySourceMap,
94
95 item_trees: FxHashMap<HirFileId, Arc<ItemTree>>,
85} 96}
86 97
87impl ExprCollector<'_> { 98impl ExprCollector<'_> {
@@ -533,6 +544,9 @@ impl ExprCollector<'_> {
533 self.source_map 544 self.source_map
534 .expansions 545 .expansions
535 .insert(macro_call, self.expander.current_file_id); 546 .insert(macro_call, self.expander.current_file_id);
547
548 let item_tree = self.db.item_tree(self.expander.current_file_id);
549 self.item_trees.insert(self.expander.current_file_id, item_tree);
536 let id = self.collect_expr(expansion); 550 let id = self.collect_expr(expansion);
537 self.expander.exit(self.db, mark); 551 self.expander.exit(self.db, mark);
538 id 552 id
@@ -547,6 +561,32 @@ impl ExprCollector<'_> {
547 } 561 }
548 } 562 }
549 563
564 fn find_inner_item<N: ItemTreeNode>(&self, ast: &N::Source) -> Option<ItemTreeId<N>> {
565 let id = self.expander.ast_id(ast);
566 let tree = &self.item_trees[&id.file_id];
567
568 // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes
569
570 // Root file (non-macro).
571 let item_tree_id = tree
572 .all_inner_items()
573 .chain(tree.top_level_items().iter().copied())
574 .filter_map(|mod_item| mod_item.downcast::<N>())
575 .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value.upcast())
576 .or_else(|| {
577 log::debug!(
578 "couldn't find inner {} item for {:?} (AST: `{}` - {:?})",
579 type_name::<N>(),
580 id,
581 ast.syntax(),
582 ast.syntax(),
583 );
584 None
585 })?;
586
587 Some(ItemTreeId::new(id.file_id, item_tree_id))
588 }
589
550 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { 590 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
551 if let Some(expr) = expr { 591 if let Some(expr) = expr {
552 self.collect_expr(expr) 592 self.collect_expr(expr)
@@ -578,56 +618,65 @@ impl ExprCollector<'_> {
578 618
579 fn collect_block_items(&mut self, block: &ast::BlockExpr) { 619 fn collect_block_items(&mut self, block: &ast::BlockExpr) {
580 let container = ContainerId::DefWithBodyId(self.def); 620 let container = ContainerId::DefWithBodyId(self.def);
581 for item in block.items() { 621
582 let (def, name): (ModuleDefId, Option<ast::Name>) = match item { 622 let items = block
583 ast::ModuleItem::FnDef(def) => { 623 .items()
584 let ast_id = self.expander.ast_id(&def); 624 .filter_map(|item| {
585 ( 625 let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
586 FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(), 626 ast::ModuleItem::FnDef(def) => {
587 def.name(), 627 let id = self.find_inner_item(&def)?;
588 ) 628 (
589 } 629 FunctionLoc { container: container.into(), id }.intern(self.db).into(),
590 ast::ModuleItem::TypeAliasDef(def) => { 630 def.name(),
591 let ast_id = self.expander.ast_id(&def); 631 )
592 ( 632 }
593 TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(), 633 ast::ModuleItem::TypeAliasDef(def) => {
594 def.name(), 634 let id = self.find_inner_item(&def)?;
595 ) 635 (
596 } 636 TypeAliasLoc { container: container.into(), id }.intern(self.db).into(),
597 ast::ModuleItem::ConstDef(def) => { 637 def.name(),
598 let ast_id = self.expander.ast_id(&def); 638 )
599 ( 639 }
600 ConstLoc { container: container.into(), ast_id }.intern(self.db).into(), 640 ast::ModuleItem::ConstDef(def) => {
601 def.name(), 641 let id = self.find_inner_item(&def)?;
602 ) 642 (
603 } 643 ConstLoc { container: container.into(), id }.intern(self.db).into(),
604 ast::ModuleItem::StaticDef(def) => { 644 def.name(),
605 let ast_id = self.expander.ast_id(&def); 645 )
606 (StaticLoc { container, ast_id }.intern(self.db).into(), def.name()) 646 }
607 } 647 ast::ModuleItem::StaticDef(def) => {
608 ast::ModuleItem::StructDef(def) => { 648 let id = self.find_inner_item(&def)?;
609 let ast_id = self.expander.ast_id(&def); 649 (StaticLoc { container, id }.intern(self.db).into(), def.name())
610 (StructLoc { container, ast_id }.intern(self.db).into(), def.name()) 650 }
611 } 651 ast::ModuleItem::StructDef(def) => {
612 ast::ModuleItem::EnumDef(def) => { 652 let id = self.find_inner_item(&def)?;
613 let ast_id = self.expander.ast_id(&def); 653 (StructLoc { container, id }.intern(self.db).into(), def.name())
614 (EnumLoc { container, ast_id }.intern(self.db).into(), def.name()) 654 }
615 } 655 ast::ModuleItem::EnumDef(def) => {
616 ast::ModuleItem::UnionDef(def) => { 656 let id = self.find_inner_item(&def)?;
617 let ast_id = self.expander.ast_id(&def); 657 (EnumLoc { container, id }.intern(self.db).into(), def.name())
618 (UnionLoc { container, ast_id }.intern(self.db).into(), def.name()) 658 }
619 } 659 ast::ModuleItem::UnionDef(def) => {
620 ast::ModuleItem::TraitDef(def) => { 660 let id = self.find_inner_item(&def)?;
621 let ast_id = self.expander.ast_id(&def); 661 (UnionLoc { container, id }.intern(self.db).into(), def.name())
622 (TraitLoc { container, ast_id }.intern(self.db).into(), def.name()) 662 }
623 } 663 ast::ModuleItem::TraitDef(def) => {
624 ast::ModuleItem::ExternBlock(_) => continue, // FIXME: collect from extern blocks 664 let id = self.find_inner_item(&def)?;
625 ast::ModuleItem::ImplDef(_) 665 (TraitLoc { container, id }.intern(self.db).into(), def.name())
626 | ast::ModuleItem::UseItem(_) 666 }
627 | ast::ModuleItem::ExternCrateItem(_) 667 ast::ModuleItem::ExternBlock(_) => return None, // FIXME: collect from extern blocks
628 | ast::ModuleItem::Module(_) 668 ast::ModuleItem::ImplDef(_)
629 | ast::ModuleItem::MacroCall(_) => continue, 669 | ast::ModuleItem::UseItem(_)
630 }; 670 | ast::ModuleItem::ExternCrateItem(_)
671 | ast::ModuleItem::Module(_)
672 | ast::ModuleItem::MacroCall(_) => return None,
673 };
674
675 Some((def, name))
676 })
677 .collect::<Vec<_>>();
678
679 for (def, name) in items {
631 self.body.item_scope.define_def(def); 680 self.body.item_scope.define_def(def);
632 if let Some(name) = name { 681 if let Some(name) = name {
633 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly 682 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
index e48ff38f9..99e876683 100644
--- a/crates/ra_hir_def/src/body/scope.rs
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -87,15 +87,13 @@ impl ExprScopes {
87 } 87 }
88 88
89 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { 89 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
90 match &body[pat] { 90 let pattern = &body[pat];
91 Pat::Bind { name, .. } => { 91 if let Pat::Bind { name, .. } = pattern {
92 // bind can have a sub pattern, but it's actually not allowed 92 let entry = ScopeEntry { name: name.clone(), pat };
93 // to bind to things in there 93 self.scopes[scope].entries.push(entry);
94 let entry = ScopeEntry { name: name.clone(), pat };
95 self.scopes[scope].entries.push(entry)
96 }
97 p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)),
98 } 94 }
95
96 pattern.walk_child_pats(|pat| self.add_bindings(body, scope, pat));
99 } 97 }
100 98
101 fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) { 99 fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) {
@@ -190,21 +188,23 @@ mod tests {
190 } 188 }
191 } 189 }
192 190
193 fn do_check(code: &str, expected: &[&str]) { 191 fn do_check(ra_fixture: &str, expected: &[&str]) {
194 let (off, code) = extract_offset(code); 192 let (offset, code) = extract_offset(ra_fixture);
195 let code = { 193 let code = {
196 let mut buf = String::new(); 194 let mut buf = String::new();
197 let off: usize = off.into(); 195 let off: usize = offset.into();
198 buf.push_str(&code[..off]); 196 buf.push_str(&code[..off]);
199 buf.push_str("marker"); 197 buf.push_str("<|>marker");
200 buf.push_str(&code[off..]); 198 buf.push_str(&code[off..]);
201 buf 199 buf
202 }; 200 };
203 201
204 let (db, file_id) = TestDB::with_single_file(&code); 202 let (db, position) = TestDB::with_position(&code);
203 let file_id = position.file_id;
204 let offset = position.offset;
205 205
206 let file_syntax = db.parse(file_id).syntax_node(); 206 let file_syntax = db.parse(file_id).syntax_node();
207 let marker: ast::PathExpr = find_node_at_offset(&file_syntax, off).unwrap(); 207 let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap();
208 let function = find_function(&db, file_id); 208 let function = find_function(&db, file_id);
209 209
210 let scopes = db.expr_scopes(function.into()); 210 let scopes = db.expr_scopes(function.into());
@@ -300,15 +300,65 @@ mod tests {
300 ); 300 );
301 } 301 }
302 302
303 fn do_check_local_name(code: &str, expected_offset: u32) { 303 #[test]
304 let (off, code) = extract_offset(code); 304 fn test_bindings_after_at() {
305 do_check(
306 r"
307fn foo() {
308 match Some(()) {
309 opt @ Some(unit) => {
310 <|>
311 }
312 _ => {}
313 }
314}
315",
316 &["opt", "unit"],
317 );
318 }
319
320 #[test]
321 fn macro_inner_item() {
322 do_check(
323 r"
324 macro_rules! mac {
325 () => {{
326 fn inner() {}
327 inner();
328 }};
329 }
330
331 fn foo() {
332 mac!();
333 <|>
334 }
335 ",
336 &[],
337 );
338 }
339
340 #[test]
341 fn broken_inner_item() {
342 do_check(
343 r"
344 fn foo() {
345 trait {}
346 <|>
347 }
348 ",
349 &[],
350 );
351 }
305 352
306 let (db, file_id) = TestDB::with_single_file(&code); 353 fn do_check_local_name(ra_fixture: &str, expected_offset: u32) {
354 let (db, position) = TestDB::with_position(ra_fixture);
355 let file_id = position.file_id;
356 let offset = position.offset;
307 357
308 let file = db.parse(file_id).ok().unwrap(); 358 let file = db.parse(file_id).ok().unwrap();
309 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) 359 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into())
310 .expect("failed to find a name at the target offset"); 360 .expect("failed to find a name at the target offset");
311 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); 361 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset).unwrap();
312 362
313 let function = find_function(&db, file_id); 363 let function = find_function(&db, file_id);
314 364
@@ -336,15 +386,16 @@ mod tests {
336 fn test_resolve_local_name() { 386 fn test_resolve_local_name() {
337 do_check_local_name( 387 do_check_local_name(
338 r#" 388 r#"
339 fn foo(x: i32, y: u32) { 389fn foo(x: i32, y: u32) {
340 { 390 {
341 let z = x * 2; 391 let z = x * 2;
342 } 392 }
343 { 393 {
344 let t = x<|> * 3; 394 let t = x<|> * 3;
345 } 395 }
346 }"#, 396}
347 21, 397"#,
398 7,
348 ); 399 );
349 } 400 }
350 401
@@ -352,10 +403,11 @@ mod tests {
352 fn test_resolve_local_name_declaration() { 403 fn test_resolve_local_name_declaration() {
353 do_check_local_name( 404 do_check_local_name(
354 r#" 405 r#"
355 fn foo(x: String) { 406fn foo(x: String) {
356 let x : &str = &x<|>; 407 let x : &str = &x<|>;
357 }"#, 408}
358 21, 409"#,
410 7,
359 ); 411 );
360 } 412 }
361 413
@@ -363,12 +415,12 @@ mod tests {
363 fn test_resolve_local_name_shadow() { 415 fn test_resolve_local_name_shadow() {
364 do_check_local_name( 416 do_check_local_name(
365 r" 417 r"
366 fn foo(x: String) { 418fn foo(x: String) {
367 let x : &str = &x; 419 let x : &str = &x;
368 x<|> 420 x<|>
369 } 421}
370 ", 422",
371 53, 423 28,
372 ); 424 );
373 } 425 }
374 426
@@ -376,13 +428,13 @@ mod tests {
376 fn ref_patterns_contribute_bindings() { 428 fn ref_patterns_contribute_bindings() {
377 do_check_local_name( 429 do_check_local_name(
378 r" 430 r"
379 fn foo() { 431fn foo() {
380 if let Some(&from) = bar() { 432 if let Some(&from) = bar() {
381 from<|>; 433 from<|>;
382 } 434 }
383 } 435}
384 ", 436",
385 53, 437 28,
386 ); 438 );
387 } 439 }
388 440