diff options
author | Jonas Schievink <[email protected]> | 2020-06-22 14:07:06 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2020-06-24 15:53:16 +0100 |
commit | 4b03b39d5b4b00daffb120a4d2d9ea4a55a9a7ac (patch) | |
tree | 85431e53ce86bbcf16ba9b38fcc5f2ad27378722 | |
parent | b94caeb88b4aab7219d4b2f5c8c6c668199247fb (diff) |
draw the rest of the owl
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 173 | ||||
-rw-r--r-- | crates/ra_hir_def/src/data.rs | 220 | ||||
-rw-r--r-- | crates/ra_hir_def/src/item_tree.rs | 133 | ||||
-rw-r--r-- | crates/ra_hir_def/src/item_tree/lower.rs | 271 | ||||
-rw-r--r-- | crates/ra_hir_def/src/item_tree/tests.rs | 254 | ||||
-rw-r--r-- | crates/ra_hir_def/src/lib.rs | 97 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 134 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests/mod_resolution.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir_def/src/src.rs | 31 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/ast_id_map.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 16 |
13 files changed, 953 insertions, 409 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index ffd5278ec..a379b9f49 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -31,10 +31,7 @@ use hir_ty::{ | |||
31 | }; | 31 | }; |
32 | use ra_db::{CrateId, CrateName, Edition, FileId}; | 32 | use ra_db::{CrateId, CrateName, Edition, FileId}; |
33 | use ra_prof::profile; | 33 | use ra_prof::profile; |
34 | use ra_syntax::{ | 34 | use ra_syntax::ast::{self, AttrsOwner, NameOwner}; |
35 | ast::{self, AttrsOwner, NameOwner}, | ||
36 | AstNode, | ||
37 | }; | ||
38 | use rustc_hash::FxHashSet; | 35 | use rustc_hash::FxHashSet; |
39 | 36 | ||
40 | use crate::{ | 37 | use crate::{ |
@@ -205,7 +202,8 @@ impl ModuleDef { | |||
205 | } | 202 | } |
206 | 203 | ||
207 | pub use hir_def::{ | 204 | pub use hir_def::{ |
208 | attr::Attrs, item_scope::ItemInNs, visibility::Visibility, AssocItemId, AssocItemLoc, | 205 | attr::Attrs, item_scope::ItemInNs, item_tree::ItemTreeNode, visibility::Visibility, |
206 | AssocItemId, AssocItemLoc, | ||
209 | }; | 207 | }; |
210 | 208 | ||
211 | impl Module { | 209 | impl Module { |
@@ -872,7 +870,7 @@ where | |||
872 | ID: Lookup<Data = AssocItemLoc<AST>>, | 870 | ID: Lookup<Data = AssocItemLoc<AST>>, |
873 | DEF: From<ID>, | 871 | DEF: From<ID>, |
874 | CTOR: FnOnce(DEF) -> AssocItem, | 872 | CTOR: FnOnce(DEF) -> AssocItem, |
875 | AST: AstNode, | 873 | AST: ItemTreeNode, |
876 | { | 874 | { |
877 | match id.lookup(db.upcast()).container { | 875 | match id.lookup(db.upcast()).container { |
878 | AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))), | 876 | AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))), |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 4f2350915..9c5272c2d 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -243,7 +243,7 @@ impl Body { | |||
243 | } | 243 | } |
244 | }; | 244 | }; |
245 | let expander = Expander::new(db, file_id, module); | 245 | let expander = Expander::new(db, file_id, module); |
246 | let (body, source_map) = Body::new(db, def, expander, params, body); | 246 | let (body, source_map) = Body::new(db, file_id, def, expander, params, body); |
247 | (Arc::new(body), Arc::new(source_map)) | 247 | (Arc::new(body), Arc::new(source_map)) |
248 | } | 248 | } |
249 | 249 | ||
@@ -253,12 +253,13 @@ impl Body { | |||
253 | 253 | ||
254 | fn new( | 254 | fn new( |
255 | db: &dyn DefDatabase, | 255 | db: &dyn DefDatabase, |
256 | file_id: HirFileId, | ||
256 | def: DefWithBodyId, | 257 | def: DefWithBodyId, |
257 | expander: Expander, | 258 | expander: Expander, |
258 | params: Option<ast::ParamList>, | 259 | params: Option<ast::ParamList>, |
259 | body: Option<ast::Expr>, | 260 | body: Option<ast::Expr>, |
260 | ) -> (Body, BodySourceMap) { | 261 | ) -> (Body, BodySourceMap) { |
261 | lower::lower(db, def, expander, params, body) | 262 | lower::lower(db, file_id, def, expander, params, body) |
262 | } | 263 | } |
263 | } | 264 | } |
264 | 265 | ||
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index f159f80af..e7cf80676 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -5,7 +5,7 @@ use either::Either; | |||
5 | use hir_expand::{ | 5 | use hir_expand::{ |
6 | hygiene::Hygiene, | 6 | hygiene::Hygiene, |
7 | name::{name, AsName, Name}, | 7 | name::{name, AsName, Name}, |
8 | HirFileId, MacroDefId, MacroDefKind, | 8 | AstId, HirFileId, MacroDefId, MacroDefKind, |
9 | }; | 9 | }; |
10 | use ra_arena::Arena; | 10 | use ra_arena::Arena; |
11 | use ra_syntax::{ | 11 | use ra_syntax::{ |
@@ -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::{FileItemTreeId, ItemTree, ItemTreeSource}, | ||
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,7 @@ use crate::{ | |||
35 | 36 | ||
36 | use super::{ExprSource, PatSource}; | 37 | use super::{ExprSource, PatSource}; |
37 | use ast::AstChildren; | 38 | use ast::AstChildren; |
39 | use std::sync::Arc; | ||
38 | 40 | ||
39 | pub(crate) struct LowerCtx { | 41 | pub(crate) struct LowerCtx { |
40 | hygiene: Hygiene, | 42 | hygiene: Hygiene, |
@@ -55,11 +57,13 @@ impl LowerCtx { | |||
55 | 57 | ||
56 | pub(super) fn lower( | 58 | pub(super) fn lower( |
57 | db: &dyn DefDatabase, | 59 | db: &dyn DefDatabase, |
60 | file_id: HirFileId, | ||
58 | def: DefWithBodyId, | 61 | def: DefWithBodyId, |
59 | expander: Expander, | 62 | expander: Expander, |
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(file_id); | ||
63 | ExprCollector { | 67 | ExprCollector { |
64 | db, | 68 | db, |
65 | def, | 69 | def, |
@@ -72,6 +76,7 @@ pub(super) fn lower( | |||
72 | body_expr: dummy_expr_id(), | 76 | body_expr: dummy_expr_id(), |
73 | item_scope: Default::default(), | 77 | item_scope: Default::default(), |
74 | }, | 78 | }, |
79 | item_trees: vec![(file_id, item_tree)], | ||
75 | } | 80 | } |
76 | .collect(params, body) | 81 | .collect(params, body) |
77 | } | 82 | } |
@@ -82,6 +87,8 @@ struct ExprCollector<'a> { | |||
82 | expander: Expander, | 87 | expander: Expander, |
83 | body: Body, | 88 | body: Body, |
84 | source_map: BodySourceMap, | 89 | source_map: BodySourceMap, |
90 | |||
91 | item_trees: Vec<(HirFileId, Arc<ItemTree>)>, | ||
85 | } | 92 | } |
86 | 93 | ||
87 | impl ExprCollector<'_> { | 94 | impl ExprCollector<'_> { |
@@ -533,6 +540,9 @@ impl ExprCollector<'_> { | |||
533 | self.source_map | 540 | self.source_map |
534 | .expansions | 541 | .expansions |
535 | .insert(macro_call, self.expander.current_file_id); | 542 | .insert(macro_call, self.expander.current_file_id); |
543 | |||
544 | let item_tree = self.db.item_tree(self.expander.current_file_id); | ||
545 | self.item_trees.push((self.expander.current_file_id, item_tree)); | ||
536 | let id = self.collect_expr(expansion); | 546 | let id = self.collect_expr(expansion); |
537 | self.expander.exit(self.db, mark); | 547 | self.expander.exit(self.db, mark); |
538 | id | 548 | id |
@@ -547,6 +557,21 @@ impl ExprCollector<'_> { | |||
547 | } | 557 | } |
548 | } | 558 | } |
549 | 559 | ||
560 | fn find_inner_item<S: ItemTreeSource>(&self, id: AstId<ast::ModuleItem>) -> FileItemTreeId<S> { | ||
561 | let index = | ||
562 | self.item_trees.iter().position(|(file, _)| *file == id.file_id).unwrap_or_else(|| { | ||
563 | panic!("couldn't find item tree for file {:?}", id.file_id); | ||
564 | }); | ||
565 | let tree = &self.item_trees[index].1; | ||
566 | |||
567 | // Root file (non-macro). | ||
568 | tree.all_inner_items() | ||
569 | .chain(tree.top_level_items().iter().copied()) | ||
570 | .filter_map(|mod_item| mod_item.downcast::<S>()) | ||
571 | .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value) | ||
572 | .unwrap() | ||
573 | } | ||
574 | |||
550 | fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { | 575 | fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { |
551 | if let Some(expr) = expr { | 576 | if let Some(expr) = expr { |
552 | self.collect_expr(expr) | 577 | self.collect_expr(expr) |
@@ -578,56 +603,102 @@ impl ExprCollector<'_> { | |||
578 | 603 | ||
579 | fn collect_block_items(&mut self, block: &ast::BlockExpr) { | 604 | fn collect_block_items(&mut self, block: &ast::BlockExpr) { |
580 | let container = ContainerId::DefWithBodyId(self.def); | 605 | let container = ContainerId::DefWithBodyId(self.def); |
581 | for item in block.items() { | 606 | |
582 | let (def, name): (ModuleDefId, Option<ast::Name>) = match item { | 607 | let items = block |
583 | ast::ModuleItem::FnDef(def) => { | 608 | .items() |
584 | let ast_id = self.expander.ast_id(&def); | 609 | .filter_map(|item| { |
585 | ( | 610 | let (def, name): (ModuleDefId, Option<ast::Name>) = match item { |
586 | FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(), | 611 | ast::ModuleItem::FnDef(def) => { |
587 | def.name(), | 612 | let ast_id = self.expander.ast_id(&def); |
588 | ) | 613 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); |
589 | } | 614 | ( |
590 | ast::ModuleItem::TypeAliasDef(def) => { | 615 | FunctionLoc { container: container.into(), id: ast_id.with_value(id) } |
591 | let ast_id = self.expander.ast_id(&def); | 616 | .intern(self.db) |
592 | ( | 617 | .into(), |
593 | TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(), | 618 | def.name(), |
594 | def.name(), | 619 | ) |
595 | ) | 620 | } |
596 | } | 621 | ast::ModuleItem::TypeAliasDef(def) => { |
597 | ast::ModuleItem::ConstDef(def) => { | 622 | let ast_id = self.expander.ast_id(&def); |
598 | let ast_id = self.expander.ast_id(&def); | 623 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); |
599 | ( | 624 | ( |
600 | ConstLoc { container: container.into(), ast_id }.intern(self.db).into(), | 625 | TypeAliasLoc { container: container.into(), id: ast_id.with_value(id) } |
601 | def.name(), | 626 | .intern(self.db) |
602 | ) | 627 | .into(), |
603 | } | 628 | def.name(), |
604 | ast::ModuleItem::StaticDef(def) => { | 629 | ) |
605 | let ast_id = self.expander.ast_id(&def); | 630 | } |
606 | (StaticLoc { container, ast_id }.intern(self.db).into(), def.name()) | 631 | ast::ModuleItem::ConstDef(def) => { |
607 | } | 632 | let ast_id = self.expander.ast_id(&def); |
608 | ast::ModuleItem::StructDef(def) => { | 633 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); |
609 | let ast_id = self.expander.ast_id(&def); | 634 | ( |
610 | (StructLoc { container, ast_id }.intern(self.db).into(), def.name()) | 635 | ConstLoc { container: container.into(), id: ast_id.with_value(id) } |
611 | } | 636 | .intern(self.db) |
612 | ast::ModuleItem::EnumDef(def) => { | 637 | .into(), |
613 | let ast_id = self.expander.ast_id(&def); | 638 | def.name(), |
614 | (EnumLoc { container, ast_id }.intern(self.db).into(), def.name()) | 639 | ) |
615 | } | 640 | } |
616 | ast::ModuleItem::UnionDef(def) => { | 641 | ast::ModuleItem::StaticDef(def) => { |
617 | let ast_id = self.expander.ast_id(&def); | 642 | let ast_id = self.expander.ast_id(&def); |
618 | (UnionLoc { container, ast_id }.intern(self.db).into(), def.name()) | 643 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); |
619 | } | 644 | ( |
620 | ast::ModuleItem::TraitDef(def) => { | 645 | StaticLoc { container, id: ast_id.with_value(id) } |
621 | let ast_id = self.expander.ast_id(&def); | 646 | .intern(self.db) |
622 | (TraitLoc { container, ast_id }.intern(self.db).into(), def.name()) | 647 | .into(), |
623 | } | 648 | def.name(), |
624 | ast::ModuleItem::ExternBlock(_) => continue, // FIXME: collect from extern blocks | 649 | ) |
625 | ast::ModuleItem::ImplDef(_) | 650 | } |
626 | | ast::ModuleItem::UseItem(_) | 651 | ast::ModuleItem::StructDef(def) => { |
627 | | ast::ModuleItem::ExternCrateItem(_) | 652 | let ast_id = self.expander.ast_id(&def); |
628 | | ast::ModuleItem::Module(_) | 653 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); |
629 | | ast::ModuleItem::MacroCall(_) => continue, | 654 | ( |
630 | }; | 655 | StructLoc { container, id: ast_id.with_value(id) } |
656 | .intern(self.db) | ||
657 | .into(), | ||
658 | def.name(), | ||
659 | ) | ||
660 | } | ||
661 | ast::ModuleItem::EnumDef(def) => { | ||
662 | let ast_id = self.expander.ast_id(&def); | ||
663 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); | ||
664 | ( | ||
665 | EnumLoc { container, id: ast_id.with_value(id) }.intern(self.db).into(), | ||
666 | def.name(), | ||
667 | ) | ||
668 | } | ||
669 | ast::ModuleItem::UnionDef(def) => { | ||
670 | let ast_id = self.expander.ast_id(&def); | ||
671 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); | ||
672 | ( | ||
673 | UnionLoc { container, id: ast_id.with_value(id) } | ||
674 | .intern(self.db) | ||
675 | .into(), | ||
676 | def.name(), | ||
677 | ) | ||
678 | } | ||
679 | ast::ModuleItem::TraitDef(def) => { | ||
680 | let ast_id = self.expander.ast_id(&def); | ||
681 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); | ||
682 | ( | ||
683 | TraitLoc { container, id: ast_id.with_value(id) } | ||
684 | .intern(self.db) | ||
685 | .into(), | ||
686 | def.name(), | ||
687 | ) | ||
688 | } | ||
689 | ast::ModuleItem::ExternBlock(_) => return None, // FIXME: collect from extern blocks | ||
690 | ast::ModuleItem::ImplDef(_) | ||
691 | | ast::ModuleItem::UseItem(_) | ||
692 | | ast::ModuleItem::ExternCrateItem(_) | ||
693 | | ast::ModuleItem::Module(_) | ||
694 | | ast::ModuleItem::MacroCall(_) => return None, | ||
695 | }; | ||
696 | |||
697 | Some((def, name)) | ||
698 | }) | ||
699 | .collect::<Vec<_>>(); | ||
700 | |||
701 | for (def, name) in items { | ||
631 | self.body.item_scope.define_def(def); | 702 | self.body.item_scope.define_def(def); |
632 | if let Some(name) = name { | 703 | if let Some(name) = name { |
633 | let vis = crate::visibility::Visibility::Public; // FIXME determine correctly | 704 | let vis = crate::visibility::Visibility::Public; // FIXME determine correctly |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 53599e74a..697fde3d2 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -5,24 +5,23 @@ use std::sync::Arc; | |||
5 | use hir_expand::{ | 5 | use hir_expand::{ |
6 | hygiene::Hygiene, | 6 | hygiene::Hygiene, |
7 | name::{name, AsName, Name}, | 7 | name::{name, AsName, Name}, |
8 | AstId, InFile, | 8 | InFile, |
9 | }; | 9 | }; |
10 | use ra_prof::profile; | 10 | use ra_prof::profile; |
11 | use ra_syntax::ast::{ | 11 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, TypeBoundsOwner, VisibilityOwner}; |
12 | self, AssocItem, AstNode, ModuleItemOwner, NameOwner, TypeAscriptionOwner, TypeBoundsOwner, | ||
13 | VisibilityOwner, | ||
14 | }; | ||
15 | 12 | ||
16 | use crate::{ | 13 | use crate::{ |
17 | attr::Attrs, | 14 | attr::Attrs, |
15 | body::Expander, | ||
18 | body::LowerCtx, | 16 | body::LowerCtx, |
19 | db::DefDatabase, | 17 | db::DefDatabase, |
18 | item_tree::{AssocItem, ItemTreeId, ModItem}, | ||
20 | path::{path, AssociatedTypeBinding, GenericArgs, Path}, | 19 | path::{path, AssociatedTypeBinding, GenericArgs, Path}, |
21 | src::HasSource, | 20 | src::HasSource, |
22 | type_ref::{Mutability, TypeBound, TypeRef}, | 21 | type_ref::{Mutability, TypeBound, TypeRef}, |
23 | visibility::RawVisibility, | 22 | visibility::RawVisibility, |
24 | AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, | 23 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, |
25 | ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | 24 | Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, |
26 | }; | 25 | }; |
27 | 26 | ||
28 | #[derive(Debug, Clone, PartialEq, Eq)] | 27 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -155,30 +154,24 @@ pub struct TraitData { | |||
155 | impl TraitData { | 154 | impl TraitData { |
156 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { | 155 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { |
157 | let tr_loc = tr.lookup(db); | 156 | let tr_loc = tr.lookup(db); |
158 | let src = tr_loc.source(db); | 157 | let item_tree = db.item_tree(tr_loc.id.file_id); |
159 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); | 158 | let tr_def = &item_tree[tr_loc.id.value]; |
160 | let auto = src.value.auto_token().is_some(); | 159 | let name = tr_def.name.clone(); |
160 | let auto = tr_def.auto; | ||
161 | let module_id = tr_loc.container.module(db); | 161 | let module_id = tr_loc.container.module(db); |
162 | |||
163 | let container = AssocContainerId::TraitId(tr); | 162 | let container = AssocContainerId::TraitId(tr); |
164 | let mut items = Vec::new(); | 163 | let mut expander = Expander::new(db, tr_loc.id.file_id, module_id); |
165 | 164 | ||
166 | if let Some(item_list) = src.value.item_list() { | 165 | let items = collect_items( |
167 | let mut expander = Expander::new(db, tr_loc.ast_id.file_id, module_id); | 166 | db, |
168 | items.extend(collect_items( | 167 | module_id, |
169 | db, | 168 | &mut expander, |
170 | &mut expander, | 169 | tr_def.items.iter().copied(), |
171 | item_list.assoc_items(), | 170 | tr_loc.id.file_id, |
172 | src.file_id, | 171 | container, |
173 | container, | 172 | 100, |
174 | )); | 173 | ); |
175 | items.extend(collect_items_in_macros( | 174 | |
176 | db, | ||
177 | &mut expander, | ||
178 | &src.with_value(item_list), | ||
179 | container, | ||
180 | )); | ||
181 | } | ||
182 | Arc::new(TraitData { name, items, auto }) | 175 | Arc::new(TraitData { name, items, auto }) |
183 | } | 176 | } |
184 | 177 | ||
@@ -209,33 +202,28 @@ impl ImplData { | |||
209 | pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { | 202 | pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { |
210 | let _p = profile("impl_data_query"); | 203 | let _p = profile("impl_data_query"); |
211 | let impl_loc = id.lookup(db); | 204 | let impl_loc = id.lookup(db); |
212 | let src = impl_loc.source(db); | ||
213 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
214 | 205 | ||
215 | let target_trait = src.value.target_trait().map(|it| TypeRef::from_ast(&lower_ctx, it)); | 206 | let item_tree = db.item_tree(impl_loc.id.file_id); |
216 | let target_type = TypeRef::from_ast_opt(&lower_ctx, src.value.target_type()); | 207 | let impl_def = &item_tree[impl_loc.id.value]; |
217 | let is_negative = src.value.excl_token().is_some(); | 208 | let target_trait = impl_def.target_trait.clone(); |
209 | let target_type = impl_def.target_type.clone(); | ||
210 | let is_negative = impl_def.is_negative; | ||
218 | let module_id = impl_loc.container.module(db); | 211 | let module_id = impl_loc.container.module(db); |
219 | let container = AssocContainerId::ImplId(id); | 212 | let container = AssocContainerId::ImplId(id); |
213 | let mut expander = Expander::new(db, impl_loc.id.file_id, module_id); | ||
220 | 214 | ||
221 | let mut items: Vec<AssocItemId> = Vec::new(); | 215 | let items = collect_items( |
222 | 216 | db, | |
223 | if let Some(item_list) = src.value.item_list() { | 217 | module_id, |
224 | let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id); | 218 | &mut expander, |
225 | items.extend( | 219 | impl_def.items.iter().copied(), |
226 | collect_items(db, &mut expander, item_list.assoc_items(), src.file_id, container) | 220 | impl_loc.id.file_id, |
227 | .into_iter() | 221 | container, |
228 | .map(|(_, item)| item), | 222 | 100, |
229 | ); | 223 | ); |
230 | items.extend( | 224 | let items = items.into_iter().map(|(_, item)| item).collect(); |
231 | collect_items_in_macros(db, &mut expander, &src.with_value(item_list), container) | ||
232 | .into_iter() | ||
233 | .map(|(_, item)| item), | ||
234 | ); | ||
235 | } | ||
236 | 225 | ||
237 | let res = ImplData { target_trait, target_type, items, is_negative }; | 226 | Arc::new(ImplData { target_trait, target_type, items, is_negative }) |
238 | Arc::new(res) | ||
239 | } | 227 | } |
240 | } | 228 | } |
241 | 229 | ||
@@ -295,28 +283,12 @@ impl StaticData { | |||
295 | } | 283 | } |
296 | } | 284 | } |
297 | 285 | ||
298 | fn collect_items_in_macros( | 286 | fn collect_items( |
299 | db: &dyn DefDatabase, | ||
300 | expander: &mut Expander, | ||
301 | impl_def: &InFile<ast::ItemList>, | ||
302 | container: AssocContainerId, | ||
303 | ) -> Vec<(Name, AssocItemId)> { | ||
304 | let mut res = Vec::new(); | ||
305 | |||
306 | // We set a limit to protect against infinite recursion | ||
307 | let limit = 100; | ||
308 | |||
309 | for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) { | ||
310 | res.extend(collect_items_in_macro(db, expander, m, container, limit)) | ||
311 | } | ||
312 | |||
313 | res | ||
314 | } | ||
315 | |||
316 | fn collect_items_in_macro( | ||
317 | db: &dyn DefDatabase, | 287 | db: &dyn DefDatabase, |
288 | module: ModuleId, | ||
318 | expander: &mut Expander, | 289 | expander: &mut Expander, |
319 | m: ast::MacroCall, | 290 | assoc_items: impl Iterator<Item = AssocItem>, |
291 | file_id: crate::HirFileId, | ||
320 | container: AssocContainerId, | 292 | container: AssocContainerId, |
321 | limit: usize, | 293 | limit: usize, |
322 | ) -> Vec<(Name, AssocItemId)> { | 294 | ) -> Vec<(Name, AssocItemId)> { |
@@ -324,62 +296,62 @@ fn collect_items_in_macro( | |||
324 | return Vec::new(); | 296 | return Vec::new(); |
325 | } | 297 | } |
326 | 298 | ||
327 | if let Some((mark, items)) = expander.enter_expand(db, None, m) { | 299 | let item_tree = db.item_tree(file_id); |
328 | let items: InFile<ast::MacroItems> = expander.to_source(items); | 300 | let cfg_options = db.crate_graph()[module.krate].cfg_options.clone(); |
329 | let mut res = collect_items( | ||
330 | db, | ||
331 | expander, | ||
332 | items.value.items().filter_map(|it| AssocItem::cast(it.syntax().clone())), | ||
333 | items.file_id, | ||
334 | container, | ||
335 | ); | ||
336 | |||
337 | // Recursive collect macros | ||
338 | // Note that ast::ModuleItem do not include ast::MacroCall | ||
339 | // We cannot use ModuleItemOwner::items here | ||
340 | for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) { | ||
341 | res.extend(collect_items_in_macro(db, expander, it, container, limit - 1)) | ||
342 | } | ||
343 | expander.exit(db, mark); | ||
344 | res | ||
345 | } else { | ||
346 | Vec::new() | ||
347 | } | ||
348 | } | ||
349 | 301 | ||
350 | fn collect_items( | 302 | let mut items = Vec::new(); |
351 | db: &dyn DefDatabase, | 303 | for item in assoc_items { |
352 | expander: &mut Expander, | 304 | match item { |
353 | assoc_items: impl Iterator<Item = AssocItem>, | 305 | AssocItem::Function(id) => { |
354 | file_id: crate::HirFileId, | 306 | let item = &item_tree[id]; |
355 | container: AssocContainerId, | 307 | if !item.attrs.is_cfg_enabled(&cfg_options) { |
356 | ) -> Vec<(Name, AssocItemId)> { | 308 | continue; |
357 | let items = db.ast_id_map(file_id); | ||
358 | |||
359 | assoc_items | ||
360 | .filter_map(|item_node| match item_node { | ||
361 | ast::AssocItem::FnDef(it) => { | ||
362 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | ||
363 | if !expander.is_cfg_enabled(&it) { | ||
364 | return None; | ||
365 | } | 309 | } |
366 | let def = FunctionLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } | 310 | let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); |
367 | .intern(db); | 311 | items.push((item.name.clone(), def.into())); |
368 | Some((name, def.into())) | ||
369 | } | 312 | } |
370 | ast::AssocItem::ConstDef(it) => { | 313 | // FIXME: cfg? |
371 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | 314 | AssocItem::Const(id) => { |
372 | let def = ConstLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } | 315 | let item = &item_tree[id]; |
373 | .intern(db); | 316 | let name = if let Some(name) = item.name.clone() { |
374 | Some((name, def.into())) | 317 | name |
318 | } else { | ||
319 | continue; | ||
320 | }; | ||
321 | let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); | ||
322 | items.push((name, def.into())); | ||
375 | } | 323 | } |
376 | ast::AssocItem::TypeAliasDef(it) => { | 324 | AssocItem::TypeAlias(id) => { |
377 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | 325 | let item = &item_tree[id]; |
378 | let def = | 326 | let def = TypeAliasLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); |
379 | TypeAliasLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } | 327 | items.push((item.name.clone(), def.into())); |
380 | .intern(db); | ||
381 | Some((name, def.into())) | ||
382 | } | 328 | } |
383 | }) | 329 | AssocItem::MacroCall(call) => { |
384 | .collect() | 330 | let call = &item_tree[call]; |
331 | let ast_id_map = db.ast_id_map(file_id); | ||
332 | let root = db.parse_or_expand(file_id).unwrap(); | ||
333 | let call = ast_id_map.get(call.ast_id).to_node(&root); | ||
334 | |||
335 | if let Some((mark, mac)) = expander.enter_expand(db, None, call) { | ||
336 | let src: InFile<ast::MacroItems> = expander.to_source(mac); | ||
337 | let item_tree = db.item_tree(src.file_id); | ||
338 | let iter = | ||
339 | item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item); | ||
340 | items.extend(collect_items( | ||
341 | db, | ||
342 | module, | ||
343 | expander, | ||
344 | iter, | ||
345 | src.file_id, | ||
346 | container, | ||
347 | limit - 1, | ||
348 | )); | ||
349 | |||
350 | expander.exit(db, mark); | ||
351 | } | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | |||
356 | items | ||
385 | } | 357 | } |
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index aca2503a0..9a5dd701e 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs | |||
@@ -1,6 +1,8 @@ | |||
1 | //! A simplified AST that only contains items. | 1 | //! A simplified AST that only contains items. |
2 | 2 | ||
3 | mod lower; | 3 | mod lower; |
4 | #[cfg(test)] | ||
5 | mod tests; | ||
4 | 6 | ||
5 | use std::{ | 7 | use std::{ |
6 | fmt::{self, Debug}, | 8 | fmt::{self, Debug}, |
@@ -31,16 +33,20 @@ use crate::{ | |||
31 | type_ref::{Mutability, TypeBound, TypeRef}, | 33 | type_ref::{Mutability, TypeBound, TypeRef}, |
32 | visibility::RawVisibility, | 34 | visibility::RawVisibility, |
33 | }; | 35 | }; |
36 | use smallvec::SmallVec; | ||
34 | 37 | ||
35 | /// The item tree of a source file. | 38 | /// The item tree of a source file. |
36 | #[derive(Debug, Default, Eq, PartialEq)] | 39 | #[derive(Debug, Eq, PartialEq)] |
37 | pub struct ItemTree { | 40 | pub struct ItemTree { |
41 | file_id: HirFileId, | ||
38 | top_level: Vec<ModItem>, | 42 | top_level: Vec<ModItem>, |
39 | top_attrs: Attrs, | 43 | top_attrs: Attrs, |
40 | attrs: FxHashMap<ModItem, Attrs>, | 44 | attrs: FxHashMap<ModItem, Attrs>, |
41 | empty_attrs: Attrs, | 45 | empty_attrs: Attrs, |
46 | inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>, | ||
42 | 47 | ||
43 | imports: Arena<Import>, | 48 | imports: Arena<Import>, |
49 | extern_crates: Arena<ExternCrate>, | ||
44 | functions: Arena<Function>, | 50 | functions: Arena<Function>, |
45 | structs: Arena<Struct>, | 51 | structs: Arena<Struct>, |
46 | fields: Arena<Field>, | 52 | fields: Arena<Field>, |
@@ -63,7 +69,7 @@ impl ItemTree { | |||
63 | let syntax = if let Some(node) = db.parse_or_expand(file_id) { | 69 | let syntax = if let Some(node) = db.parse_or_expand(file_id) { |
64 | node | 70 | node |
65 | } else { | 71 | } else { |
66 | return Default::default(); | 72 | return Arc::new(Self::empty(file_id)); |
67 | }; | 73 | }; |
68 | 74 | ||
69 | let hygiene = Hygiene::new(db.upcast(), file_id); | 75 | let hygiene = Hygiene::new(db.upcast(), file_id); |
@@ -80,20 +86,41 @@ impl ItemTree { | |||
80 | file_storage = file; | 86 | file_storage = file; |
81 | &file_storage | 87 | &file_storage |
82 | }, | 88 | }, |
83 | _ => return Default::default(), | 89 | _ => return Arc::new(Self::empty(file_id)), |
84 | } | 90 | } |
85 | }; | 91 | }; |
86 | 92 | ||
87 | let map = db.ast_id_map(file_id); | 93 | let ctx = lower::Ctx::new(db, hygiene, file_id); |
88 | let mut ctx = lower::Ctx { | 94 | let mut item_tree = ctx.lower(item_owner); |
89 | tree: ItemTree::default(), | 95 | item_tree.top_attrs = top_attrs.unwrap_or_default(); |
90 | hygiene, | 96 | Arc::new(item_tree) |
91 | file: file_id, | 97 | } |
92 | source_ast_id_map: map, | 98 | |
93 | body_ctx: crate::body::LowerCtx::new(db, file_id), | 99 | fn empty(file_id: HirFileId) -> Self { |
94 | }; | 100 | Self { |
95 | ctx.tree.top_attrs = top_attrs.unwrap_or_default(); | 101 | file_id, |
96 | Arc::new(ctx.lower(item_owner)) | 102 | top_level: Default::default(), |
103 | top_attrs: Default::default(), | ||
104 | attrs: Default::default(), | ||
105 | empty_attrs: Default::default(), | ||
106 | inner_items: Default::default(), | ||
107 | imports: Default::default(), | ||
108 | extern_crates: Default::default(), | ||
109 | functions: Default::default(), | ||
110 | structs: Default::default(), | ||
111 | fields: Default::default(), | ||
112 | unions: Default::default(), | ||
113 | enums: Default::default(), | ||
114 | variants: Default::default(), | ||
115 | consts: Default::default(), | ||
116 | statics: Default::default(), | ||
117 | traits: Default::default(), | ||
118 | impls: Default::default(), | ||
119 | type_aliases: Default::default(), | ||
120 | mods: Default::default(), | ||
121 | macro_calls: Default::default(), | ||
122 | exprs: Default::default(), | ||
123 | } | ||
97 | } | 124 | } |
98 | 125 | ||
99 | /// Returns an iterator over all items located at the top level of the `HirFileId` this | 126 | /// Returns an iterator over all items located at the top level of the `HirFileId` this |
@@ -110,17 +137,49 @@ impl ItemTree { | |||
110 | pub fn attrs(&self, of: ModItem) -> &Attrs { | 137 | pub fn attrs(&self, of: ModItem) -> &Attrs { |
111 | self.attrs.get(&of).unwrap_or(&self.empty_attrs) | 138 | self.attrs.get(&of).unwrap_or(&self.empty_attrs) |
112 | } | 139 | } |
140 | |||
141 | /// Returns the lowered inner items that `ast` corresponds to. | ||
142 | /// | ||
143 | /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered | ||
144 | /// to multiple items in the `ItemTree`. | ||
145 | pub fn inner_items(&self, ast: FileAstId<ast::ModuleItem>) -> &[ModItem] { | ||
146 | &self.inner_items[&ast] | ||
147 | } | ||
148 | |||
149 | pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ { | ||
150 | self.inner_items.values().flatten().copied() | ||
151 | } | ||
152 | |||
153 | pub fn source<S: ItemTreeSource>( | ||
154 | &self, | ||
155 | db: &dyn DefDatabase, | ||
156 | of: FileItemTreeId<S>, | ||
157 | ) -> S::Source { | ||
158 | // This unwrap cannot fail, since it has either succeeded above, or resulted in an empty | ||
159 | // ItemTree (in which case there is no valid `FileItemTreeId` to call this method with). | ||
160 | let root = db | ||
161 | .parse_or_expand(self.file_id) | ||
162 | .expect("parse_or_expand failed on constructed ItemTree"); | ||
163 | |||
164 | let id = self[of].ast_id(); | ||
165 | let map = db.ast_id_map(self.file_id); | ||
166 | let ptr = map.get(id); | ||
167 | ptr.to_node(&root) | ||
168 | } | ||
113 | } | 169 | } |
114 | 170 | ||
115 | /// Trait implemented by all nodes in the item tree. | 171 | /// Trait implemented by all nodes in the item tree. |
116 | pub trait ItemTreeNode: Clone { | 172 | pub trait ItemTreeNode: Clone { |
117 | /// Looks up an instance of `Self` in an item tree. | 173 | /// Looks up an instance of `Self` in an item tree. |
118 | fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self; | 174 | fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self; |
175 | |||
176 | /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type. | ||
177 | fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>>; | ||
119 | } | 178 | } |
120 | 179 | ||
121 | /// Trait for item tree nodes that allow accessing the original AST node. | 180 | /// Trait for item tree nodes that allow accessing the original AST node. |
122 | pub trait ItemTreeSource: ItemTreeNode { | 181 | pub trait ItemTreeSource: ItemTreeNode { |
123 | type Source: AstNode; | 182 | type Source: AstNode + Into<ast::ModuleItem>; |
124 | 183 | ||
125 | fn ast_id(&self) -> FileAstId<Self::Source>; | 184 | fn ast_id(&self) -> FileAstId<Self::Source>; |
126 | } | 185 | } |
@@ -164,12 +223,22 @@ macro_rules! nodes { | |||
164 | fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self { | 223 | fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self { |
165 | &tree.$fld[index] | 224 | &tree.$fld[index] |
166 | } | 225 | } |
226 | |||
227 | |||
228 | fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> { | ||
229 | if let ModItem::$node(id) = mod_item { | ||
230 | Some(id) | ||
231 | } else { | ||
232 | None | ||
233 | } | ||
234 | } | ||
167 | } | 235 | } |
168 | )+ }; | 236 | )+ }; |
169 | } | 237 | } |
170 | 238 | ||
171 | nodes!( | 239 | nodes!( |
172 | Import in imports, | 240 | Import in imports, |
241 | ExternCrate in extern_crates, | ||
173 | Function in functions, | 242 | Function in functions, |
174 | Struct in structs, | 243 | Struct in structs, |
175 | Union in unions, | 244 | Union in unions, |
@@ -196,6 +265,8 @@ macro_rules! source { | |||
196 | } | 265 | } |
197 | 266 | ||
198 | source! { | 267 | source! { |
268 | Import -> ast::UseItem, | ||
269 | ExternCrate -> ast::ExternCrateItem, | ||
199 | Function -> ast::FnDef, | 270 | Function -> ast::FnDef, |
200 | Struct -> ast::StructDef, | 271 | Struct -> ast::StructDef, |
201 | Union -> ast::UnionDef, | 272 | Union -> ast::UnionDef, |
@@ -248,7 +319,7 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | |||
248 | } | 319 | } |
249 | } | 320 | } |
250 | 321 | ||
251 | /// A desugared `extern crate` or `use` import. | 322 | /// A desugared `use` import. |
252 | #[derive(Debug, Clone, Eq, PartialEq)] | 323 | #[derive(Debug, Clone, Eq, PartialEq)] |
253 | pub struct Import { | 324 | pub struct Import { |
254 | pub path: ModPath, | 325 | pub path: ModPath, |
@@ -256,8 +327,19 @@ pub struct Import { | |||
256 | pub visibility: RawVisibility, | 327 | pub visibility: RawVisibility, |
257 | pub is_glob: bool, | 328 | pub is_glob: bool, |
258 | pub is_prelude: bool, | 329 | pub is_prelude: bool, |
259 | pub is_extern_crate: bool, | 330 | /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many |
331 | /// `Import`s can map to the same `use` item. | ||
332 | pub ast_id: FileAstId<ast::UseItem>, | ||
333 | } | ||
334 | |||
335 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
336 | pub struct ExternCrate { | ||
337 | pub path: ModPath, | ||
338 | pub alias: Option<ImportAlias>, | ||
339 | pub visibility: RawVisibility, | ||
340 | /// Whether this is a `#[macro_use] extern crate ...`. | ||
260 | pub is_macro_use: bool, | 341 | pub is_macro_use: bool, |
342 | pub ast_id: FileAstId<ast::ExternCrateItem>, | ||
261 | } | 343 | } |
262 | 344 | ||
263 | #[derive(Debug, Clone, Eq, PartialEq)] | 345 | #[derive(Debug, Clone, Eq, PartialEq)] |
@@ -270,7 +352,6 @@ pub struct Function { | |||
270 | pub params: Vec<TypeRef>, | 352 | pub params: Vec<TypeRef>, |
271 | pub ret_type: TypeRef, | 353 | pub ret_type: TypeRef, |
272 | pub ast_id: FileAstId<ast::FnDef>, | 354 | pub ast_id: FileAstId<ast::FnDef>, |
273 | // FIXME inner items | ||
274 | } | 355 | } |
275 | 356 | ||
276 | #[derive(Debug, Clone, Eq, PartialEq)] | 357 | #[derive(Debug, Clone, Eq, PartialEq)] |
@@ -412,6 +493,7 @@ macro_rules! impl_froms { | |||
412 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | 493 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] |
413 | pub enum ModItem { | 494 | pub enum ModItem { |
414 | Import(FileItemTreeId<Import>), | 495 | Import(FileItemTreeId<Import>), |
496 | ExternCrate(FileItemTreeId<ExternCrate>), | ||
415 | Function(FileItemTreeId<Function>), | 497 | Function(FileItemTreeId<Function>), |
416 | Struct(FileItemTreeId<Struct>), | 498 | Struct(FileItemTreeId<Struct>), |
417 | Union(FileItemTreeId<Union>), | 499 | Union(FileItemTreeId<Union>), |
@@ -429,6 +511,7 @@ impl ModItem { | |||
429 | pub fn as_assoc_item(&self) -> Option<AssocItem> { | 511 | pub fn as_assoc_item(&self) -> Option<AssocItem> { |
430 | match self { | 512 | match self { |
431 | ModItem::Import(_) | 513 | ModItem::Import(_) |
514 | | ModItem::ExternCrate(_) | ||
432 | | ModItem::Struct(_) | 515 | | ModItem::Struct(_) |
433 | | ModItem::Union(_) | 516 | | ModItem::Union(_) |
434 | | ModItem::Enum(_) | 517 | | ModItem::Enum(_) |
@@ -442,10 +525,15 @@ impl ModItem { | |||
442 | ModItem::Function(func) => Some(AssocItem::Function(*func)), | 525 | ModItem::Function(func) => Some(AssocItem::Function(*func)), |
443 | } | 526 | } |
444 | } | 527 | } |
528 | |||
529 | pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> { | ||
530 | N::id_from_mod_item(self) | ||
531 | } | ||
445 | } | 532 | } |
446 | 533 | ||
447 | impl_froms!(ModItem { | 534 | impl_froms!(ModItem { |
448 | Import(FileItemTreeId<Import>), | 535 | Import(FileItemTreeId<Import>), |
536 | ExternCrate(FileItemTreeId<ExternCrate>), | ||
449 | Function(FileItemTreeId<Function>), | 537 | Function(FileItemTreeId<Function>), |
450 | Struct(FileItemTreeId<Struct>), | 538 | Struct(FileItemTreeId<Struct>), |
451 | Union(FileItemTreeId<Union>), | 539 | Union(FileItemTreeId<Union>), |
@@ -474,6 +562,17 @@ impl_froms!(AssocItem { | |||
474 | MacroCall(FileItemTreeId<MacroCall>), | 562 | MacroCall(FileItemTreeId<MacroCall>), |
475 | }); | 563 | }); |
476 | 564 | ||
565 | impl From<AssocItem> for ModItem { | ||
566 | fn from(item: AssocItem) -> Self { | ||
567 | match item { | ||
568 | AssocItem::Function(it) => it.into(), | ||
569 | AssocItem::TypeAlias(it) => it.into(), | ||
570 | AssocItem::Const(it) => it.into(), | ||
571 | AssocItem::MacroCall(it) => it.into(), | ||
572 | } | ||
573 | } | ||
574 | } | ||
575 | |||
477 | #[derive(Debug, Eq, PartialEq)] | 576 | #[derive(Debug, Eq, PartialEq)] |
478 | pub struct Variant { | 577 | pub struct Variant { |
479 | pub name: Name, | 578 | pub name: Name, |
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 737a69c30..f2b8a9418 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs | |||
@@ -7,9 +7,12 @@ use crate::{ | |||
7 | }; | 7 | }; |
8 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; | 8 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; |
9 | use ra_arena::map::ArenaMap; | 9 | use ra_arena::map::ArenaMap; |
10 | use ra_syntax::ast::{self, ModuleItemOwner}; | 10 | use ra_syntax::{ |
11 | ast::{self, ModuleItemOwner}, | ||
12 | SyntaxNode, | ||
13 | }; | ||
11 | use smallvec::SmallVec; | 14 | use smallvec::SmallVec; |
12 | use std::sync::Arc; | 15 | use std::{mem, sync::Arc}; |
13 | 16 | ||
14 | fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> { | 17 | fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> { |
15 | FileItemTreeId { index, _p: PhantomData } | 18 | FileItemTreeId { index, _p: PhantomData } |
@@ -27,78 +30,81 @@ where | |||
27 | } | 30 | } |
28 | 31 | ||
29 | pub(super) struct Ctx { | 32 | pub(super) struct Ctx { |
30 | pub tree: ItemTree, | 33 | tree: ItemTree, |
31 | pub hygiene: Hygiene, | 34 | hygiene: Hygiene, |
32 | pub file: HirFileId, | 35 | file: HirFileId, |
33 | pub source_ast_id_map: Arc<AstIdMap>, | 36 | source_ast_id_map: Arc<AstIdMap>, |
34 | pub body_ctx: crate::body::LowerCtx, | 37 | body_ctx: crate::body::LowerCtx, |
38 | inner_items: Vec<ModItem>, | ||
35 | } | 39 | } |
36 | 40 | ||
37 | impl Ctx { | 41 | impl Ctx { |
42 | pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { | ||
43 | Self { | ||
44 | tree: ItemTree::empty(file), | ||
45 | hygiene, | ||
46 | file, | ||
47 | source_ast_id_map: db.ast_id_map(file), | ||
48 | body_ctx: crate::body::LowerCtx::new(db, file), | ||
49 | inner_items: Vec::new(), | ||
50 | } | ||
51 | } | ||
52 | |||
38 | pub(super) fn lower(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { | 53 | pub(super) fn lower(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { |
39 | self.tree.top_level = item_owner | 54 | self.tree.top_level = item_owner |
40 | .items() | 55 | .items() |
41 | .flat_map(|item| self.lower_mod_item(&item)) | 56 | .flat_map(|item| self.lower_mod_item(&item, false)) |
42 | .flat_map(|items| items.0) | 57 | .flat_map(|items| items.0) |
43 | .collect(); | 58 | .collect(); |
44 | self.tree | 59 | self.tree |
45 | } | 60 | } |
46 | 61 | ||
47 | fn lower_mod_item(&mut self, item: &ast::ModuleItem) -> Option<ModItems> { | 62 | fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option<ModItems> { |
63 | assert!(inner || self.inner_items.is_empty()); | ||
64 | |||
65 | // Collect inner items for 1-to-1-lowered items. | ||
66 | match item { | ||
67 | ast::ModuleItem::StructDef(_) | ||
68 | | ast::ModuleItem::UnionDef(_) | ||
69 | | ast::ModuleItem::EnumDef(_) | ||
70 | | ast::ModuleItem::FnDef(_) | ||
71 | | ast::ModuleItem::TypeAliasDef(_) | ||
72 | | ast::ModuleItem::ConstDef(_) | ||
73 | | ast::ModuleItem::StaticDef(_) | ||
74 | | ast::ModuleItem::MacroCall(_) => self.collect_inner_items(item.syntax()), | ||
75 | |||
76 | // These are handled in their respective `lower_X` method (since we can't just blindly | ||
77 | // walk them). | ||
78 | ast::ModuleItem::TraitDef(_) | ||
79 | | ast::ModuleItem::ImplDef(_) | ||
80 | | ast::ModuleItem::ExternBlock(_) => {} | ||
81 | |||
82 | // These don't have inner items. | ||
83 | ast::ModuleItem::Module(_) | ||
84 | | ast::ModuleItem::ExternCrateItem(_) | ||
85 | | ast::ModuleItem::UseItem(_) => {} | ||
86 | }; | ||
87 | |||
48 | let attrs = Attrs::new(item, &self.hygiene); | 88 | let attrs = Attrs::new(item, &self.hygiene); |
49 | let items = match item { | 89 | let items = match item { |
50 | ast::ModuleItem::StructDef(ast) => { | 90 | ast::ModuleItem::StructDef(ast) => self.lower_struct(ast).map(Into::into), |
51 | self.lower_struct(ast).map(|data| id(self.tree.structs.alloc(data)).into()) | 91 | ast::ModuleItem::UnionDef(ast) => self.lower_union(ast).map(Into::into), |
52 | } | 92 | ast::ModuleItem::EnumDef(ast) => self.lower_enum(ast).map(Into::into), |
53 | ast::ModuleItem::UnionDef(ast) => { | 93 | ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), |
54 | self.lower_union(ast).map(|data| id(self.tree.unions.alloc(data)).into()) | 94 | ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), |
55 | } | 95 | ast::ModuleItem::StaticDef(ast) => self.lower_static(ast).map(Into::into), |
56 | ast::ModuleItem::EnumDef(ast) => { | 96 | ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), |
57 | self.lower_enum(ast).map(|data| id(self.tree.enums.alloc(data)).into()) | 97 | ast::ModuleItem::Module(ast) => self.lower_module(ast).map(Into::into), |
58 | } | 98 | ast::ModuleItem::TraitDef(ast) => self.lower_trait(ast).map(Into::into), |
59 | ast::ModuleItem::FnDef(ast) => { | 99 | ast::ModuleItem::ImplDef(ast) => self.lower_impl(ast).map(Into::into), |
60 | self.lower_function(ast).map(|data| id(self.tree.functions.alloc(data)).into()) | ||
61 | } | ||
62 | ast::ModuleItem::TypeAliasDef(ast) => { | ||
63 | self.lower_type_alias(ast).map(|data| id(self.tree.type_aliases.alloc(data)).into()) | ||
64 | } | ||
65 | ast::ModuleItem::StaticDef(ast) => { | ||
66 | self.lower_static(ast).map(|data| id(self.tree.statics.alloc(data)).into()) | ||
67 | } | ||
68 | ast::ModuleItem::ConstDef(ast) => { | ||
69 | let data = self.lower_const(ast); | ||
70 | Some(id(self.tree.consts.alloc(data)).into()) | ||
71 | } | ||
72 | ast::ModuleItem::Module(ast) => { | ||
73 | self.lower_module(ast).map(|data| id(self.tree.mods.alloc(data)).into()) | ||
74 | } | ||
75 | ast::ModuleItem::TraitDef(ast) => { | ||
76 | self.lower_trait(ast).map(|data| id(self.tree.traits.alloc(data)).into()) | ||
77 | } | ||
78 | ast::ModuleItem::ImplDef(ast) => { | ||
79 | self.lower_impl(ast).map(|data| id(self.tree.impls.alloc(data)).into()) | ||
80 | } | ||
81 | ast::ModuleItem::UseItem(ast) => Some(ModItems( | 100 | ast::ModuleItem::UseItem(ast) => Some(ModItems( |
82 | self.lower_use(ast) | 101 | self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(), |
83 | .into_iter() | ||
84 | .map(|data| id(self.tree.imports.alloc(data)).into()) | ||
85 | .collect::<SmallVec<_>>(), | ||
86 | )), | 102 | )), |
87 | ast::ModuleItem::ExternCrateItem(ast) => { | 103 | ast::ModuleItem::ExternCrateItem(ast) => self.lower_extern_crate(ast).map(Into::into), |
88 | self.lower_extern_crate(ast).map(|data| id(self.tree.imports.alloc(data)).into()) | 104 | ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), |
105 | ast::ModuleItem::ExternBlock(ast) => { | ||
106 | Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>())) | ||
89 | } | 107 | } |
90 | ast::ModuleItem::MacroCall(ast) => { | ||
91 | self.lower_macro_call(ast).map(|data| id(self.tree.macro_calls.alloc(data)).into()) | ||
92 | } | ||
93 | ast::ModuleItem::ExternBlock(ast) => Some(ModItems( | ||
94 | self.lower_extern_block(ast) | ||
95 | .into_iter() | ||
96 | .map(|item| match item { | ||
97 | Either::Left(func) => id(self.tree.functions.alloc(func)).into(), | ||
98 | Either::Right(statik) => id(self.tree.statics.alloc(statik)).into(), | ||
99 | }) | ||
100 | .collect::<SmallVec<_>>(), | ||
101 | )), | ||
102 | }; | 108 | }; |
103 | 109 | ||
104 | if !attrs.is_empty() { | 110 | if !attrs.is_empty() { |
@@ -110,22 +116,28 @@ impl Ctx { | |||
110 | items | 116 | items |
111 | } | 117 | } |
112 | 118 | ||
113 | fn lower_assoc_item(&mut self, item: &ast::AssocItem) -> Option<AssocItem> { | 119 | fn collect_inner_items(&mut self, container: &SyntaxNode) { |
120 | let mut inner_items = mem::replace(&mut self.tree.inner_items, FxHashMap::default()); | ||
121 | inner_items.extend( | ||
122 | container.descendants().skip(1).filter_map(ast::ModuleItem::cast).filter_map(|item| { | ||
123 | let ast_id = self.source_ast_id_map.ast_id(&item); | ||
124 | Some((ast_id, self.lower_mod_item(&item, true)?.0)) | ||
125 | }), | ||
126 | ); | ||
127 | self.tree.inner_items = inner_items; | ||
128 | } | ||
129 | |||
130 | fn lower_assoc_item(&mut self, item: &ast::ModuleItem) -> Option<AssocItem> { | ||
114 | match item { | 131 | match item { |
115 | ast::AssocItem::FnDef(ast) => { | 132 | ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), |
116 | self.lower_function(ast).map(|data| id(self.tree.functions.alloc(data)).into()) | 133 | ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), |
117 | } | 134 | ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), |
118 | ast::AssocItem::TypeAliasDef(ast) => { | 135 | ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), |
119 | self.lower_type_alias(ast).map(|data| id(self.tree.type_aliases.alloc(data)).into()) | 136 | _ => None, |
120 | } | ||
121 | ast::AssocItem::ConstDef(ast) => { | ||
122 | let data = self.lower_const(ast); | ||
123 | Some(id(self.tree.consts.alloc(data)).into()) | ||
124 | } | ||
125 | } | 137 | } |
126 | } | 138 | } |
127 | 139 | ||
128 | fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option<Struct> { | 140 | fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option<FileItemTreeId<Struct>> { |
129 | let attrs = self.lower_attrs(strukt); | 141 | let attrs = self.lower_attrs(strukt); |
130 | let visibility = self.lower_visibility(strukt); | 142 | let visibility = self.lower_visibility(strukt); |
131 | let name = strukt.name()?.as_name(); | 143 | let name = strukt.name()?.as_name(); |
@@ -138,7 +150,7 @@ impl Ctx { | |||
138 | ast::StructKind::Unit => StructDefKind::Unit, | 150 | ast::StructKind::Unit => StructDefKind::Unit, |
139 | }; | 151 | }; |
140 | let res = Struct { name, attrs, visibility, generic_params, fields, ast_id, kind }; | 152 | let res = Struct { name, attrs, visibility, generic_params, fields, ast_id, kind }; |
141 | Some(res) | 153 | Some(id(self.tree.structs.alloc(res))) |
142 | } | 154 | } |
143 | 155 | ||
144 | fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { | 156 | fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { |
@@ -193,7 +205,7 @@ impl Ctx { | |||
193 | Some(res) | 205 | Some(res) |
194 | } | 206 | } |
195 | 207 | ||
196 | fn lower_union(&mut self, union: &ast::UnionDef) -> Option<Union> { | 208 | fn lower_union(&mut self, union: &ast::UnionDef) -> Option<FileItemTreeId<Union>> { |
197 | let attrs = self.lower_attrs(union); | 209 | let attrs = self.lower_attrs(union); |
198 | let visibility = self.lower_visibility(union); | 210 | let visibility = self.lower_visibility(union); |
199 | let name = union.name()?.as_name(); | 211 | let name = union.name()?.as_name(); |
@@ -206,10 +218,10 @@ impl Ctx { | |||
206 | }; | 218 | }; |
207 | let ast_id = self.source_ast_id_map.ast_id(union); | 219 | let ast_id = self.source_ast_id_map.ast_id(union); |
208 | let res = Union { name, attrs, visibility, generic_params, fields, ast_id }; | 220 | let res = Union { name, attrs, visibility, generic_params, fields, ast_id }; |
209 | Some(res) | 221 | Some(id(self.tree.unions.alloc(res))) |
210 | } | 222 | } |
211 | 223 | ||
212 | fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option<Enum> { | 224 | fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option<FileItemTreeId<Enum>> { |
213 | let attrs = self.lower_attrs(enum_); | 225 | let attrs = self.lower_attrs(enum_); |
214 | let visibility = self.lower_visibility(enum_); | 226 | let visibility = self.lower_visibility(enum_); |
215 | let name = enum_.name()?.as_name(); | 227 | let name = enum_.name()?.as_name(); |
@@ -220,7 +232,7 @@ impl Ctx { | |||
220 | }; | 232 | }; |
221 | let ast_id = self.source_ast_id_map.ast_id(enum_); | 233 | let ast_id = self.source_ast_id_map.ast_id(enum_); |
222 | let res = Enum { name, attrs, visibility, generic_params, variants, ast_id }; | 234 | let res = Enum { name, attrs, visibility, generic_params, variants, ast_id }; |
223 | Some(res) | 235 | Some(id(self.tree.enums.alloc(res))) |
224 | } | 236 | } |
225 | 237 | ||
226 | fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range<Idx<Variant>> { | 238 | fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range<Idx<Variant>> { |
@@ -241,7 +253,7 @@ impl Ctx { | |||
241 | Some(res) | 253 | Some(res) |
242 | } | 254 | } |
243 | 255 | ||
244 | fn lower_function(&mut self, func: &ast::FnDef) -> Option<Function> { | 256 | fn lower_function(&mut self, func: &ast::FnDef) -> Option<FileItemTreeId<Function>> { |
245 | let attrs = self.lower_attrs(func); | 257 | let attrs = self.lower_attrs(func); |
246 | let visibility = self.lower_visibility(func); | 258 | let visibility = self.lower_visibility(func); |
247 | let name = func.name()?.as_name(); | 259 | let name = func.name()?.as_name(); |
@@ -297,37 +309,42 @@ impl Ctx { | |||
297 | ast_id, | 309 | ast_id, |
298 | }; | 310 | }; |
299 | res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); | 311 | res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); |
300 | Some(res) | 312 | |
313 | Some(id(self.tree.functions.alloc(res))) | ||
301 | } | 314 | } |
302 | 315 | ||
303 | fn lower_type_alias(&mut self, type_alias: &ast::TypeAliasDef) -> Option<TypeAlias> { | 316 | fn lower_type_alias( |
317 | &mut self, | ||
318 | type_alias: &ast::TypeAliasDef, | ||
319 | ) -> Option<FileItemTreeId<TypeAlias>> { | ||
304 | let name = type_alias.name()?.as_name(); | 320 | let name = type_alias.name()?.as_name(); |
305 | let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); | 321 | let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); |
306 | let visibility = self.lower_visibility(type_alias); | 322 | let visibility = self.lower_visibility(type_alias); |
307 | let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); | 323 | let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); |
308 | let ast_id = self.source_ast_id_map.ast_id(type_alias); | 324 | let ast_id = self.source_ast_id_map.ast_id(type_alias); |
309 | let res = TypeAlias { name, visibility, generic_params, type_ref, ast_id }; | 325 | let res = TypeAlias { name, visibility, generic_params, type_ref, ast_id }; |
310 | Some(res) | 326 | Some(id(self.tree.type_aliases.alloc(res))) |
311 | } | 327 | } |
312 | 328 | ||
313 | fn lower_static(&mut self, static_: &ast::StaticDef) -> Option<Static> { | 329 | fn lower_static(&mut self, static_: &ast::StaticDef) -> Option<FileItemTreeId<Static>> { |
314 | let name = static_.name()?.as_name(); | 330 | let name = static_.name()?.as_name(); |
315 | let type_ref = self.lower_type_ref_opt(static_.ascribed_type()); | 331 | let type_ref = self.lower_type_ref_opt(static_.ascribed_type()); |
316 | let visibility = self.lower_visibility(static_); | 332 | let visibility = self.lower_visibility(static_); |
317 | let ast_id = self.source_ast_id_map.ast_id(static_); | 333 | let ast_id = self.source_ast_id_map.ast_id(static_); |
318 | let res = Static { name, visibility, type_ref, ast_id }; | 334 | let res = Static { name, visibility, type_ref, ast_id }; |
319 | Some(res) | 335 | Some(id(self.tree.statics.alloc(res))) |
320 | } | 336 | } |
321 | 337 | ||
322 | fn lower_const(&mut self, konst: &ast::ConstDef) -> Const { | 338 | fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId<Const> { |
323 | let name = konst.name().map(|it| it.as_name()); | 339 | let name = konst.name().map(|it| it.as_name()); |
324 | let type_ref = self.lower_type_ref_opt(konst.ascribed_type()); | 340 | let type_ref = self.lower_type_ref_opt(konst.ascribed_type()); |
325 | let visibility = self.lower_visibility(konst); | 341 | let visibility = self.lower_visibility(konst); |
326 | let ast_id = self.source_ast_id_map.ast_id(konst); | 342 | let ast_id = self.source_ast_id_map.ast_id(konst); |
327 | Const { name, visibility, type_ref, ast_id } | 343 | let res = Const { name, visibility, type_ref, ast_id }; |
344 | id(self.tree.consts.alloc(res)) | ||
328 | } | 345 | } |
329 | 346 | ||
330 | fn lower_module(&mut self, module: &ast::Module) -> Option<Mod> { | 347 | fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> { |
331 | let name = module.name()?.as_name(); | 348 | let name = module.name()?.as_name(); |
332 | let visibility = self.lower_visibility(module); | 349 | let visibility = self.lower_visibility(module); |
333 | let kind = if module.semicolon_token().is_some() { | 350 | let kind = if module.semicolon_token().is_some() { |
@@ -338,7 +355,7 @@ impl Ctx { | |||
338 | .item_list() | 355 | .item_list() |
339 | .map(|list| { | 356 | .map(|list| { |
340 | list.items() | 357 | list.items() |
341 | .flat_map(|item| self.lower_mod_item(&item)) | 358 | .flat_map(|item| self.lower_mod_item(&item, false)) |
342 | .flat_map(|items| items.0) | 359 | .flat_map(|items| items.0) |
343 | .collect() | 360 | .collect() |
344 | }) | 361 | }) |
@@ -349,90 +366,101 @@ impl Ctx { | |||
349 | } | 366 | } |
350 | }; | 367 | }; |
351 | let ast_id = self.source_ast_id_map.ast_id(module); | 368 | let ast_id = self.source_ast_id_map.ast_id(module); |
352 | Some(Mod { name, visibility, kind, ast_id }) | 369 | let res = Mod { name, visibility, kind, ast_id }; |
370 | Some(id(self.tree.mods.alloc(res))) | ||
353 | } | 371 | } |
354 | 372 | ||
355 | fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option<Trait> { | 373 | fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option<FileItemTreeId<Trait>> { |
356 | let name = trait_def.name()?.as_name(); | 374 | let name = trait_def.name()?.as_name(); |
357 | let visibility = self.lower_visibility(trait_def); | 375 | let visibility = self.lower_visibility(trait_def); |
358 | let generic_params = self.lower_generic_params(GenericsOwner::Trait(trait_def), trait_def); | 376 | let generic_params = self.lower_generic_params(GenericsOwner::Trait(trait_def), trait_def); |
359 | let auto = trait_def.auto_token().is_some(); | 377 | let auto = trait_def.auto_token().is_some(); |
360 | let items = trait_def.item_list().map(|list| { | 378 | let items = trait_def.item_list().map(|list| { |
361 | // FIXME: Does not handle macros | 379 | list.items() |
362 | list.assoc_items().flat_map(|item| self.lower_assoc_item(&item)).collect() | 380 | .flat_map(|item| { |
381 | self.collect_inner_items(item.syntax()); | ||
382 | self.lower_assoc_item(&item) | ||
383 | }) | ||
384 | .collect() | ||
363 | }); | 385 | }); |
364 | let ast_id = self.source_ast_id_map.ast_id(trait_def); | 386 | let ast_id = self.source_ast_id_map.ast_id(trait_def); |
365 | Some(Trait { | 387 | let res = Trait { |
366 | name, | 388 | name, |
367 | visibility, | 389 | visibility, |
368 | generic_params, | 390 | generic_params, |
369 | auto, | 391 | auto, |
370 | items: items.unwrap_or_default(), | 392 | items: items.unwrap_or_default(), |
371 | ast_id, | 393 | ast_id, |
372 | }) | 394 | }; |
395 | Some(id(self.tree.traits.alloc(res))) | ||
373 | } | 396 | } |
374 | 397 | ||
375 | fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option<Impl> { | 398 | fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option<FileItemTreeId<Impl>> { |
376 | let generic_params = self.lower_generic_params(GenericsOwner::Impl, impl_def); | 399 | let generic_params = self.lower_generic_params(GenericsOwner::Impl, impl_def); |
377 | let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); | 400 | let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); |
378 | let target_type = self.lower_type_ref(&impl_def.target_type()?); | 401 | let target_type = self.lower_type_ref(&impl_def.target_type()?); |
379 | let is_negative = impl_def.excl_token().is_some(); | 402 | let is_negative = impl_def.excl_token().is_some(); |
403 | |||
404 | // We cannot use `assoc_items()` here as that does not include macro calls. | ||
380 | let items = impl_def | 405 | let items = impl_def |
381 | .item_list()? | 406 | .item_list()? |
382 | .assoc_items() | 407 | .items() |
383 | .filter_map(|item| self.lower_assoc_item(&item)) | 408 | .filter_map(|item| { |
409 | self.collect_inner_items(item.syntax()); | ||
410 | let assoc = self.lower_assoc_item(&item)?; | ||
411 | Some(assoc) | ||
412 | }) | ||
384 | .collect(); | 413 | .collect(); |
385 | let ast_id = self.source_ast_id_map.ast_id(impl_def); | 414 | let ast_id = self.source_ast_id_map.ast_id(impl_def); |
386 | Some(Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }) | 415 | let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }; |
416 | Some(id(self.tree.impls.alloc(res))) | ||
387 | } | 417 | } |
388 | 418 | ||
389 | fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec<Import> { | 419 | fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec<FileItemTreeId<Import>> { |
390 | // FIXME: cfg_attr | 420 | // FIXME: cfg_attr |
391 | let is_prelude = use_item.has_atom_attr("prelude_import"); | 421 | let is_prelude = use_item.has_atom_attr("prelude_import"); |
392 | let visibility = self.lower_visibility(use_item); | 422 | let visibility = self.lower_visibility(use_item); |
423 | let ast_id = self.source_ast_id_map.ast_id(use_item); | ||
393 | 424 | ||
394 | // Every use item can expand to many `Import`s. | 425 | // Every use item can expand to many `Import`s. |
395 | let mut imports = Vec::new(); | 426 | let mut imports = Vec::new(); |
427 | let tree = &mut self.tree; | ||
396 | ModPath::expand_use_item( | 428 | ModPath::expand_use_item( |
397 | InFile::new(self.file, use_item.clone()), | 429 | InFile::new(self.file, use_item.clone()), |
398 | &self.hygiene, | 430 | &self.hygiene, |
399 | |path, _tree, is_glob, alias| { | 431 | |path, _tree, is_glob, alias| { |
400 | imports.push(Import { | 432 | imports.push(id(tree.imports.alloc(Import { |
401 | path, | 433 | path, |
402 | alias, | 434 | alias, |
403 | visibility: visibility.clone(), | 435 | visibility: visibility.clone(), |
404 | is_glob, | 436 | is_glob, |
405 | is_prelude, | 437 | is_prelude, |
406 | is_extern_crate: false, | 438 | ast_id, |
407 | is_macro_use: false, | 439 | }))); |
408 | }); | ||
409 | }, | 440 | }, |
410 | ); | 441 | ); |
411 | 442 | ||
412 | imports | 443 | imports |
413 | } | 444 | } |
414 | 445 | ||
415 | fn lower_extern_crate(&mut self, extern_crate: &ast::ExternCrateItem) -> Option<Import> { | 446 | fn lower_extern_crate( |
447 | &mut self, | ||
448 | extern_crate: &ast::ExternCrateItem, | ||
449 | ) -> Option<FileItemTreeId<ExternCrate>> { | ||
416 | let path = ModPath::from_name_ref(&extern_crate.name_ref()?); | 450 | let path = ModPath::from_name_ref(&extern_crate.name_ref()?); |
417 | let alias = extern_crate.alias().map(|a| { | 451 | let alias = extern_crate.alias().map(|a| { |
418 | a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) | 452 | a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) |
419 | }); | 453 | }); |
420 | let visibility = self.lower_visibility(extern_crate); | 454 | let visibility = self.lower_visibility(extern_crate); |
455 | let ast_id = self.source_ast_id_map.ast_id(extern_crate); | ||
421 | // FIXME: cfg_attr | 456 | // FIXME: cfg_attr |
422 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | 457 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); |
423 | 458 | ||
424 | Some(Import { | 459 | let res = ExternCrate { path, alias, visibility, is_macro_use, ast_id }; |
425 | path, | 460 | Some(id(self.tree.extern_crates.alloc(res))) |
426 | alias, | ||
427 | visibility, | ||
428 | is_glob: false, | ||
429 | is_prelude: false, | ||
430 | is_extern_crate: true, | ||
431 | is_macro_use, | ||
432 | }) | ||
433 | } | 461 | } |
434 | 462 | ||
435 | fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<MacroCall> { | 463 | fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { |
436 | let name = m.name().map(|it| it.as_name()); | 464 | let name = m.name().map(|it| it.as_name()); |
437 | let attrs = Attrs::new(m, &self.hygiene); | 465 | let attrs = Attrs::new(m, &self.hygiene); |
438 | let path = ModPath::from_src(m.path()?, &self.hygiene)?; | 466 | let path = ModPath::from_src(m.path()?, &self.hygiene)?; |
@@ -455,15 +483,26 @@ impl Ctx { | |||
455 | }; | 483 | }; |
456 | 484 | ||
457 | let is_builtin = attrs.by_key("rustc_builtin_macro").exists(); | 485 | let is_builtin = attrs.by_key("rustc_builtin_macro").exists(); |
458 | Some(MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id }) | 486 | let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id }; |
487 | Some(id(self.tree.macro_calls.alloc(res))) | ||
459 | } | 488 | } |
460 | 489 | ||
461 | fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<Either<Function, Static>> { | 490 | fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> { |
462 | block.extern_item_list().map_or(Vec::new(), |list| { | 491 | block.extern_item_list().map_or(Vec::new(), |list| { |
463 | list.extern_items() | 492 | list.extern_items() |
464 | .filter_map(|item| match item { | 493 | .filter_map(|item| { |
465 | ast::ExternItem::FnDef(ast) => self.lower_function(&ast).map(Either::Left), | 494 | self.collect_inner_items(item.syntax()); |
466 | ast::ExternItem::StaticDef(ast) => self.lower_static(&ast).map(Either::Right), | 495 | let id = match item { |
496 | ast::ExternItem::FnDef(ast) => { | ||
497 | let func = self.lower_function(&ast)?; | ||
498 | func.into() | ||
499 | } | ||
500 | ast::ExternItem::StaticDef(ast) => { | ||
501 | let statik = self.lower_static(&ast)?; | ||
502 | statik.into() | ||
503 | } | ||
504 | }; | ||
505 | Some(id) | ||
467 | }) | 506 | }) |
468 | .collect() | 507 | .collect() |
469 | }) | 508 | }) |
diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs new file mode 100644 index 000000000..b60e6cbb0 --- /dev/null +++ b/crates/ra_hir_def/src/item_tree/tests.rs | |||
@@ -0,0 +1,254 @@ | |||
1 | use super::{ItemTree, ModItem, ModKind}; | ||
2 | use crate::{db::DefDatabase, test_db::TestDB}; | ||
3 | use hir_expand::db::AstDatabase; | ||
4 | use insta::assert_snapshot; | ||
5 | use ra_db::fixture::WithFixture; | ||
6 | use ra_syntax::{ast, AstNode}; | ||
7 | use rustc_hash::FxHashSet; | ||
8 | use std::sync::Arc; | ||
9 | use stdx::format_to; | ||
10 | |||
11 | fn test_inner_items(ra_fixture: &str) { | ||
12 | let (db, file_id) = TestDB::with_single_file(ra_fixture); | ||
13 | let tree = db.item_tree(file_id.into()); | ||
14 | let root = db.parse_or_expand(file_id.into()).unwrap(); | ||
15 | let ast_id_map = db.ast_id_map(file_id.into()); | ||
16 | |||
17 | // Traverse the item tree and collect all module/impl/trait-level items as AST nodes. | ||
18 | let mut outer_items = FxHashSet::default(); | ||
19 | let mut worklist = tree.top_level_items().to_vec(); | ||
20 | while let Some(item) = worklist.pop() { | ||
21 | let node: ast::ModuleItem = match item { | ||
22 | ModItem::Import(it) => tree.source(&db, it).into(), | ||
23 | ModItem::ExternCrate(it) => tree.source(&db, it).into(), | ||
24 | ModItem::Function(it) => tree.source(&db, it).into(), | ||
25 | ModItem::Struct(it) => tree.source(&db, it).into(), | ||
26 | ModItem::Union(it) => tree.source(&db, it).into(), | ||
27 | ModItem::Enum(it) => tree.source(&db, it).into(), | ||
28 | ModItem::Const(it) => tree.source(&db, it).into(), | ||
29 | ModItem::Static(it) => tree.source(&db, it).into(), | ||
30 | ModItem::TypeAlias(it) => tree.source(&db, it).into(), | ||
31 | ModItem::Mod(it) => { | ||
32 | if let ModKind::Inline { items } = &tree[it].kind { | ||
33 | worklist.extend(items); | ||
34 | } | ||
35 | tree.source(&db, it).into() | ||
36 | } | ||
37 | ModItem::Trait(it) => { | ||
38 | worklist.extend(tree[it].items.iter().map(|item| ModItem::from(*item))); | ||
39 | tree.source(&db, it).into() | ||
40 | } | ||
41 | ModItem::Impl(it) => { | ||
42 | worklist.extend(tree[it].items.iter().map(|item| ModItem::from(*item))); | ||
43 | tree.source(&db, it).into() | ||
44 | } | ||
45 | ModItem::MacroCall(_) => continue, | ||
46 | }; | ||
47 | |||
48 | outer_items.insert(node); | ||
49 | } | ||
50 | |||
51 | // Now descend the root node and check that all `ast::ModuleItem`s are either recorded above, or | ||
52 | // registered as inner items. | ||
53 | for item in root.descendants().skip(1).filter_map(ast::ModuleItem::cast) { | ||
54 | if outer_items.contains(&item) { | ||
55 | continue; | ||
56 | } | ||
57 | |||
58 | let ast_id = ast_id_map.ast_id(&item); | ||
59 | assert!(!tree.inner_items(ast_id).is_empty()); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | fn item_tree(ra_fixture: &str) -> Arc<ItemTree> { | ||
64 | let (db, file_id) = TestDB::with_single_file(ra_fixture); | ||
65 | db.item_tree(file_id.into()) | ||
66 | } | ||
67 | |||
68 | fn print_item_tree(ra_fixture: &str) -> String { | ||
69 | let tree = item_tree(ra_fixture); | ||
70 | let mut out = String::new(); | ||
71 | |||
72 | format_to!(out, "inner attrs: {:?}\n\n", tree.top_level_attrs()); | ||
73 | format_to!(out, "top-level items:\n"); | ||
74 | for item in tree.top_level_items() { | ||
75 | fmt_mod_item(&mut out, &tree, *item); | ||
76 | format_to!(out, "\n"); | ||
77 | } | ||
78 | |||
79 | if !tree.inner_items.is_empty() { | ||
80 | format_to!(out, "\ninner items:\n"); | ||
81 | for (ast_id, items) in &tree.inner_items { | ||
82 | format_to!(out, "{:?}:\n", ast_id); | ||
83 | for inner in items { | ||
84 | format_to!(out, "- "); | ||
85 | fmt_mod_item(&mut out, &tree, *inner); | ||
86 | format_to!(out, "\n"); | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
91 | out | ||
92 | } | ||
93 | |||
94 | fn fmt_mod_item(out: &mut String, tree: &ItemTree, item: ModItem) { | ||
95 | match item { | ||
96 | ModItem::ExternCrate(it) => { | ||
97 | format_to!(out, "{:?}", tree[it]); | ||
98 | } | ||
99 | ModItem::Import(it) => { | ||
100 | format_to!(out, "{:?}", tree[it]); | ||
101 | } | ||
102 | ModItem::Function(it) => { | ||
103 | format_to!(out, "{:?}", tree[it]); | ||
104 | } | ||
105 | ModItem::Struct(it) => { | ||
106 | format_to!(out, "{:?}", tree[it]); | ||
107 | } | ||
108 | ModItem::Union(it) => { | ||
109 | format_to!(out, "{:?}", tree[it]); | ||
110 | } | ||
111 | ModItem::Enum(it) => { | ||
112 | format_to!(out, "{:?}", tree[it]); | ||
113 | } | ||
114 | ModItem::Const(it) => { | ||
115 | format_to!(out, "{:?}", tree[it]); | ||
116 | } | ||
117 | ModItem::Static(it) => { | ||
118 | format_to!(out, "{:?}", tree[it]); | ||
119 | } | ||
120 | ModItem::Trait(it) => { | ||
121 | format_to!(out, "{:?}", tree[it]); | ||
122 | } | ||
123 | ModItem::Impl(it) => { | ||
124 | format_to!(out, "{:?}", tree[it]); | ||
125 | } | ||
126 | ModItem::TypeAlias(it) => { | ||
127 | format_to!(out, "{:?}", tree[it]); | ||
128 | } | ||
129 | ModItem::Mod(it) => { | ||
130 | format_to!(out, "{:?}", tree[it]); | ||
131 | } | ||
132 | ModItem::MacroCall(it) => { | ||
133 | format_to!(out, "{:?}", tree[it]); | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | #[test] | ||
139 | fn smoke() { | ||
140 | assert_snapshot!(print_item_tree(r" | ||
141 | #![attr] | ||
142 | |||
143 | use {a, b::*}; | ||
144 | extern crate krate; | ||
145 | |||
146 | trait Tr<U> { | ||
147 | type AssocTy: Tr<()>; | ||
148 | const CONST: u8; | ||
149 | fn method(&self); | ||
150 | fn dfl_method(&mut self) {} | ||
151 | } | ||
152 | |||
153 | struct Struct0<T = ()>; | ||
154 | struct Struct1<T>(u8); | ||
155 | struct Struct2<T> { | ||
156 | fld: (T, ), | ||
157 | } | ||
158 | |||
159 | enum En { | ||
160 | Variant { | ||
161 | field: u8, | ||
162 | }, | ||
163 | } | ||
164 | |||
165 | union Un { | ||
166 | fld: u16, | ||
167 | } | ||
168 | "), @r###" | ||
169 | inner attrs: Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr"))] }, input: None }]) } | ||
170 | |||
171 | top-level items: | ||
172 | Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_glob: false, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) } | ||
173 | Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_glob: true, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) } | ||
174 | ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_macro_use: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ExternCrateItem>(1) } | ||
175 | Trait { name: Name(Text("Tr")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 2, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }, TypeParamData { name: Some(Name(Text("U"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, auto: false, items: [TypeAlias(Idx::<TypeAlias>(0)), Const(Idx::<Const>(0)), Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(2) } | ||
176 | Struct { name: Name(Text("Struct0")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: Some(Tuple([])), provenance: TypeParamList }] }, where_predicates: [] }, fields: Unit, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(3), kind: Unit } | ||
177 | Struct { name: Name(Text("Struct1")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Tuple(Idx::<Field>(0)..Idx::<Field>(1)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(4), kind: Tuple } | ||
178 | Struct { name: Name(Text("Struct2")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Record(Idx::<Field>(1)..Idx::<Field>(2)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(5), kind: Record } | ||
179 | Enum { name: Name(Text("En")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, variants: Idx::<Variant>(0)..Idx::<Variant>(1), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::EnumDef>(6) } | ||
180 | Union { name: Name(Text("Un")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, fields: Record(Idx::<Field>(3)..Idx::<Field>(4)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UnionDef>(7) } | ||
181 | "###); | ||
182 | } | ||
183 | |||
184 | #[test] | ||
185 | fn simple_inner_items() { | ||
186 | let tree = print_item_tree( | ||
187 | r" | ||
188 | impl<T:A> D for Response<T> { | ||
189 | fn foo() { | ||
190 | end(); | ||
191 | fn end<W: Write>() { | ||
192 | let _x: T = loop {}; | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | ", | ||
197 | ); | ||
198 | |||
199 | assert_snapshot!(tree, @r###" | ||
200 | inner attrs: Attrs { entries: None } | ||
201 | |||
202 | top-level items: | ||
203 | Impl { generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) } | ||
204 | |||
205 | inner items: | ||
206 | FileAstId::<ra_syntax::ast::generated::nodes::ModuleItem>(2): | ||
207 | - Function { name: Name(Text("end")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("W"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("W"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Write"))] }, generic_args: [None] }) }] }, has_self_param: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) } | ||
208 | "###); | ||
209 | } | ||
210 | |||
211 | #[test] | ||
212 | fn cursed_inner_items() { | ||
213 | test_inner_items( | ||
214 | r" | ||
215 | struct S<T: Trait = [u8; { fn f() {} 0 }]>(T); | ||
216 | |||
217 | enum En { | ||
218 | Var1 { | ||
219 | t: [(); { trait Inner {} 0 }], | ||
220 | }, | ||
221 | |||
222 | Var2([u16; { enum Inner {} 0 }]), | ||
223 | } | ||
224 | |||
225 | type Ty = [En; { struct Inner; 0 }]; | ||
226 | |||
227 | impl En { | ||
228 | fn assoc() { | ||
229 | trait InnerTrait {} | ||
230 | struct InnerStruct {} | ||
231 | impl InnerTrait for InnerStruct {} | ||
232 | } | ||
233 | } | ||
234 | ", | ||
235 | ); | ||
236 | } | ||
237 | |||
238 | #[test] | ||
239 | fn assoc_item_macros() { | ||
240 | let tree = print_item_tree( | ||
241 | r" | ||
242 | impl S { | ||
243 | items!(); | ||
244 | } | ||
245 | ", | ||
246 | ); | ||
247 | |||
248 | assert_snapshot!(tree, @r###" | ||
249 | inner attrs: Attrs { entries: None } | ||
250 | |||
251 | top-level items: | ||
252 | Impl { generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("S"))] }, generic_args: [None] }), is_negative: false, items: [MacroCall(Idx::<MacroCall>(0))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) } | ||
253 | "###); | ||
254 | } | ||
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index b5500f370..564434ccc 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -50,7 +50,7 @@ pub mod import_map; | |||
50 | #[cfg(test)] | 50 | #[cfg(test)] |
51 | mod test_db; | 51 | mod test_db; |
52 | 52 | ||
53 | use std::hash::Hash; | 53 | use std::hash::{Hash, Hasher}; |
54 | 54 | ||
55 | use hir_expand::{ | 55 | use hir_expand::{ |
56 | ast_id_map::FileAstId, eager::expand_eager_macro, hygiene::Hygiene, AstId, HirFileId, InFile, | 56 | ast_id_map::FileAstId, eager::expand_eager_macro, hygiene::Hygiene, AstId, HirFileId, InFile, |
@@ -58,10 +58,13 @@ use hir_expand::{ | |||
58 | }; | 58 | }; |
59 | use ra_arena::Idx; | 59 | use ra_arena::Idx; |
60 | use ra_db::{impl_intern_key, salsa, CrateId}; | 60 | use ra_db::{impl_intern_key, salsa, CrateId}; |
61 | use ra_syntax::{ast, AstNode}; | 61 | use ra_syntax::ast; |
62 | 62 | ||
63 | use crate::body::Expander; | ||
64 | use crate::builtin_type::BuiltinType; | 63 | use crate::builtin_type::BuiltinType; |
64 | use item_tree::{ | ||
65 | Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait, | ||
66 | TypeAlias, Union, | ||
67 | }; | ||
65 | 68 | ||
66 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 69 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
67 | pub struct ModuleId { | 70 | pub struct ModuleId { |
@@ -72,16 +75,62 @@ pub struct ModuleId { | |||
72 | /// An ID of a module, **local** to a specific crate | 75 | /// An ID of a module, **local** to a specific crate |
73 | pub type LocalModuleId = Idx<nameres::ModuleData>; | 76 | pub type LocalModuleId = Idx<nameres::ModuleData>; |
74 | 77 | ||
75 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 78 | #[derive(Debug)] |
76 | pub struct ItemLoc<N: AstNode> { | 79 | pub struct ItemLoc<N: ItemTreeNode> { |
77 | pub container: ContainerId, | 80 | pub container: ContainerId, |
78 | pub ast_id: AstId<N>, | 81 | pub id: ItemTreeId<N>, |
82 | } | ||
83 | |||
84 | impl<N: ItemTreeNode> Clone for ItemLoc<N> { | ||
85 | fn clone(&self) -> Self { | ||
86 | Self { container: self.container, id: self.id } | ||
87 | } | ||
88 | } | ||
89 | |||
90 | impl<N: ItemTreeNode> Copy for ItemLoc<N> {} | ||
91 | |||
92 | impl<N: ItemTreeNode> PartialEq for ItemLoc<N> { | ||
93 | fn eq(&self, other: &Self) -> bool { | ||
94 | self.container == other.container && self.id == other.id | ||
95 | } | ||
79 | } | 96 | } |
80 | 97 | ||
81 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 98 | impl<N: ItemTreeNode> Eq for ItemLoc<N> {} |
82 | pub struct AssocItemLoc<N: AstNode> { | 99 | |
100 | impl<N: ItemTreeNode> Hash for ItemLoc<N> { | ||
101 | fn hash<H: Hasher>(&self, state: &mut H) { | ||
102 | self.container.hash(state); | ||
103 | self.id.hash(state); | ||
104 | } | ||
105 | } | ||
106 | |||
107 | #[derive(Debug)] | ||
108 | pub struct AssocItemLoc<N: ItemTreeNode> { | ||
83 | pub container: AssocContainerId, | 109 | pub container: AssocContainerId, |
84 | pub ast_id: AstId<N>, | 110 | pub id: ItemTreeId<N>, |
111 | } | ||
112 | |||
113 | impl<N: ItemTreeNode> Clone for AssocItemLoc<N> { | ||
114 | fn clone(&self) -> Self { | ||
115 | Self { container: self.container, id: self.id } | ||
116 | } | ||
117 | } | ||
118 | |||
119 | impl<N: ItemTreeNode> Copy for AssocItemLoc<N> {} | ||
120 | |||
121 | impl<N: ItemTreeNode> PartialEq for AssocItemLoc<N> { | ||
122 | fn eq(&self, other: &Self) -> bool { | ||
123 | self.container == other.container && self.id == other.id | ||
124 | } | ||
125 | } | ||
126 | |||
127 | impl<N: ItemTreeNode> Eq for AssocItemLoc<N> {} | ||
128 | |||
129 | impl<N: ItemTreeNode> Hash for AssocItemLoc<N> { | ||
130 | fn hash<H: Hasher>(&self, state: &mut H) { | ||
131 | self.container.hash(state); | ||
132 | self.id.hash(state); | ||
133 | } | ||
85 | } | 134 | } |
86 | 135 | ||
87 | macro_rules! impl_intern { | 136 | macro_rules! impl_intern { |
@@ -106,22 +155,22 @@ macro_rules! impl_intern { | |||
106 | 155 | ||
107 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 156 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
108 | pub struct FunctionId(salsa::InternId); | 157 | pub struct FunctionId(salsa::InternId); |
109 | type FunctionLoc = AssocItemLoc<ast::FnDef>; | 158 | type FunctionLoc = AssocItemLoc<Function>; |
110 | impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); | 159 | impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); |
111 | 160 | ||
112 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 161 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
113 | pub struct StructId(salsa::InternId); | 162 | pub struct StructId(salsa::InternId); |
114 | type StructLoc = ItemLoc<ast::StructDef>; | 163 | type StructLoc = ItemLoc<Struct>; |
115 | impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); | 164 | impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); |
116 | 165 | ||
117 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 166 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
118 | pub struct UnionId(salsa::InternId); | 167 | pub struct UnionId(salsa::InternId); |
119 | pub type UnionLoc = ItemLoc<ast::UnionDef>; | 168 | pub type UnionLoc = ItemLoc<Union>; |
120 | impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); | 169 | impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); |
121 | 170 | ||
122 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 171 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
123 | pub struct EnumId(salsa::InternId); | 172 | pub struct EnumId(salsa::InternId); |
124 | pub type EnumLoc = ItemLoc<ast::EnumDef>; | 173 | pub type EnumLoc = ItemLoc<Enum>; |
125 | impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); | 174 | impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); |
126 | 175 | ||
127 | // FIXME: rename to `VariantId`, only enums can ave variants | 176 | // FIXME: rename to `VariantId`, only enums can ave variants |
@@ -143,27 +192,27 @@ pub type LocalFieldId = Idx<adt::FieldData>; | |||
143 | 192 | ||
144 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 193 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
145 | pub struct ConstId(salsa::InternId); | 194 | pub struct ConstId(salsa::InternId); |
146 | type ConstLoc = AssocItemLoc<ast::ConstDef>; | 195 | type ConstLoc = AssocItemLoc<Const>; |
147 | impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const); | 196 | impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const); |
148 | 197 | ||
149 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 198 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
150 | pub struct StaticId(salsa::InternId); | 199 | pub struct StaticId(salsa::InternId); |
151 | pub type StaticLoc = ItemLoc<ast::StaticDef>; | 200 | pub type StaticLoc = ItemLoc<Static>; |
152 | impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); | 201 | impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); |
153 | 202 | ||
154 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 203 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
155 | pub struct TraitId(salsa::InternId); | 204 | pub struct TraitId(salsa::InternId); |
156 | pub type TraitLoc = ItemLoc<ast::TraitDef>; | 205 | pub type TraitLoc = ItemLoc<Trait>; |
157 | impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); | 206 | impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); |
158 | 207 | ||
159 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 208 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
160 | pub struct TypeAliasId(salsa::InternId); | 209 | pub struct TypeAliasId(salsa::InternId); |
161 | type TypeAliasLoc = AssocItemLoc<ast::TypeAliasDef>; | 210 | type TypeAliasLoc = AssocItemLoc<TypeAlias>; |
162 | impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias); | 211 | impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias); |
163 | 212 | ||
164 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] | 213 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] |
165 | pub struct ImplId(salsa::InternId); | 214 | pub struct ImplId(salsa::InternId); |
166 | type ImplLoc = ItemLoc<ast::ImplDef>; | 215 | type ImplLoc = ItemLoc<Impl>; |
167 | impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); | 216 | impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); |
168 | 217 | ||
169 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 218 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -367,7 +416,7 @@ impl HasModule for AssocContainerId { | |||
367 | } | 416 | } |
368 | } | 417 | } |
369 | 418 | ||
370 | impl<N: AstNode> HasModule for AssocItemLoc<N> { | 419 | impl<N: ItemTreeNode> HasModule for AssocItemLoc<N> { |
371 | fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { | 420 | fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { |
372 | self.container.module(db) | 421 | self.container.module(db) |
373 | } | 422 | } |
@@ -394,6 +443,16 @@ impl HasModule for DefWithBodyId { | |||
394 | } | 443 | } |
395 | } | 444 | } |
396 | 445 | ||
446 | impl DefWithBodyId { | ||
447 | pub fn as_mod_item(self, db: &dyn db::DefDatabase) -> ModItem { | ||
448 | match self { | ||
449 | DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(), | ||
450 | DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(), | ||
451 | DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(), | ||
452 | } | ||
453 | } | ||
454 | } | ||
455 | |||
397 | impl HasModule for GenericDefId { | 456 | impl HasModule for GenericDefId { |
398 | fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { | 457 | fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { |
399 | match self { | 458 | match self { |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index c227b6da1..40aff830f 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -20,9 +20,7 @@ use test_utils::mark; | |||
20 | use crate::{ | 20 | use crate::{ |
21 | attr::Attrs, | 21 | attr::Attrs, |
22 | db::DefDatabase, | 22 | db::DefDatabase, |
23 | item_tree::{ | 23 | item_tree::{self, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind}, |
24 | FileItemTreeId, Import, ItemTree, MacroCall, Mod, ModItem, ModKind, StructDefKind, | ||
25 | }, | ||
26 | nameres::{ | 24 | nameres::{ |
27 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, | 25 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, |
28 | BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, | 26 | BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, |
@@ -106,9 +104,47 @@ impl PartialResolvedImport { | |||
106 | } | 104 | } |
107 | 105 | ||
108 | #[derive(Clone, Debug, Eq, PartialEq)] | 106 | #[derive(Clone, Debug, Eq, PartialEq)] |
107 | struct Import { | ||
108 | pub path: ModPath, | ||
109 | pub alias: Option<ImportAlias>, | ||
110 | pub visibility: RawVisibility, | ||
111 | pub is_glob: bool, | ||
112 | pub is_prelude: bool, | ||
113 | pub is_extern_crate: bool, | ||
114 | pub is_macro_use: bool, | ||
115 | } | ||
116 | |||
117 | impl From<item_tree::Import> for Import { | ||
118 | fn from(it: item_tree::Import) -> Self { | ||
119 | Self { | ||
120 | path: it.path, | ||
121 | alias: it.alias, | ||
122 | visibility: it.visibility, | ||
123 | is_glob: it.is_glob, | ||
124 | is_prelude: it.is_prelude, | ||
125 | is_extern_crate: false, | ||
126 | is_macro_use: false, | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | impl From<item_tree::ExternCrate> for Import { | ||
132 | fn from(it: item_tree::ExternCrate) -> Self { | ||
133 | Self { | ||
134 | path: it.path, | ||
135 | alias: it.alias, | ||
136 | visibility: it.visibility, | ||
137 | is_glob: false, | ||
138 | is_prelude: false, | ||
139 | is_extern_crate: true, | ||
140 | is_macro_use: it.is_macro_use, | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | #[derive(Clone, Debug, Eq, PartialEq)] | ||
109 | struct ImportDirective { | 146 | struct ImportDirective { |
110 | module_id: LocalModuleId, | 147 | module_id: LocalModuleId, |
111 | import_id: FileItemTreeId<Import>, | ||
112 | import: Import, | 148 | import: Import, |
113 | status: PartialResolvedImport, | 149 | status: PartialResolvedImport, |
114 | } | 150 | } |
@@ -297,7 +333,7 @@ impl DefCollector<'_> { | |||
297 | fn import_macros_from_extern_crate( | 333 | fn import_macros_from_extern_crate( |
298 | &mut self, | 334 | &mut self, |
299 | current_module_id: LocalModuleId, | 335 | current_module_id: LocalModuleId, |
300 | import: &Import, | 336 | import: &item_tree::ExternCrate, |
301 | ) { | 337 | ) { |
302 | log::debug!( | 338 | log::debug!( |
303 | "importing macros from extern crate: {:?} ({:?})", | 339 | "importing macros from extern crate: {:?} ({:?})", |
@@ -703,9 +739,9 @@ impl ModCollector<'_, '_> { | |||
703 | // any other items. | 739 | // any other items. |
704 | for item in items { | 740 | for item in items { |
705 | if self.is_cfg_enabled(self.item_tree.attrs(*item)) { | 741 | if self.is_cfg_enabled(self.item_tree.attrs(*item)) { |
706 | if let ModItem::Import(import_id) = item { | 742 | if let ModItem::ExternCrate(id) = item { |
707 | let import = self.item_tree[*import_id].clone(); | 743 | let import = self.item_tree[*id].clone(); |
708 | if import.is_extern_crate && import.is_macro_use { | 744 | if import.is_macro_use { |
709 | self.def_collector.import_macros_from_extern_crate(self.module_id, &import); | 745 | self.def_collector.import_macros_from_extern_crate(self.module_id, &import); |
710 | } | 746 | } |
711 | } | 747 | } |
@@ -725,8 +761,14 @@ impl ModCollector<'_, '_> { | |||
725 | ModItem::Import(import_id) => { | 761 | ModItem::Import(import_id) => { |
726 | self.def_collector.unresolved_imports.push(ImportDirective { | 762 | self.def_collector.unresolved_imports.push(ImportDirective { |
727 | module_id: self.module_id, | 763 | module_id: self.module_id, |
728 | import_id, | 764 | import: self.item_tree[import_id].clone().into(), |
729 | import: self.item_tree[import_id].clone(), | 765 | status: PartialResolvedImport::Unresolved, |
766 | }) | ||
767 | } | ||
768 | ModItem::ExternCrate(import_id) => { | ||
769 | self.def_collector.unresolved_imports.push(ImportDirective { | ||
770 | module_id: self.module_id, | ||
771 | import: self.item_tree[import_id].clone().into(), | ||
730 | status: PartialResolvedImport::Unresolved, | 772 | status: PartialResolvedImport::Unresolved, |
731 | }) | 773 | }) |
732 | } | 774 | } |
@@ -737,30 +779,28 @@ impl ModCollector<'_, '_> { | |||
737 | local_id: self.module_id, | 779 | local_id: self.module_id, |
738 | }; | 780 | }; |
739 | let container = ContainerId::ModuleId(module); | 781 | let container = ContainerId::ModuleId(module); |
740 | let ast_id = self.item_tree[imp].ast_id; | 782 | let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) } |
741 | let impl_id = | 783 | .intern(self.def_collector.db); |
742 | ImplLoc { container, ast_id: AstId::new(self.file_id, ast_id) } | ||
743 | .intern(self.def_collector.db); | ||
744 | self.def_collector.def_map.modules[self.module_id] | 784 | self.def_collector.def_map.modules[self.module_id] |
745 | .scope | 785 | .scope |
746 | .define_impl(impl_id) | 786 | .define_impl(impl_id) |
747 | } | 787 | } |
748 | ModItem::Function(it) => { | 788 | ModItem::Function(id) => { |
749 | let it = &self.item_tree[it]; | 789 | let func = &self.item_tree[id]; |
750 | def = Some(DefData { | 790 | def = Some(DefData { |
751 | id: FunctionLoc { | 791 | id: FunctionLoc { |
752 | container: container.into(), | 792 | container: container.into(), |
753 | ast_id: AstId::new(self.file_id, it.ast_id), | 793 | id: ItemTreeId::new(self.file_id, id), |
754 | } | 794 | } |
755 | .intern(self.def_collector.db) | 795 | .intern(self.def_collector.db) |
756 | .into(), | 796 | .into(), |
757 | name: &it.name, | 797 | name: &func.name, |
758 | visibility: &it.visibility, | 798 | visibility: &func.visibility, |
759 | has_constructor: false, | 799 | has_constructor: false, |
760 | }); | 800 | }); |
761 | } | 801 | } |
762 | ModItem::Struct(it) => { | 802 | ModItem::Struct(id) => { |
763 | let it = &self.item_tree[it]; | 803 | let it = &self.item_tree[id]; |
764 | 804 | ||
765 | // FIXME: check attrs to see if this is an attribute macro invocation; | 805 | // FIXME: check attrs to see if this is an attribute macro invocation; |
766 | // in which case we don't add the invocation, just a single attribute | 806 | // in which case we don't add the invocation, just a single attribute |
@@ -768,19 +808,16 @@ impl ModCollector<'_, '_> { | |||
768 | self.collect_derives(attrs, it.ast_id.upcast()); | 808 | self.collect_derives(attrs, it.ast_id.upcast()); |
769 | 809 | ||
770 | def = Some(DefData { | 810 | def = Some(DefData { |
771 | id: StructLoc { | 811 | id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) } |
772 | container, | 812 | .intern(self.def_collector.db) |
773 | ast_id: AstId::new(self.file_id, it.ast_id), | 813 | .into(), |
774 | } | ||
775 | .intern(self.def_collector.db) | ||
776 | .into(), | ||
777 | name: &it.name, | 814 | name: &it.name, |
778 | visibility: &it.visibility, | 815 | visibility: &it.visibility, |
779 | has_constructor: it.kind != StructDefKind::Record, | 816 | has_constructor: it.kind != StructDefKind::Record, |
780 | }); | 817 | }); |
781 | } | 818 | } |
782 | ModItem::Union(it) => { | 819 | ModItem::Union(id) => { |
783 | let it = &self.item_tree[it]; | 820 | let it = &self.item_tree[id]; |
784 | 821 | ||
785 | // FIXME: check attrs to see if this is an attribute macro invocation; | 822 | // FIXME: check attrs to see if this is an attribute macro invocation; |
786 | // in which case we don't add the invocation, just a single attribute | 823 | // in which case we don't add the invocation, just a single attribute |
@@ -788,7 +825,7 @@ impl ModCollector<'_, '_> { | |||
788 | self.collect_derives(attrs, it.ast_id.upcast()); | 825 | self.collect_derives(attrs, it.ast_id.upcast()); |
789 | 826 | ||
790 | def = Some(DefData { | 827 | def = Some(DefData { |
791 | id: UnionLoc { container, ast_id: AstId::new(self.file_id, it.ast_id) } | 828 | id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) } |
792 | .intern(self.def_collector.db) | 829 | .intern(self.def_collector.db) |
793 | .into(), | 830 | .into(), |
794 | name: &it.name, | 831 | name: &it.name, |
@@ -796,8 +833,8 @@ impl ModCollector<'_, '_> { | |||
796 | has_constructor: false, | 833 | has_constructor: false, |
797 | }); | 834 | }); |
798 | } | 835 | } |
799 | ModItem::Enum(it) => { | 836 | ModItem::Enum(id) => { |
800 | let it = &self.item_tree[it]; | 837 | let it = &self.item_tree[id]; |
801 | 838 | ||
802 | // FIXME: check attrs to see if this is an attribute macro invocation; | 839 | // FIXME: check attrs to see if this is an attribute macro invocation; |
803 | // in which case we don't add the invocation, just a single attribute | 840 | // in which case we don't add the invocation, just a single attribute |
@@ -805,7 +842,7 @@ impl ModCollector<'_, '_> { | |||
805 | self.collect_derives(attrs, it.ast_id.upcast()); | 842 | self.collect_derives(attrs, it.ast_id.upcast()); |
806 | 843 | ||
807 | def = Some(DefData { | 844 | def = Some(DefData { |
808 | id: EnumLoc { container, ast_id: AstId::new(self.file_id, it.ast_id) } | 845 | id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) } |
809 | .intern(self.def_collector.db) | 846 | .intern(self.def_collector.db) |
810 | .into(), | 847 | .into(), |
811 | name: &it.name, | 848 | name: &it.name, |
@@ -813,14 +850,14 @@ impl ModCollector<'_, '_> { | |||
813 | has_constructor: false, | 850 | has_constructor: false, |
814 | }); | 851 | }); |
815 | } | 852 | } |
816 | ModItem::Const(it) => { | 853 | ModItem::Const(id) => { |
817 | let it = &self.item_tree[it]; | 854 | let it = &self.item_tree[id]; |
818 | 855 | ||
819 | if let Some(name) = &it.name { | 856 | if let Some(name) = &it.name { |
820 | def = Some(DefData { | 857 | def = Some(DefData { |
821 | id: ConstLoc { | 858 | id: ConstLoc { |
822 | container: container.into(), | 859 | container: container.into(), |
823 | ast_id: AstId::new(self.file_id, it.ast_id), | 860 | id: ItemTreeId::new(self.file_id, id), |
824 | } | 861 | } |
825 | .intern(self.def_collector.db) | 862 | .intern(self.def_collector.db) |
826 | .into(), | 863 | .into(), |
@@ -830,26 +867,23 @@ impl ModCollector<'_, '_> { | |||
830 | }); | 867 | }); |
831 | } | 868 | } |
832 | } | 869 | } |
833 | ModItem::Static(it) => { | 870 | ModItem::Static(id) => { |
834 | let it = &self.item_tree[it]; | 871 | let it = &self.item_tree[id]; |
835 | 872 | ||
836 | def = Some(DefData { | 873 | def = Some(DefData { |
837 | id: StaticLoc { | 874 | id: StaticLoc { container, id: ItemTreeId::new(self.file_id, id) } |
838 | container, | 875 | .intern(self.def_collector.db) |
839 | ast_id: AstId::new(self.file_id, it.ast_id), | 876 | .into(), |
840 | } | ||
841 | .intern(self.def_collector.db) | ||
842 | .into(), | ||
843 | name: &it.name, | 877 | name: &it.name, |
844 | visibility: &it.visibility, | 878 | visibility: &it.visibility, |
845 | has_constructor: false, | 879 | has_constructor: false, |
846 | }); | 880 | }); |
847 | } | 881 | } |
848 | ModItem::Trait(it) => { | 882 | ModItem::Trait(id) => { |
849 | let it = &self.item_tree[it]; | 883 | let it = &self.item_tree[id]; |
850 | 884 | ||
851 | def = Some(DefData { | 885 | def = Some(DefData { |
852 | id: TraitLoc { container, ast_id: AstId::new(self.file_id, it.ast_id) } | 886 | id: TraitLoc { container, id: ItemTreeId::new(self.file_id, id) } |
853 | .intern(self.def_collector.db) | 887 | .intern(self.def_collector.db) |
854 | .into(), | 888 | .into(), |
855 | name: &it.name, | 889 | name: &it.name, |
@@ -857,13 +891,13 @@ impl ModCollector<'_, '_> { | |||
857 | has_constructor: false, | 891 | has_constructor: false, |
858 | }); | 892 | }); |
859 | } | 893 | } |
860 | ModItem::TypeAlias(it) => { | 894 | ModItem::TypeAlias(id) => { |
861 | let it = &self.item_tree[it]; | 895 | let it = &self.item_tree[id]; |
862 | 896 | ||
863 | def = Some(DefData { | 897 | def = Some(DefData { |
864 | id: TypeAliasLoc { | 898 | id: TypeAliasLoc { |
865 | container: container.into(), | 899 | container: container.into(), |
866 | ast_id: AstId::new(self.file_id, it.ast_id), | 900 | id: ItemTreeId::new(self.file_id, id), |
867 | } | 901 | } |
868 | .intern(self.def_collector.db) | 902 | .intern(self.def_collector.db) |
869 | .into(), | 903 | .into(), |
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs index d42933eed..e9a5e4cba 100644 --- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs | |||
@@ -722,10 +722,7 @@ fn unresolved_module_diagnostics() { | |||
722 | ), | 722 | ), |
723 | ), | 723 | ), |
724 | ), | 724 | ), |
725 | value: FileAstId { | 725 | value: FileAstId::<ra_syntax::ast::generated::nodes::Module>(1), |
726 | raw: Idx::<SyntaxNodePtr>(1), | ||
727 | _ty: PhantomData, | ||
728 | }, | ||
729 | }, | 726 | }, |
730 | candidate: "bar.rs", | 727 | candidate: "bar.rs", |
731 | }, | 728 | }, |
diff --git a/crates/ra_hir_def/src/src.rs b/crates/ra_hir_def/src/src.rs index 46e90da70..10e21d48e 100644 --- a/crates/ra_hir_def/src/src.rs +++ b/crates/ra_hir_def/src/src.rs | |||
@@ -2,30 +2,37 @@ | |||
2 | 2 | ||
3 | use hir_expand::InFile; | 3 | use hir_expand::InFile; |
4 | use ra_arena::map::ArenaMap; | 4 | use ra_arena::map::ArenaMap; |
5 | use ra_syntax::AstNode; | ||
6 | 5 | ||
7 | use crate::{db::DefDatabase, AssocItemLoc, ItemLoc}; | 6 | use crate::{db::DefDatabase, item_tree::ItemTreeSource, AssocItemLoc, ItemLoc}; |
8 | 7 | ||
9 | pub trait HasSource { | 8 | pub trait HasSource { |
10 | type Value; | 9 | type Value; |
11 | fn source(&self, db: &dyn DefDatabase) -> InFile<Self::Value>; | 10 | fn source(&self, db: &dyn DefDatabase) -> InFile<Self::Value>; |
12 | } | 11 | } |
13 | 12 | ||
14 | impl<N: AstNode> HasSource for AssocItemLoc<N> { | 13 | impl<N: ItemTreeSource> HasSource for AssocItemLoc<N> { |
15 | type Value = N; | 14 | type Value = N::Source; |
16 | 15 | ||
17 | fn source(&self, db: &dyn DefDatabase) -> InFile<N> { | 16 | fn source(&self, db: &dyn DefDatabase) -> InFile<N::Source> { |
18 | let node = self.ast_id.to_node(db.upcast()); | 17 | let tree = db.item_tree(self.id.file_id); |
19 | InFile::new(self.ast_id.file_id, node) | 18 | let ast_id_map = db.ast_id_map(self.id.file_id); |
19 | let root = db.parse_or_expand(self.id.file_id).unwrap(); | ||
20 | let node = &tree[self.id.value]; | ||
21 | |||
22 | InFile::new(self.id.file_id, ast_id_map.get(node.ast_id()).to_node(&root)) | ||
20 | } | 23 | } |
21 | } | 24 | } |
22 | 25 | ||
23 | impl<N: AstNode> HasSource for ItemLoc<N> { | 26 | impl<N: ItemTreeSource> HasSource for ItemLoc<N> { |
24 | type Value = N; | 27 | type Value = N::Source; |
28 | |||
29 | fn source(&self, db: &dyn DefDatabase) -> InFile<N::Source> { | ||
30 | let tree = db.item_tree(self.id.file_id); | ||
31 | let ast_id_map = db.ast_id_map(self.id.file_id); | ||
32 | let root = db.parse_or_expand(self.id.file_id).unwrap(); | ||
33 | let node = &tree[self.id.value]; | ||
25 | 34 | ||
26 | fn source(&self, db: &dyn DefDatabase) -> InFile<N> { | 35 | InFile::new(self.id.file_id, ast_id_map.get(node.ast_id()).to_node(&root)) |
27 | let node = self.ast_id.to_node(db.upcast()); | ||
28 | InFile::new(self.ast_id.file_id, node) | ||
29 | } | 36 | } |
30 | } | 37 | } |
31 | 38 | ||
diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs index d19569245..f4d31526a 100644 --- a/crates/ra_hir_expand/src/ast_id_map.rs +++ b/crates/ra_hir_expand/src/ast_id_map.rs | |||
@@ -6,6 +6,8 @@ | |||
6 | //! changes. | 6 | //! changes. |
7 | 7 | ||
8 | use std::{ | 8 | use std::{ |
9 | any::type_name, | ||
10 | fmt, | ||
9 | hash::{Hash, Hasher}, | 11 | hash::{Hash, Hasher}, |
10 | marker::PhantomData, | 12 | marker::PhantomData, |
11 | }; | 13 | }; |
@@ -14,7 +16,6 @@ use ra_arena::{Arena, Idx}; | |||
14 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; | 16 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; |
15 | 17 | ||
16 | /// `AstId` points to an AST node in a specific file. | 18 | /// `AstId` points to an AST node in a specific file. |
17 | #[derive(Debug)] | ||
18 | pub struct FileAstId<N: AstNode> { | 19 | pub struct FileAstId<N: AstNode> { |
19 | raw: ErasedFileAstId, | 20 | raw: ErasedFileAstId, |
20 | _ty: PhantomData<fn() -> N>, | 21 | _ty: PhantomData<fn() -> N>, |
@@ -39,11 +40,17 @@ impl<N: AstNode> Hash for FileAstId<N> { | |||
39 | } | 40 | } |
40 | } | 41 | } |
41 | 42 | ||
43 | impl<N: AstNode> fmt::Debug for FileAstId<N> { | ||
44 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
45 | write!(f, "FileAstId::<{}>({})", type_name::<N>(), self.raw.into_raw()) | ||
46 | } | ||
47 | } | ||
48 | |||
42 | impl<N: AstNode> FileAstId<N> { | 49 | impl<N: AstNode> FileAstId<N> { |
43 | // Can't make this a From implementation because of coherence | 50 | // Can't make this a From implementation because of coherence |
44 | pub fn upcast<M: AstNode>(self) -> FileAstId<M> | 51 | pub fn upcast<M: AstNode>(self) -> FileAstId<M> |
45 | where | 52 | where |
46 | M: From<N>, | 53 | N: Into<M>, |
47 | { | 54 | { |
48 | FileAstId { raw: self.raw, _ty: PhantomData } | 55 | FileAstId { raw: self.raw, _ty: PhantomData } |
49 | } | 56 | } |
@@ -89,7 +96,7 @@ impl AstIdMap { | |||
89 | } | 96 | } |
90 | } | 97 | } |
91 | 98 | ||
92 | pub(crate) fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> { | 99 | pub fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> { |
93 | self.arena[id.raw].clone().cast::<N>().unwrap() | 100 | self.arena[id.raw].clone().cast::<N>().unwrap() |
94 | } | 101 | } |
95 | 102 | ||
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 1fe05c70c..e82f2c11e 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -67,8 +67,8 @@ fn type_at_pos_displayed( | |||
67 | panic!("Can't find expression") | 67 | panic!("Can't find expression") |
68 | } | 68 | } |
69 | 69 | ||
70 | fn type_at(content: &str) -> String { | 70 | fn type_at(ra_fixture: &str) -> String { |
71 | let (db, file_pos) = TestDB::with_position(content); | 71 | let (db, file_pos) = TestDB::with_position(ra_fixture); |
72 | type_at_pos(&db, file_pos) | 72 | type_at_pos(&db, file_pos) |
73 | } | 73 | } |
74 | 74 | ||
@@ -164,13 +164,19 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { | |||
164 | visit_module(&db, &crate_def_map, module.local_id, &mut |it| defs.push(it)); | 164 | visit_module(&db, &crate_def_map, module.local_id, &mut |it| defs.push(it)); |
165 | defs.sort_by_key(|def| match def { | 165 | defs.sort_by_key(|def| match def { |
166 | DefWithBodyId::FunctionId(it) => { | 166 | DefWithBodyId::FunctionId(it) => { |
167 | it.lookup(&db).ast_id.to_node(&db).syntax().text_range().start() | 167 | let loc = it.lookup(&db); |
168 | let tree = db.item_tree(loc.id.file_id); | ||
169 | tree.source(&db, loc.id.value).syntax().text_range().start() | ||
168 | } | 170 | } |
169 | DefWithBodyId::ConstId(it) => { | 171 | DefWithBodyId::ConstId(it) => { |
170 | it.lookup(&db).ast_id.to_node(&db).syntax().text_range().start() | 172 | let loc = it.lookup(&db); |
173 | let tree = db.item_tree(loc.id.file_id); | ||
174 | tree.source(&db, loc.id.value).syntax().text_range().start() | ||
171 | } | 175 | } |
172 | DefWithBodyId::StaticId(it) => { | 176 | DefWithBodyId::StaticId(it) => { |
173 | it.lookup(&db).ast_id.to_node(&db).syntax().text_range().start() | 177 | let loc = it.lookup(&db); |
178 | let tree = db.item_tree(loc.id.file_id); | ||
179 | tree.source(&db, loc.id.value).syntax().text_range().start() | ||
174 | } | 180 | } |
175 | }); | 181 | }); |
176 | for def in defs { | 182 | for def in defs { |