aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-06-24 16:07:37 +0100
committerGitHub <[email protected]>2020-06-24 16:07:37 +0100
commite9bdb05e9676e85bdd8fa5008e3ada3812b36fd9 (patch)
treea21d348fbfa2d06f1fba77622c5417383938e6fe
parent1a3b507a007d0373a83bde203d780b860ea55ce1 (diff)
parent2928600374a8356c2c2bffee080c47cb0f463fb9 (diff)
Merge #4990
4990: Introduce an ItemTree layer to avoid reparsing files r=matklad a=jonas-schievink This reduces the latency of "go to definition" in a simple benchmark on rust-analyzer by around 30%. cc https://github.com/rust-analyzer/rust-analyzer/issues/1650 Closes https://github.com/rust-analyzer/rust-analyzer/issues/3485 Co-authored-by: Aleksey Kladov <[email protected]> Co-authored-by: Jonas Schievink <[email protected]> Co-authored-by: Jonas Schievink <[email protected]>
-rw-r--r--Cargo.lock1
-rw-r--r--crates/ra_arena/src/lib.rs3
-rw-r--r--crates/ra_db/src/lib.rs2
-rw-r--r--crates/ra_hir/src/code_model.rs10
-rw-r--r--crates/ra_hir/src/db.rs2
-rw-r--r--crates/ra_hir_def/Cargo.toml1
-rw-r--r--crates/ra_hir_def/src/attr.rs49
-rw-r--r--crates/ra_hir_def/src/body/lower.rs177
-rw-r--r--crates/ra_hir_def/src/body/scope.rs20
-rw-r--r--crates/ra_hir_def/src/data.rs382
-rw-r--r--crates/ra_hir_def/src/db.rs7
-rw-r--r--crates/ra_hir_def/src/generics.rs62
-rw-r--r--crates/ra_hir_def/src/item_tree.rs697
-rw-r--r--crates/ra_hir_def/src/item_tree/lower.rs695
-rw-r--r--crates/ra_hir_def/src/item_tree/tests.rs435
-rw-r--r--crates/ra_hir_def/src/lib.rs99
-rw-r--r--crates/ra_hir_def/src/nameres.rs1
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs386
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs482
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs38
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs12
-rw-r--r--crates/ra_hir_def/src/src.rs31
-rw-r--r--crates/ra_hir_def/src/visibility.rs21
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs13
-rw-r--r--crates/ra_hir_ty/src/tests.rs16
-rw-r--r--crates/ra_ide_db/src/change.rs2
26 files changed, 2594 insertions, 1050 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7bd2144a7..c2d00adeb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1018,6 +1018,7 @@ dependencies = [
1018 "ra_syntax", 1018 "ra_syntax",
1019 "ra_tt", 1019 "ra_tt",
1020 "rustc-hash", 1020 "rustc-hash",
1021 "smallvec",
1021 "stdx", 1022 "stdx",
1022 "test_utils", 1023 "test_utils",
1023] 1024]
diff --git a/crates/ra_arena/src/lib.rs b/crates/ra_arena/src/lib.rs
index 441fbb3cb..3169aa5b8 100644
--- a/crates/ra_arena/src/lib.rs
+++ b/crates/ra_arena/src/lib.rs
@@ -116,6 +116,9 @@ impl<T> Arena<T> {
116 ) -> impl Iterator<Item = (Idx<T>, &T)> + ExactSizeIterator + DoubleEndedIterator { 116 ) -> impl Iterator<Item = (Idx<T>, &T)> + ExactSizeIterator + DoubleEndedIterator {
117 self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawId(idx as u32)), value)) 117 self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawId(idx as u32)), value))
118 } 118 }
119 pub fn shrink_to_fit(&mut self) {
120 self.data.shrink_to_fit();
121 }
119} 122}
120 123
121impl<T> Default for Arena<T> { 124impl<T> Default for Arena<T> {
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 875290259..4a3ba57da 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -114,7 +114,7 @@ pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug {
114} 114}
115 115
116fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> { 116fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
117 let _p = profile("parse_query"); 117 let _p = profile("parse_query").detail(|| format!("{:?}", file_id));
118 let text = db.file_text(file_id); 118 let text = db.file_text(file_id);
119 SourceFile::parse(&*text) 119 SourceFile::parse(&*text)
120} 120}
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};
32use ra_db::{CrateId, CrateName, Edition, FileId}; 32use ra_db::{CrateId, CrateName, Edition, FileId};
33use ra_prof::profile; 33use ra_prof::profile;
34use ra_syntax::{ 34use ra_syntax::ast::{self, AttrsOwner, NameOwner};
35 ast::{self, AttrsOwner, NameOwner},
36 AstNode,
37};
38use rustc_hash::FxHashSet; 35use rustc_hash::FxHashSet;
39 36
40use crate::{ 37use crate::{
@@ -205,7 +202,8 @@ impl ModuleDef {
205} 202}
206 203
207pub use hir_def::{ 204pub 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
211impl Module { 209impl 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/src/db.rs b/crates/ra_hir/src/db.rs
index b25dac28e..bb67952de 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -6,7 +6,7 @@ pub use hir_def::db::{
6 ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery, 6 ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery,
7 InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, 7 InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery,
8 InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, 8 InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery,
9 InternUnionQuery, LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, 9 InternUnionQuery, ItemTreeQuery, LangItemQuery, ModuleLangItemsQuery, StaticDataQuery,
10 StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, 10 StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery,
11}; 11};
12pub use hir_expand::db::{ 12pub use hir_expand::db::{
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml
index ef1f65ee0..6d43924e3 100644
--- a/crates/ra_hir_def/Cargo.toml
+++ b/crates/ra_hir_def/Cargo.toml
@@ -17,6 +17,7 @@ drop_bomb = "0.1.4"
17fst = { version = "0.4", default-features = false } 17fst = { version = "0.4", default-features = false }
18itertools = "0.9.0" 18itertools = "0.9.0"
19indexmap = "1.4.0" 19indexmap = "1.4.0"
20smallvec = "1.4.0"
20 21
21stdx = { path = "../stdx" } 22stdx = { path = "../stdx" }
22 23
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index 2eeba0572..197737ffc 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -13,7 +13,11 @@ use ra_syntax::{
13use tt::Subtree; 13use tt::Subtree;
14 14
15use crate::{ 15use crate::{
16 db::DefDatabase, nameres::ModuleSource, path::ModPath, src::HasChildSource, src::HasSource, 16 db::DefDatabase,
17 item_tree::{ItemTreeId, ItemTreeNode},
18 nameres::ModuleSource,
19 path::ModPath,
20 src::HasChildSource,
17 AdtId, AttrDefId, Lookup, 21 AdtId, AttrDefId, Lookup,
18}; 22};
19 23
@@ -34,6 +38,8 @@ impl ops::Deref for Attrs {
34} 38}
35 39
36impl Attrs { 40impl Attrs {
41 pub const EMPTY: Attrs = Attrs { entries: None };
42
37 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { 43 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
38 match def { 44 match def {
39 AttrDefId::ModuleId(module) => { 45 AttrDefId::ModuleId(module) => {
@@ -65,19 +71,19 @@ impl Attrs {
65 Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) 71 Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
66 } 72 }
67 AttrDefId::AdtId(it) => match it { 73 AttrDefId::AdtId(it) => match it {
68 AdtId::StructId(it) => attrs_from_loc(it.lookup(db), db), 74 AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
69 AdtId::EnumId(it) => attrs_from_loc(it.lookup(db), db), 75 AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
70 AdtId::UnionId(it) => attrs_from_loc(it.lookup(db), db), 76 AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
71 }, 77 },
72 AttrDefId::TraitId(it) => attrs_from_loc(it.lookup(db), db), 78 AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
73 AttrDefId::MacroDefId(it) => { 79 AttrDefId::MacroDefId(it) => {
74 it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) 80 it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
75 } 81 }
76 AttrDefId::ImplId(it) => attrs_from_loc(it.lookup(db), db), 82 AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
77 AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db), 83 AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
78 AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db), 84 AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
79 AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db), 85 AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
80 AttrDefId::TypeAliasId(it) => attrs_from_loc(it.lookup(db), db), 86 AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
81 } 87 }
82 } 88 }
83 89
@@ -103,6 +109,18 @@ impl Attrs {
103 Attrs { entries } 109 Attrs { entries }
104 } 110 }
105 111
112 pub fn merge(&self, other: Attrs) -> Attrs {
113 match (&self.entries, &other.entries) {
114 (None, None) => Attrs { entries: None },
115 (Some(entries), None) | (None, Some(entries)) => {
116 Attrs { entries: Some(entries.clone()) }
117 }
118 (Some(a), Some(b)) => {
119 Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
120 }
121 }
122 }
123
106 pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { 124 pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
107 AttrQuery { attrs: self, key } 125 AttrQuery { attrs: self, key }
108 } 126 }
@@ -187,11 +205,8 @@ where
187 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) 205 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
188} 206}
189 207
190fn attrs_from_loc<T>(node: T, db: &dyn DefDatabase) -> Attrs 208fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs {
191where 209 let tree = db.item_tree(id.file_id);
192 T: HasSource, 210 let mod_item = N::id_to_mod_item(id.value);
193 T::Value: ast::AttrsOwner, 211 tree.attrs(mod_item).clone()
194{
195 let src = node.source(db);
196 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
197} 212}
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index f159f80af..3ced648e5 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;
5use hir_expand::{ 5use 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};
10use ra_arena::Arena; 10use ra_arena::Arena;
11use ra_syntax::{ 11use 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, ItemTreeNode},
30 path::{GenericArgs, Path}, 31 path::{GenericArgs, Path},
31 type_ref::{Mutability, Rawness, TypeRef}, 32 type_ref::{Mutability, Rawness, TypeRef},
32 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, 33 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId,
@@ -35,6 +36,8 @@ use crate::{
35 36
36use super::{ExprSource, PatSource}; 37use super::{ExprSource, PatSource};
37use ast::AstChildren; 38use ast::AstChildren;
39use rustc_hash::FxHashMap;
40use std::sync::Arc;
38 41
39pub(crate) struct LowerCtx { 42pub(crate) struct LowerCtx {
40 hygiene: Hygiene, 43 hygiene: Hygiene,
@@ -60,10 +63,10 @@ pub(super) fn lower(
60 params: Option<ast::ParamList>, 63 params: Option<ast::ParamList>,
61 body: Option<ast::Expr>, 64 body: Option<ast::Expr>,
62) -> (Body, BodySourceMap) { 65) -> (Body, BodySourceMap) {
66 let item_tree = db.item_tree(expander.current_file_id);
63 ExprCollector { 67 ExprCollector {
64 db, 68 db,
65 def, 69 def,
66 expander,
67 source_map: BodySourceMap::default(), 70 source_map: BodySourceMap::default(),
68 body: Body { 71 body: Body {
69 exprs: Arena::default(), 72 exprs: Arena::default(),
@@ -72,6 +75,12 @@ pub(super) fn lower(
72 body_expr: dummy_expr_id(), 75 body_expr: dummy_expr_id(),
73 item_scope: Default::default(), 76 item_scope: Default::default(),
74 }, 77 },
78 item_trees: {
79 let mut map = FxHashMap::default();
80 map.insert(expander.current_file_id, item_tree);
81 map
82 },
83 expander,
75 } 84 }
76 .collect(params, body) 85 .collect(params, body)
77} 86}
@@ -82,6 +91,8 @@ struct ExprCollector<'a> {
82 expander: Expander, 91 expander: Expander,
83 body: Body, 92 body: Body,
84 source_map: BodySourceMap, 93 source_map: BodySourceMap,
94
95 item_trees: FxHashMap<HirFileId, Arc<ItemTree>>,
85} 96}
86 97
87impl ExprCollector<'_> { 98impl ExprCollector<'_> {
@@ -533,6 +544,9 @@ impl ExprCollector<'_> {
533 self.source_map 544 self.source_map
534 .expansions 545 .expansions
535 .insert(macro_call, self.expander.current_file_id); 546 .insert(macro_call, self.expander.current_file_id);
547
548 let item_tree = self.db.item_tree(self.expander.current_file_id);
549 self.item_trees.insert(self.expander.current_file_id, item_tree);
536 let id = self.collect_expr(expansion); 550 let id = self.collect_expr(expansion);
537 self.expander.exit(self.db, mark); 551 self.expander.exit(self.db, mark);
538 id 552 id
@@ -547,6 +561,19 @@ impl ExprCollector<'_> {
547 } 561 }
548 } 562 }
549 563
564 fn find_inner_item<S: ItemTreeNode>(&self, id: AstId<ast::ModuleItem>) -> FileItemTreeId<S> {
565 let tree = &self.item_trees[&id.file_id];
566
567 // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes
568
569 // Root file (non-macro).
570 tree.all_inner_items()
571 .chain(tree.top_level_items().iter().copied())
572 .filter_map(|mod_item| mod_item.downcast::<S>())
573 .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value)
574 .unwrap_or_else(|| panic!("couldn't find inner item for {:?}", id))
575 }
576
550 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { 577 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
551 if let Some(expr) = expr { 578 if let Some(expr) = expr {
552 self.collect_expr(expr) 579 self.collect_expr(expr)
@@ -578,56 +605,102 @@ impl ExprCollector<'_> {
578 605
579 fn collect_block_items(&mut self, block: &ast::BlockExpr) { 606 fn collect_block_items(&mut self, block: &ast::BlockExpr) {
580 let container = ContainerId::DefWithBodyId(self.def); 607 let container = ContainerId::DefWithBodyId(self.def);
581 for item in block.items() { 608
582 let (def, name): (ModuleDefId, Option<ast::Name>) = match item { 609 let items = block
583 ast::ModuleItem::FnDef(def) => { 610 .items()
584 let ast_id = self.expander.ast_id(&def); 611 .filter_map(|item| {
585 ( 612 let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
586 FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(), 613 ast::ModuleItem::FnDef(def) => {
587 def.name(), 614 let ast_id = self.expander.ast_id(&def);
588 ) 615 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
589 } 616 (
590 ast::ModuleItem::TypeAliasDef(def) => { 617 FunctionLoc { container: container.into(), id: ast_id.with_value(id) }
591 let ast_id = self.expander.ast_id(&def); 618 .intern(self.db)
592 ( 619 .into(),
593 TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(), 620 def.name(),
594 def.name(), 621 )
595 ) 622 }
596 } 623 ast::ModuleItem::TypeAliasDef(def) => {
597 ast::ModuleItem::ConstDef(def) => { 624 let ast_id = self.expander.ast_id(&def);
598 let ast_id = self.expander.ast_id(&def); 625 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
599 ( 626 (
600 ConstLoc { container: container.into(), ast_id }.intern(self.db).into(), 627 TypeAliasLoc { container: container.into(), id: ast_id.with_value(id) }
601 def.name(), 628 .intern(self.db)
602 ) 629 .into(),
603 } 630 def.name(),
604 ast::ModuleItem::StaticDef(def) => { 631 )
605 let ast_id = self.expander.ast_id(&def); 632 }
606 (StaticLoc { container, ast_id }.intern(self.db).into(), def.name()) 633 ast::ModuleItem::ConstDef(def) => {
607 } 634 let ast_id = self.expander.ast_id(&def);
608 ast::ModuleItem::StructDef(def) => { 635 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
609 let ast_id = self.expander.ast_id(&def); 636 (
610 (StructLoc { container, ast_id }.intern(self.db).into(), def.name()) 637 ConstLoc { container: container.into(), id: ast_id.with_value(id) }
611 } 638 .intern(self.db)
612 ast::ModuleItem::EnumDef(def) => { 639 .into(),
613 let ast_id = self.expander.ast_id(&def); 640 def.name(),
614 (EnumLoc { container, ast_id }.intern(self.db).into(), def.name()) 641 )
615 } 642 }
616 ast::ModuleItem::UnionDef(def) => { 643 ast::ModuleItem::StaticDef(def) => {
617 let ast_id = self.expander.ast_id(&def); 644 let ast_id = self.expander.ast_id(&def);
618 (UnionLoc { container, ast_id }.intern(self.db).into(), def.name()) 645 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
619 } 646 (
620 ast::ModuleItem::TraitDef(def) => { 647 StaticLoc { container, id: ast_id.with_value(id) }
621 let ast_id = self.expander.ast_id(&def); 648 .intern(self.db)
622 (TraitLoc { container, ast_id }.intern(self.db).into(), def.name()) 649 .into(),
623 } 650 def.name(),
624 ast::ModuleItem::ExternBlock(_) => continue, // FIXME: collect from extern blocks 651 )
625 ast::ModuleItem::ImplDef(_) 652 }
626 | ast::ModuleItem::UseItem(_) 653 ast::ModuleItem::StructDef(def) => {
627 | ast::ModuleItem::ExternCrateItem(_) 654 let ast_id = self.expander.ast_id(&def);
628 | ast::ModuleItem::Module(_) 655 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
629 | ast::ModuleItem::MacroCall(_) => continue, 656 (
630 }; 657 StructLoc { container, id: ast_id.with_value(id) }
658 .intern(self.db)
659 .into(),
660 def.name(),
661 )
662 }
663 ast::ModuleItem::EnumDef(def) => {
664 let ast_id = self.expander.ast_id(&def);
665 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
666 (
667 EnumLoc { container, id: ast_id.with_value(id) }.intern(self.db).into(),
668 def.name(),
669 )
670 }
671 ast::ModuleItem::UnionDef(def) => {
672 let ast_id = self.expander.ast_id(&def);
673 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
674 (
675 UnionLoc { container, id: ast_id.with_value(id) }
676 .intern(self.db)
677 .into(),
678 def.name(),
679 )
680 }
681 ast::ModuleItem::TraitDef(def) => {
682 let ast_id = self.expander.ast_id(&def);
683 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
684 (
685 TraitLoc { container, id: ast_id.with_value(id) }
686 .intern(self.db)
687 .into(),
688 def.name(),
689 )
690 }
691 ast::ModuleItem::ExternBlock(_) => return None, // FIXME: collect from extern blocks
692 ast::ModuleItem::ImplDef(_)
693 | ast::ModuleItem::UseItem(_)
694 | ast::ModuleItem::ExternCrateItem(_)
695 | ast::ModuleItem::Module(_)
696 | ast::ModuleItem::MacroCall(_) => return None,
697 };
698
699 Some((def, name))
700 })
701 .collect::<Vec<_>>();
702
703 for (def, name) in items {
631 self.body.item_scope.define_def(def); 704 self.body.item_scope.define_def(def);
632 if let Some(name) = name { 705 if let Some(name) = name {
633 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly 706 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
index 0b74199d9..81397b063 100644
--- a/crates/ra_hir_def/src/body/scope.rs
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -317,6 +317,26 @@ fn foo() {
317 ); 317 );
318 } 318 }
319 319
320 #[test]
321 fn macro_inner_item() {
322 do_check(
323 r"
324 macro_rules! mac {
325 () => {{
326 fn inner() {}
327 inner();
328 }};
329 }
330
331 fn foo() {
332 mac!();
333 <|>
334 }
335 ",
336 &[],
337 );
338 }
339
320 fn do_check_local_name(ra_fixture: &str, expected_offset: u32) { 340 fn do_check_local_name(ra_fixture: &str, expected_offset: u32) {
321 let (db, position) = TestDB::with_position(ra_fixture); 341 let (db, position) = TestDB::with_position(ra_fixture);
322 let file_id = position.file_id; 342 let file_id = position.file_id;
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index 53599e74a..f9e5701db 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -2,27 +2,19 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_expand::{ 5use hir_expand::{name::Name, InFile};
6 hygiene::Hygiene,
7 name::{name, AsName, Name},
8 AstId, InFile,
9};
10use ra_prof::profile; 6use ra_prof::profile;
11use ra_syntax::ast::{ 7use ra_syntax::ast;
12 self, AssocItem, AstNode, ModuleItemOwner, NameOwner, TypeAscriptionOwner, TypeBoundsOwner,
13 VisibilityOwner,
14};
15 8
16use crate::{ 9use crate::{
17 attr::Attrs, 10 attr::Attrs,
18 body::LowerCtx, 11 body::Expander,
19 db::DefDatabase, 12 db::DefDatabase,
20 path::{path, AssociatedTypeBinding, GenericArgs, Path}, 13 item_tree::{AssocItem, ItemTreeId, ModItem},
21 src::HasSource, 14 type_ref::{TypeBound, TypeRef},
22 type_ref::{Mutability, TypeBound, TypeRef},
23 visibility::RawVisibility, 15 visibility::RawVisibility,
24 AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, 16 AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
25 ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, 17 Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
26}; 18};
27 19
28#[derive(Debug, Clone, PartialEq, Eq)] 20#[derive(Debug, Clone, PartialEq, Eq)]
@@ -41,82 +33,27 @@ pub struct FunctionData {
41impl FunctionData { 33impl FunctionData {
42 pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { 34 pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> {
43 let loc = func.lookup(db); 35 let loc = func.lookup(db);
44 let src = loc.source(db); 36 let item_tree = db.item_tree(loc.id.file_id);
45 let ctx = LowerCtx::new(db, src.file_id); 37 let func = &item_tree[loc.id.value];
46 let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); 38
47 let mut params = Vec::new(); 39 Arc::new(FunctionData {
48 let mut has_self_param = false; 40 name: func.name.clone(),
49 if let Some(param_list) = src.value.param_list() { 41 params: func.params.to_vec(),
50 if let Some(self_param) = param_list.self_param() { 42 ret_type: func.ret_type.clone(),
51 let self_type = if let Some(type_ref) = self_param.ascribed_type() { 43 attrs: item_tree.attrs(loc.id.value.into()).clone(),
52 TypeRef::from_ast(&ctx, type_ref) 44 has_self_param: func.has_self_param,
53 } else { 45 is_unsafe: func.is_unsafe,
54 let self_type = TypeRef::Path(name![Self].into()); 46 visibility: item_tree[func.visibility].clone(),
55 match self_param.kind() { 47 })
56 ast::SelfParamKind::Owned => self_type,
57 ast::SelfParamKind::Ref => {
58 TypeRef::Reference(Box::new(self_type), Mutability::Shared)
59 }
60 ast::SelfParamKind::MutRef => {
61 TypeRef::Reference(Box::new(self_type), Mutability::Mut)
62 }
63 }
64 };
65 params.push(self_type);
66 has_self_param = true;
67 }
68 for param in param_list.params() {
69 let type_ref = TypeRef::from_ast_opt(&ctx, param.ascribed_type());
70 params.push(type_ref);
71 }
72 }
73 let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id));
74
75 let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) {
76 TypeRef::from_ast(&ctx, type_ref)
77 } else {
78 TypeRef::unit()
79 };
80
81 let ret_type = if src.value.async_token().is_some() {
82 let future_impl = desugar_future_path(ret_type);
83 let ty_bound = TypeBound::Path(future_impl);
84 TypeRef::ImplTrait(vec![ty_bound])
85 } else {
86 ret_type
87 };
88
89 let is_unsafe = src.value.unsafe_token().is_some();
90
91 let vis_default = RawVisibility::default_for_container(loc.container);
92 let visibility =
93 RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility()));
94
95 let sig =
96 FunctionData { name, params, ret_type, has_self_param, is_unsafe, visibility, attrs };
97 Arc::new(sig)
98 } 48 }
99} 49}
100 50
101fn desugar_future_path(orig: TypeRef) -> Path {
102 let path = path![core::future::Future];
103 let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect();
104 let mut last = GenericArgs::empty();
105 last.bindings.push(AssociatedTypeBinding {
106 name: name![Output],
107 type_ref: Some(orig),
108 bounds: Vec::new(),
109 });
110 generic_args.push(Some(Arc::new(last)));
111
112 Path::from_known_path(path, generic_args)
113}
114
115#[derive(Debug, Clone, PartialEq, Eq)] 51#[derive(Debug, Clone, PartialEq, Eq)]
116pub struct TypeAliasData { 52pub struct TypeAliasData {
117 pub name: Name, 53 pub name: Name,
118 pub type_ref: Option<TypeRef>, 54 pub type_ref: Option<TypeRef>,
119 pub visibility: RawVisibility, 55 pub visibility: RawVisibility,
56 /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
120 pub bounds: Vec<TypeBound>, 57 pub bounds: Vec<TypeBound>,
121} 58}
122 59
@@ -126,22 +63,15 @@ impl TypeAliasData {
126 typ: TypeAliasId, 63 typ: TypeAliasId,
127 ) -> Arc<TypeAliasData> { 64 ) -> Arc<TypeAliasData> {
128 let loc = typ.lookup(db); 65 let loc = typ.lookup(db);
129 let node = loc.source(db); 66 let item_tree = db.item_tree(loc.id.file_id);
130 let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); 67 let typ = &item_tree[loc.id.value];
131 let lower_ctx = LowerCtx::new(db, node.file_id); 68
132 let type_ref = node.value.type_ref().map(|it| TypeRef::from_ast(&lower_ctx, it)); 69 Arc::new(TypeAliasData {
133 let vis_default = RawVisibility::default_for_container(loc.container); 70 name: typ.name.clone(),
134 let visibility = RawVisibility::from_ast_with_default( 71 type_ref: typ.type_ref.clone(),
135 db, 72 visibility: item_tree[typ.visibility].clone(),
136 vis_default, 73 bounds: typ.bounds.to_vec(),
137 node.as_ref().map(|n| n.visibility()), 74 })
138 );
139 let bounds = if let Some(bound_list) = node.value.type_bound_list() {
140 bound_list.bounds().map(|it| TypeBound::from_ast(&lower_ctx, it)).collect()
141 } else {
142 Vec::new()
143 };
144 Arc::new(TypeAliasData { name, type_ref, visibility, bounds })
145 } 75 }
146} 76}
147 77
@@ -155,30 +85,24 @@ pub struct TraitData {
155impl TraitData { 85impl TraitData {
156 pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { 86 pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> {
157 let tr_loc = tr.lookup(db); 87 let tr_loc = tr.lookup(db);
158 let src = tr_loc.source(db); 88 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()); 89 let tr_def = &item_tree[tr_loc.id.value];
160 let auto = src.value.auto_token().is_some(); 90 let name = tr_def.name.clone();
91 let auto = tr_def.auto;
161 let module_id = tr_loc.container.module(db); 92 let module_id = tr_loc.container.module(db);
162
163 let container = AssocContainerId::TraitId(tr); 93 let container = AssocContainerId::TraitId(tr);
164 let mut items = Vec::new(); 94 let mut expander = Expander::new(db, tr_loc.id.file_id, module_id);
165 95
166 if let Some(item_list) = src.value.item_list() { 96 let items = collect_items(
167 let mut expander = Expander::new(db, tr_loc.ast_id.file_id, module_id); 97 db,
168 items.extend(collect_items( 98 module_id,
169 db, 99 &mut expander,
170 &mut expander, 100 tr_def.items.iter().copied(),
171 item_list.assoc_items(), 101 tr_loc.id.file_id,
172 src.file_id, 102 container,
173 container, 103 100,
174 )); 104 );
175 items.extend(collect_items_in_macros( 105
176 db,
177 &mut expander,
178 &src.with_value(item_list),
179 container,
180 ));
181 }
182 Arc::new(TraitData { name, items, auto }) 106 Arc::new(TraitData { name, items, auto })
183 } 107 }
184 108
@@ -209,33 +133,28 @@ impl ImplData {
209 pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { 133 pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> {
210 let _p = profile("impl_data_query"); 134 let _p = profile("impl_data_query");
211 let impl_loc = id.lookup(db); 135 let impl_loc = id.lookup(db);
212 let src = impl_loc.source(db);
213 let lower_ctx = LowerCtx::new(db, src.file_id);
214 136
215 let target_trait = src.value.target_trait().map(|it| TypeRef::from_ast(&lower_ctx, it)); 137 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()); 138 let impl_def = &item_tree[impl_loc.id.value];
217 let is_negative = src.value.excl_token().is_some(); 139 let target_trait = impl_def.target_trait.clone();
140 let target_type = impl_def.target_type.clone();
141 let is_negative = impl_def.is_negative;
218 let module_id = impl_loc.container.module(db); 142 let module_id = impl_loc.container.module(db);
219 let container = AssocContainerId::ImplId(id); 143 let container = AssocContainerId::ImplId(id);
144 let mut expander = Expander::new(db, impl_loc.id.file_id, module_id);
220 145
221 let mut items: Vec<AssocItemId> = Vec::new(); 146 let items = collect_items(
222 147 db,
223 if let Some(item_list) = src.value.item_list() { 148 module_id,
224 let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id); 149 &mut expander,
225 items.extend( 150 impl_def.items.iter().copied(),
226 collect_items(db, &mut expander, item_list.assoc_items(), src.file_id, container) 151 impl_loc.id.file_id,
227 .into_iter() 152 container,
228 .map(|(_, item)| item), 153 100,
229 ); 154 );
230 items.extend( 155 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 156
237 let res = ImplData { target_trait, target_type, items, is_negative }; 157 Arc::new(ImplData { target_trait, target_type, items, is_negative })
238 Arc::new(res)
239 } 158 }
240} 159}
241 160
@@ -250,22 +169,14 @@ pub struct ConstData {
250impl ConstData { 169impl ConstData {
251 pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> { 170 pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> {
252 let loc = konst.lookup(db); 171 let loc = konst.lookup(db);
253 let node = loc.source(db); 172 let item_tree = db.item_tree(loc.id.file_id);
254 let vis_default = RawVisibility::default_for_container(loc.container); 173 let konst = &item_tree[loc.id.value];
255 Arc::new(ConstData::new(db, vis_default, node))
256 }
257 174
258 fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>( 175 Arc::new(ConstData {
259 db: &dyn DefDatabase, 176 name: konst.name.clone(),
260 vis_default: RawVisibility, 177 type_ref: konst.type_ref.clone(),
261 node: InFile<N>, 178 visibility: item_tree[konst.visibility].clone(),
262 ) -> ConstData { 179 })
263 let ctx = LowerCtx::new(db, node.file_id);
264 let name = node.value.name().map(|n| n.as_name());
265 let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type());
266 let visibility =
267 RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility()));
268 ConstData { name, type_ref, visibility }
269 } 180 }
270} 181}
271 182
@@ -279,44 +190,25 @@ pub struct StaticData {
279 190
280impl StaticData { 191impl StaticData {
281 pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> { 192 pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> {
282 let node = konst.lookup(db).source(db); 193 let node = konst.lookup(db);
283 let ctx = LowerCtx::new(db, node.file_id); 194 let item_tree = db.item_tree(node.id.file_id);
284 195 let statik = &item_tree[node.id.value];
285 let name = node.value.name().map(|n| n.as_name()); 196
286 let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type()); 197 Arc::new(StaticData {
287 let mutable = node.value.mut_token().is_some(); 198 name: Some(statik.name.clone()),
288 let visibility = RawVisibility::from_ast_with_default( 199 type_ref: statik.type_ref.clone(),
289 db, 200 visibility: item_tree[statik.visibility].clone(),
290 RawVisibility::private(), 201 mutable: statik.mutable,
291 node.map(|n| n.visibility()), 202 })
292 );
293
294 Arc::new(StaticData { name, type_ref, visibility, mutable })
295 }
296}
297
298fn collect_items_in_macros(
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 } 203 }
312
313 res
314} 204}
315 205
316fn collect_items_in_macro( 206fn collect_items(
317 db: &dyn DefDatabase, 207 db: &dyn DefDatabase,
208 module: ModuleId,
318 expander: &mut Expander, 209 expander: &mut Expander,
319 m: ast::MacroCall, 210 assoc_items: impl Iterator<Item = AssocItem>,
211 file_id: crate::HirFileId,
320 container: AssocContainerId, 212 container: AssocContainerId,
321 limit: usize, 213 limit: usize,
322) -> Vec<(Name, AssocItemId)> { 214) -> Vec<(Name, AssocItemId)> {
@@ -324,62 +216,62 @@ fn collect_items_in_macro(
324 return Vec::new(); 216 return Vec::new();
325 } 217 }
326 218
327 if let Some((mark, items)) = expander.enter_expand(db, None, m) { 219 let item_tree = db.item_tree(file_id);
328 let items: InFile<ast::MacroItems> = expander.to_source(items); 220 let cfg_options = db.crate_graph()[module.krate].cfg_options.clone();
329 let mut res = collect_items( 221
330 db, 222 let mut items = Vec::new();
331 expander, 223 for item in assoc_items {
332 items.value.items().filter_map(|it| AssocItem::cast(it.syntax().clone())), 224 match item {
333 items.file_id, 225 AssocItem::Function(id) => {
334 container, 226 let item = &item_tree[id];
335 ); 227 let attrs = item_tree.attrs(id.into());
336 228 if !attrs.is_cfg_enabled(&cfg_options) {
337 // Recursive collect macros 229 continue;
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
350fn collect_items(
351 db: &dyn DefDatabase,
352 expander: &mut Expander,
353 assoc_items: impl Iterator<Item = AssocItem>,
354 file_id: crate::HirFileId,
355 container: AssocContainerId,
356) -> Vec<(Name, AssocItemId)> {
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 } 230 }
366 let def = FunctionLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } 231 let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
367 .intern(db); 232 items.push((item.name.clone(), def.into()));
368 Some((name, def.into()))
369 } 233 }
370 ast::AssocItem::ConstDef(it) => { 234 // FIXME: cfg?
371 let name = it.name().map_or_else(Name::missing, |it| it.as_name()); 235 AssocItem::Const(id) => {
372 let def = ConstLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } 236 let item = &item_tree[id];
373 .intern(db); 237 let name = match item.name.clone() {
374 Some((name, def.into())) 238 Some(name) => name,
239 None => continue,
240 };
241 let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
242 items.push((name, def.into()));
375 } 243 }
376 ast::AssocItem::TypeAliasDef(it) => { 244 AssocItem::TypeAlias(id) => {
377 let name = it.name().map_or_else(Name::missing, |it| it.as_name()); 245 let item = &item_tree[id];
378 let def = 246 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)) } 247 items.push((item.name.clone(), def.into()));
380 .intern(db);
381 Some((name, def.into()))
382 } 248 }
383 }) 249 AssocItem::MacroCall(call) => {
384 .collect() 250 let call = &item_tree[call];
251 let ast_id_map = db.ast_id_map(file_id);
252 let root = db.parse_or_expand(file_id).unwrap();
253 let call = ast_id_map.get(call.ast_id).to_node(&root);
254
255 if let Some((mark, mac)) = expander.enter_expand(db, None, call) {
256 let src: InFile<ast::MacroItems> = expander.to_source(mac);
257 let item_tree = db.item_tree(src.file_id);
258 let iter =
259 item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item);
260 items.extend(collect_items(
261 db,
262 module,
263 expander,
264 iter,
265 src.file_id,
266 container,
267 limit - 1,
268 ));
269
270 expander.exit(db, mark);
271 }
272 }
273 }
274 }
275
276 items
385} 277}
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index 10cc26480..9c3ede2d7 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -14,8 +14,9 @@ use crate::{
14 docs::Documentation, 14 docs::Documentation,
15 generics::GenericParams, 15 generics::GenericParams,
16 import_map::ImportMap, 16 import_map::ImportMap,
17 item_tree::ItemTree,
17 lang_item::{LangItemTarget, LangItems}, 18 lang_item::{LangItemTarget, LangItems},
18 nameres::{raw::RawItems, CrateDefMap}, 19 nameres::CrateDefMap,
19 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, 20 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc,
20 GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, 21 GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId,
21 TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, 22 TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc,
@@ -45,8 +46,8 @@ pub trait InternDatabase: SourceDatabase {
45 46
46#[salsa::query_group(DefDatabaseStorage)] 47#[salsa::query_group(DefDatabaseStorage)]
47pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { 48pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
48 #[salsa::invoke(RawItems::raw_items_query)] 49 #[salsa::invoke(ItemTree::item_tree_query)]
49 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; 50 fn item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
50 51
51 #[salsa::invoke(crate_def_map_wait)] 52 #[salsa::invoke(crate_def_map_wait)]
52 #[salsa::transparent] 53 #[salsa::transparent]
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index 09a5241f7..6a0f493a7 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -42,7 +42,7 @@ pub enum TypeParamProvenance {
42} 42}
43 43
44/// Data about the generic parameters of a function, struct, impl, etc. 44/// Data about the generic parameters of a function, struct, impl, etc.
45#[derive(Clone, PartialEq, Eq, Debug)] 45#[derive(Clone, PartialEq, Eq, Debug, Default)]
46pub struct GenericParams { 46pub struct GenericParams {
47 pub types: Arena<TypeParamData>, 47 pub types: Arena<TypeParamData>,
48 // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>, 48 // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>,
@@ -74,8 +74,53 @@ impl GenericParams {
74 def: GenericDefId, 74 def: GenericDefId,
75 ) -> Arc<GenericParams> { 75 ) -> Arc<GenericParams> {
76 let _p = profile("generic_params_query"); 76 let _p = profile("generic_params_query");
77 let (params, _source_map) = GenericParams::new(db, def); 77
78 Arc::new(params) 78 let generics = match def {
79 GenericDefId::FunctionId(id) => {
80 let id = id.lookup(db).id;
81 let tree = db.item_tree(id.file_id);
82 let item = &tree[id.value];
83 tree[item.generic_params].clone()
84 }
85 GenericDefId::AdtId(AdtId::StructId(id)) => {
86 let id = id.lookup(db).id;
87 let tree = db.item_tree(id.file_id);
88 let item = &tree[id.value];
89 tree[item.generic_params].clone()
90 }
91 GenericDefId::AdtId(AdtId::EnumId(id)) => {
92 let id = id.lookup(db).id;
93 let tree = db.item_tree(id.file_id);
94 let item = &tree[id.value];
95 tree[item.generic_params].clone()
96 }
97 GenericDefId::AdtId(AdtId::UnionId(id)) => {
98 let id = id.lookup(db).id;
99 let tree = db.item_tree(id.file_id);
100 let item = &tree[id.value];
101 tree[item.generic_params].clone()
102 }
103 GenericDefId::TraitId(id) => {
104 let id = id.lookup(db).id;
105 let tree = db.item_tree(id.file_id);
106 let item = &tree[id.value];
107 tree[item.generic_params].clone()
108 }
109 GenericDefId::TypeAliasId(id) => {
110 let id = id.lookup(db).id;
111 let tree = db.item_tree(id.file_id);
112 let item = &tree[id.value];
113 tree[item.generic_params].clone()
114 }
115 GenericDefId::ImplId(id) => {
116 let id = id.lookup(db).id;
117 let tree = db.item_tree(id.file_id);
118 let item = &tree[id.value];
119 tree[item.generic_params].clone()
120 }
121 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(),
122 };
123 Arc::new(generics)
79 } 124 }
80 125
81 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { 126 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {
@@ -156,7 +201,12 @@ impl GenericParams {
156 (generics, InFile::new(file_id, sm)) 201 (generics, InFile::new(file_id, sm))
157 } 202 }
158 203
159 fn fill(&mut self, lower_ctx: &LowerCtx, sm: &mut SourceMap, node: &dyn TypeParamsOwner) { 204 pub(crate) fn fill(
205 &mut self,
206 lower_ctx: &LowerCtx,
207 sm: &mut SourceMap,
208 node: &dyn TypeParamsOwner,
209 ) {
160 if let Some(params) = node.type_param_list() { 210 if let Some(params) = node.type_param_list() {
161 self.fill_params(lower_ctx, sm, params) 211 self.fill_params(lower_ctx, sm, params)
162 } 212 }
@@ -165,7 +215,7 @@ impl GenericParams {
165 } 215 }
166 } 216 }
167 217
168 fn fill_bounds( 218 pub(crate) fn fill_bounds(
169 &mut self, 219 &mut self,
170 lower_ctx: &LowerCtx, 220 lower_ctx: &LowerCtx,
171 node: &dyn ast::TypeBoundsOwner, 221 node: &dyn ast::TypeBoundsOwner,
@@ -229,7 +279,7 @@ impl GenericParams {
229 .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); 279 .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound });
230 } 280 }
231 281
232 fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { 282 pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) {
233 type_ref.walk(&mut |type_ref| { 283 type_ref.walk(&mut |type_ref| {
234 if let TypeRef::ImplTrait(bounds) = type_ref { 284 if let TypeRef::ImplTrait(bounds) = type_ref {
235 let param = TypeParamData { 285 let param = TypeParamData {
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs
new file mode 100644
index 000000000..d7bc64e6c
--- /dev/null
+++ b/crates/ra_hir_def/src/item_tree.rs
@@ -0,0 +1,697 @@
1//! A simplified AST that only contains items.
2
3mod lower;
4#[cfg(test)]
5mod tests;
6
7use std::{
8 fmt::{self, Debug},
9 hash::{Hash, Hasher},
10 marker::PhantomData,
11 ops::{Index, Range},
12 sync::Arc,
13};
14
15use ast::{AstNode, AttrsOwner, NameOwner, StructKind, TypeAscriptionOwner};
16use either::Either;
17use hir_expand::{
18 ast_id_map::FileAstId,
19 hygiene::Hygiene,
20 name::{name, AsName, Name},
21 HirFileId, InFile,
22};
23use ra_arena::{Arena, Idx, RawId};
24use ra_syntax::{ast, match_ast};
25use rustc_hash::FxHashMap;
26use smallvec::SmallVec;
27use test_utils::mark;
28
29use crate::{
30 attr::Attrs,
31 db::DefDatabase,
32 generics::GenericParams,
33 path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
34 type_ref::{Mutability, TypeBound, TypeRef},
35 visibility::RawVisibility,
36};
37
38#[derive(Copy, Clone, Eq, PartialEq)]
39pub struct RawVisibilityId(u32);
40
41impl RawVisibilityId {
42 pub const PUB: Self = RawVisibilityId(u32::max_value());
43 pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1);
44 pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2);
45}
46
47impl fmt::Debug for RawVisibilityId {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 let mut f = f.debug_tuple("RawVisibilityId");
50 match *self {
51 Self::PUB => f.field(&"pub"),
52 Self::PRIV => f.field(&"pub(self)"),
53 Self::PUB_CRATE => f.field(&"pub(crate)"),
54 _ => f.field(&self.0),
55 };
56 f.finish()
57 }
58}
59
60#[derive(Debug, Copy, Clone, Eq, PartialEq)]
61pub struct GenericParamsId(u32);
62
63impl GenericParamsId {
64 pub const EMPTY: Self = GenericParamsId(u32::max_value());
65}
66
67/// The item tree of a source file.
68#[derive(Debug, Eq, PartialEq)]
69pub struct ItemTree {
70 top_level: SmallVec<[ModItem; 1]>,
71 attrs: FxHashMap<AttrOwner, Attrs>,
72 inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>,
73
74 data: Option<Box<ItemTreeData>>,
75}
76
77impl ItemTree {
78 pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
79 let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id));
80 let syntax = if let Some(node) = db.parse_or_expand(file_id) {
81 node
82 } else {
83 return Arc::new(Self::empty());
84 };
85
86 let hygiene = Hygiene::new(db.upcast(), file_id);
87 let ctx = lower::Ctx::new(db, hygiene.clone(), file_id);
88 let mut top_attrs = None;
89 let mut item_tree = match_ast! {
90 match syntax {
91 ast::SourceFile(file) => {
92 top_attrs = Some(Attrs::new(&file, &hygiene));
93 ctx.lower_module_items(&file)
94 },
95 ast::MacroItems(items) => {
96 ctx.lower_module_items(&items)
97 },
98 // Macros can expand to expressions. We return an empty item tree in this case, but
99 // still need to collect inner items.
100 ast::Expr(e) => {
101 ctx.lower_inner_items(e.syntax())
102 },
103 _ => {
104 panic!("cannot create item tree from {:?}", syntax);
105 },
106 }
107 };
108
109 if let Some(attrs) = top_attrs {
110 item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
111 }
112 item_tree.shrink_to_fit();
113 Arc::new(item_tree)
114 }
115
116 fn empty() -> Self {
117 Self {
118 top_level: Default::default(),
119 attrs: Default::default(),
120 inner_items: Default::default(),
121 data: Default::default(),
122 }
123 }
124
125 fn shrink_to_fit(&mut self) {
126 if let Some(data) = &mut self.data {
127 let ItemTreeData {
128 imports,
129 extern_crates,
130 functions,
131 structs,
132 fields,
133 unions,
134 enums,
135 variants,
136 consts,
137 statics,
138 traits,
139 impls,
140 type_aliases,
141 mods,
142 macro_calls,
143 exprs,
144 vis,
145 generics,
146 } = &mut **data;
147
148 imports.shrink_to_fit();
149 extern_crates.shrink_to_fit();
150 functions.shrink_to_fit();
151 structs.shrink_to_fit();
152 fields.shrink_to_fit();
153 unions.shrink_to_fit();
154 enums.shrink_to_fit();
155 variants.shrink_to_fit();
156 consts.shrink_to_fit();
157 statics.shrink_to_fit();
158 traits.shrink_to_fit();
159 impls.shrink_to_fit();
160 type_aliases.shrink_to_fit();
161 mods.shrink_to_fit();
162 macro_calls.shrink_to_fit();
163 exprs.shrink_to_fit();
164
165 vis.arena.shrink_to_fit();
166 generics.arena.shrink_to_fit();
167 }
168 }
169
170 /// Returns an iterator over all items located at the top level of the `HirFileId` this
171 /// `ItemTree` was created from.
172 pub fn top_level_items(&self) -> &[ModItem] {
173 &self.top_level
174 }
175
176 /// Returns the inner attributes of the source file.
177 pub fn top_level_attrs(&self) -> &Attrs {
178 self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&Attrs::EMPTY)
179 }
180
181 pub fn attrs(&self, of: ModItem) -> &Attrs {
182 self.attrs.get(&AttrOwner::ModItem(of)).unwrap_or(&Attrs::EMPTY)
183 }
184
185 /// Returns the lowered inner items that `ast` corresponds to.
186 ///
187 /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered
188 /// to multiple items in the `ItemTree`.
189 pub fn inner_items(&self, ast: FileAstId<ast::ModuleItem>) -> &[ModItem] {
190 &self.inner_items[&ast]
191 }
192
193 pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ {
194 self.inner_items.values().flatten().copied()
195 }
196
197 pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source {
198 // This unwrap cannot fail, since it has either succeeded above, or resulted in an empty
199 // ItemTree (in which case there is no valid `FileItemTreeId` to call this method with).
200 let root =
201 db.parse_or_expand(of.file_id).expect("parse_or_expand failed on constructed ItemTree");
202
203 let id = self[of.value].ast_id();
204 let map = db.ast_id_map(of.file_id);
205 let ptr = map.get(id);
206 ptr.to_node(&root)
207 }
208
209 fn data(&self) -> &ItemTreeData {
210 self.data.as_ref().expect("attempted to access data of empty ItemTree")
211 }
212
213 fn data_mut(&mut self) -> &mut ItemTreeData {
214 self.data.get_or_insert_with(Box::default)
215 }
216}
217
218#[derive(Default, Debug, Eq, PartialEq)]
219struct ItemVisibilities {
220 arena: Arena<RawVisibility>,
221}
222
223impl ItemVisibilities {
224 fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
225 match &vis {
226 RawVisibility::Public => RawVisibilityId::PUB,
227 RawVisibility::Module(path) if path.segments.is_empty() => match &path.kind {
228 PathKind::Super(0) => RawVisibilityId::PRIV,
229 PathKind::Crate => RawVisibilityId::PUB_CRATE,
230 _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
231 },
232 _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
233 }
234 }
235}
236
237static VIS_PUB: RawVisibility = RawVisibility::Public;
238static VIS_PRIV: RawVisibility =
239 RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() });
240static VIS_PUB_CRATE: RawVisibility =
241 RawVisibility::Module(ModPath { kind: PathKind::Crate, segments: Vec::new() });
242
243#[derive(Default, Debug, Eq, PartialEq)]
244struct GenericParamsStorage {
245 arena: Arena<GenericParams>,
246}
247
248impl GenericParamsStorage {
249 fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
250 if params.types.is_empty() && params.where_predicates.is_empty() {
251 return GenericParamsId::EMPTY;
252 }
253
254 GenericParamsId(self.arena.alloc(params).into_raw().into())
255 }
256}
257
258static EMPTY_GENERICS: GenericParams =
259 GenericParams { types: Arena::new(), where_predicates: Vec::new() };
260
261#[derive(Default, Debug, Eq, PartialEq)]
262struct ItemTreeData {
263 imports: Arena<Import>,
264 extern_crates: Arena<ExternCrate>,
265 functions: Arena<Function>,
266 structs: Arena<Struct>,
267 fields: Arena<Field>,
268 unions: Arena<Union>,
269 enums: Arena<Enum>,
270 variants: Arena<Variant>,
271 consts: Arena<Const>,
272 statics: Arena<Static>,
273 traits: Arena<Trait>,
274 impls: Arena<Impl>,
275 type_aliases: Arena<TypeAlias>,
276 mods: Arena<Mod>,
277 macro_calls: Arena<MacroCall>,
278 exprs: Arena<Expr>,
279
280 vis: ItemVisibilities,
281 generics: GenericParamsStorage,
282}
283
284#[derive(Debug, Eq, PartialEq, Hash)]
285enum AttrOwner {
286 /// Attributes on an item.
287 ModItem(ModItem),
288 /// Inner attributes of the source file.
289 TopLevel,
290 // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`.
291}
292
293/// Trait implemented by all nodes in the item tree.
294pub trait ItemTreeNode: Clone {
295 type Source: AstNode + Into<ast::ModuleItem>;
296
297 fn ast_id(&self) -> FileAstId<Self::Source>;
298
299 /// Looks up an instance of `Self` in an item tree.
300 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self;
301
302 /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type.
303 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>>;
304
305 /// Upcasts a `FileItemTreeId` to a generic `ModItem`.
306 fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem;
307}
308
309pub struct FileItemTreeId<N: ItemTreeNode> {
310 index: Idx<N>,
311 _p: PhantomData<N>,
312}
313
314impl<N: ItemTreeNode> Clone for FileItemTreeId<N> {
315 fn clone(&self) -> Self {
316 Self { index: self.index, _p: PhantomData }
317 }
318}
319impl<N: ItemTreeNode> Copy for FileItemTreeId<N> {}
320
321impl<N: ItemTreeNode> PartialEq for FileItemTreeId<N> {
322 fn eq(&self, other: &FileItemTreeId<N>) -> bool {
323 self.index == other.index
324 }
325}
326impl<N: ItemTreeNode> Eq for FileItemTreeId<N> {}
327
328impl<N: ItemTreeNode> Hash for FileItemTreeId<N> {
329 fn hash<H: Hasher>(&self, state: &mut H) {
330 self.index.hash(state)
331 }
332}
333
334impl<N: ItemTreeNode> fmt::Debug for FileItemTreeId<N> {
335 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336 self.index.fmt(f)
337 }
338}
339
340pub type ItemTreeId<N> = InFile<FileItemTreeId<N>>;
341
342macro_rules! mod_items {
343 ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => {
344 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
345 pub enum ModItem {
346 $(
347 $typ(FileItemTreeId<$typ>),
348 )+
349 }
350
351 $(
352 impl From<FileItemTreeId<$typ>> for ModItem {
353 fn from(id: FileItemTreeId<$typ>) -> ModItem {
354 ModItem::$typ(id)
355 }
356 }
357 )+
358
359 $(
360 impl ItemTreeNode for $typ {
361 type Source = $ast;
362
363 fn ast_id(&self) -> FileAstId<Self::Source> {
364 self.ast_id
365 }
366
367 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
368 &tree.data().$fld[index]
369 }
370
371 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> {
372 if let ModItem::$typ(id) = mod_item {
373 Some(id)
374 } else {
375 None
376 }
377 }
378
379 fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem {
380 ModItem::$typ(id)
381 }
382 }
383
384 impl Index<Idx<$typ>> for ItemTree {
385 type Output = $typ;
386
387 fn index(&self, index: Idx<$typ>) -> &Self::Output {
388 &self.data().$fld[index]
389 }
390 }
391 )+
392 };
393}
394
395mod_items! {
396 Import in imports -> ast::UseItem,
397 ExternCrate in extern_crates -> ast::ExternCrateItem,
398 Function in functions -> ast::FnDef,
399 Struct in structs -> ast::StructDef,
400 Union in unions -> ast::UnionDef,
401 Enum in enums -> ast::EnumDef,
402 Const in consts -> ast::ConstDef,
403 Static in statics -> ast::StaticDef,
404 Trait in traits -> ast::TraitDef,
405 Impl in impls -> ast::ImplDef,
406 TypeAlias in type_aliases -> ast::TypeAliasDef,
407 Mod in mods -> ast::Module,
408 MacroCall in macro_calls -> ast::MacroCall,
409}
410
411macro_rules! impl_index {
412 ( $($fld:ident: $t:ty),+ $(,)? ) => {
413 $(
414 impl Index<Idx<$t>> for ItemTree {
415 type Output = $t;
416
417 fn index(&self, index: Idx<$t>) -> &Self::Output {
418 &self.data().$fld[index]
419 }
420 }
421 )+
422 };
423}
424
425impl_index!(fields: Field, variants: Variant, exprs: Expr);
426
427impl Index<RawVisibilityId> for ItemTree {
428 type Output = RawVisibility;
429 fn index(&self, index: RawVisibilityId) -> &Self::Output {
430 match index {
431 RawVisibilityId::PRIV => &VIS_PRIV,
432 RawVisibilityId::PUB => &VIS_PUB,
433 RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
434 _ => &self.data().vis.arena[Idx::from_raw(index.0.into())],
435 }
436 }
437}
438
439impl Index<GenericParamsId> for ItemTree {
440 type Output = GenericParams;
441
442 fn index(&self, index: GenericParamsId) -> &Self::Output {
443 match index {
444 GenericParamsId::EMPTY => &EMPTY_GENERICS,
445 _ => &self.data().generics.arena[Idx::from_raw(index.0.into())],
446 }
447 }
448}
449
450impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
451 type Output = N;
452 fn index(&self, id: FileItemTreeId<N>) -> &N {
453 N::lookup(self, id.index)
454 }
455}
456
457/// A desugared `use` import.
458#[derive(Debug, Clone, Eq, PartialEq)]
459pub struct Import {
460 pub path: ModPath,
461 pub alias: Option<ImportAlias>,
462 pub visibility: RawVisibilityId,
463 pub is_glob: bool,
464 pub is_prelude: bool,
465 /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many
466 /// `Import`s can map to the same `use` item.
467 pub ast_id: FileAstId<ast::UseItem>,
468}
469
470#[derive(Debug, Clone, Eq, PartialEq)]
471pub struct ExternCrate {
472 pub path: ModPath,
473 pub alias: Option<ImportAlias>,
474 pub visibility: RawVisibilityId,
475 /// Whether this is a `#[macro_use] extern crate ...`.
476 pub is_macro_use: bool,
477 pub ast_id: FileAstId<ast::ExternCrateItem>,
478}
479
480#[derive(Debug, Clone, Eq, PartialEq)]
481pub struct Function {
482 pub name: Name,
483 pub visibility: RawVisibilityId,
484 pub generic_params: GenericParamsId,
485 pub has_self_param: bool,
486 pub is_unsafe: bool,
487 pub params: Box<[TypeRef]>,
488 pub ret_type: TypeRef,
489 pub ast_id: FileAstId<ast::FnDef>,
490}
491
492#[derive(Debug, Clone, Eq, PartialEq)]
493pub struct Struct {
494 pub name: Name,
495 pub visibility: RawVisibilityId,
496 pub generic_params: GenericParamsId,
497 pub fields: Fields,
498 pub ast_id: FileAstId<ast::StructDef>,
499 pub kind: StructDefKind,
500}
501
502#[derive(Debug, Clone, Eq, PartialEq)]
503pub enum StructDefKind {
504 /// `struct S { ... }` - type namespace only.
505 Record,
506 /// `struct S(...);`
507 Tuple,
508 /// `struct S;`
509 Unit,
510}
511
512#[derive(Debug, Clone, Eq, PartialEq)]
513pub struct Union {
514 pub name: Name,
515 pub visibility: RawVisibilityId,
516 pub generic_params: GenericParamsId,
517 pub fields: Fields,
518 pub ast_id: FileAstId<ast::UnionDef>,
519}
520
521#[derive(Debug, Clone, Eq, PartialEq)]
522pub struct Enum {
523 pub name: Name,
524 pub visibility: RawVisibilityId,
525 pub generic_params: GenericParamsId,
526 pub variants: Range<Idx<Variant>>,
527 pub ast_id: FileAstId<ast::EnumDef>,
528}
529
530#[derive(Debug, Clone, Eq, PartialEq)]
531pub struct Const {
532 /// const _: () = ();
533 pub name: Option<Name>,
534 pub visibility: RawVisibilityId,
535 pub type_ref: TypeRef,
536 pub ast_id: FileAstId<ast::ConstDef>,
537}
538
539#[derive(Debug, Clone, Eq, PartialEq)]
540pub struct Static {
541 pub name: Name,
542 pub visibility: RawVisibilityId,
543 pub mutable: bool,
544 pub type_ref: TypeRef,
545 pub ast_id: FileAstId<ast::StaticDef>,
546}
547
548#[derive(Debug, Clone, Eq, PartialEq)]
549pub struct Trait {
550 pub name: Name,
551 pub visibility: RawVisibilityId,
552 pub generic_params: GenericParamsId,
553 pub auto: bool,
554 pub items: Box<[AssocItem]>,
555 pub ast_id: FileAstId<ast::TraitDef>,
556}
557
558#[derive(Debug, Clone, Eq, PartialEq)]
559pub struct Impl {
560 pub generic_params: GenericParamsId,
561 pub target_trait: Option<TypeRef>,
562 pub target_type: TypeRef,
563 pub is_negative: bool,
564 pub items: Box<[AssocItem]>,
565 pub ast_id: FileAstId<ast::ImplDef>,
566}
567
568#[derive(Debug, Clone, PartialEq, Eq)]
569pub struct TypeAlias {
570 pub name: Name,
571 pub visibility: RawVisibilityId,
572 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
573 pub bounds: Box<[TypeBound]>,
574 pub generic_params: GenericParamsId,
575 pub type_ref: Option<TypeRef>,
576 pub ast_id: FileAstId<ast::TypeAliasDef>,
577}
578
579#[derive(Debug, Clone, Eq, PartialEq)]
580pub struct Mod {
581 pub name: Name,
582 pub visibility: RawVisibilityId,
583 pub kind: ModKind,
584 pub ast_id: FileAstId<ast::Module>,
585}
586
587#[derive(Debug, Clone, Eq, PartialEq)]
588pub enum ModKind {
589 /// `mod m { ... }`
590 Inline { items: Box<[ModItem]> },
591
592 /// `mod m;`
593 Outline {},
594}
595
596#[derive(Debug, Clone, Eq, PartialEq)]
597pub struct MacroCall {
598 /// For `macro_rules!` declarations, this is the name of the declared macro.
599 pub name: Option<Name>,
600 /// Path to the called macro.
601 pub path: ModPath,
602 /// Has `#[macro_export]`.
603 pub is_export: bool,
604 /// Has `#[macro_export(local_inner_macros)]`.
605 pub is_local_inner: bool,
606 /// Has `#[rustc_builtin_macro]`.
607 pub is_builtin: bool,
608 pub ast_id: FileAstId<ast::MacroCall>,
609}
610
611// NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array
612// lengths, but we don't do much with them yet.
613#[derive(Debug, Clone, Eq, PartialEq)]
614pub struct Expr;
615
616macro_rules! impl_froms {
617 ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => {
618 $(
619 impl From<$t> for $e {
620 fn from(it: $t) -> $e {
621 $e::$v(it)
622 }
623 }
624 )*
625 }
626}
627
628impl ModItem {
629 pub fn as_assoc_item(&self) -> Option<AssocItem> {
630 match self {
631 ModItem::Import(_)
632 | ModItem::ExternCrate(_)
633 | ModItem::Struct(_)
634 | ModItem::Union(_)
635 | ModItem::Enum(_)
636 | ModItem::Static(_)
637 | ModItem::Trait(_)
638 | ModItem::Impl(_)
639 | ModItem::Mod(_) => None,
640 ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
641 ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
642 ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
643 ModItem::Function(func) => Some(AssocItem::Function(*func)),
644 }
645 }
646
647 pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> {
648 N::id_from_mod_item(self)
649 }
650}
651
652#[derive(Debug, Copy, Clone, Eq, PartialEq)]
653pub enum AssocItem {
654 Function(FileItemTreeId<Function>),
655 TypeAlias(FileItemTreeId<TypeAlias>),
656 Const(FileItemTreeId<Const>),
657 MacroCall(FileItemTreeId<MacroCall>),
658}
659
660impl_froms!(AssocItem {
661 Function(FileItemTreeId<Function>),
662 TypeAlias(FileItemTreeId<TypeAlias>),
663 Const(FileItemTreeId<Const>),
664 MacroCall(FileItemTreeId<MacroCall>),
665});
666
667impl From<AssocItem> for ModItem {
668 fn from(item: AssocItem) -> Self {
669 match item {
670 AssocItem::Function(it) => it.into(),
671 AssocItem::TypeAlias(it) => it.into(),
672 AssocItem::Const(it) => it.into(),
673 AssocItem::MacroCall(it) => it.into(),
674 }
675 }
676}
677
678#[derive(Debug, Eq, PartialEq)]
679pub struct Variant {
680 pub name: Name,
681 pub fields: Fields,
682}
683
684#[derive(Debug, Clone, PartialEq, Eq)]
685pub enum Fields {
686 Record(Range<Idx<Field>>),
687 Tuple(Range<Idx<Field>>),
688 Unit,
689}
690
691/// A single field of an enum variant or struct
692#[derive(Debug, Clone, PartialEq, Eq)]
693pub struct Field {
694 pub name: Name,
695 pub type_ref: TypeRef,
696 pub visibility: RawVisibilityId,
697}
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs
new file mode 100644
index 000000000..f10ad25f7
--- /dev/null
+++ b/crates/ra_hir_def/src/item_tree/lower.rs
@@ -0,0 +1,695 @@
1//! AST -> `ItemTree` lowering code.
2
3use super::*;
4use crate::{
5 attr::Attrs,
6 generics::{GenericParams, TypeParamData, TypeParamProvenance},
7};
8use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId};
9use ra_arena::map::ArenaMap;
10use ra_syntax::{
11 ast::{self, ModuleItemOwner},
12 SyntaxNode,
13};
14use smallvec::SmallVec;
15use std::{collections::hash_map::Entry, mem, sync::Arc};
16
17fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
18 FileItemTreeId { index, _p: PhantomData }
19}
20
21struct ModItems(SmallVec<[ModItem; 1]>);
22
23impl<T> From<T> for ModItems
24where
25 T: Into<ModItem>,
26{
27 fn from(t: T) -> Self {
28 ModItems(SmallVec::from_buf([t.into(); 1]))
29 }
30}
31
32pub(super) struct Ctx {
33 tree: ItemTree,
34 hygiene: Hygiene,
35 file: HirFileId,
36 source_ast_id_map: Arc<AstIdMap>,
37 body_ctx: crate::body::LowerCtx,
38 inner_items: Vec<ModItem>,
39 forced_visibility: Option<RawVisibilityId>,
40}
41
42impl Ctx {
43 pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self {
44 Self {
45 tree: ItemTree::empty(),
46 hygiene,
47 file,
48 source_ast_id_map: db.ast_id_map(file),
49 body_ctx: crate::body::LowerCtx::new(db, file),
50 inner_items: Vec::new(),
51 forced_visibility: None,
52 }
53 }
54
55 pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree {
56 self.tree.top_level = item_owner
57 .items()
58 .flat_map(|item| self.lower_mod_item(&item, false))
59 .flat_map(|items| items.0)
60 .collect();
61 self.tree
62 }
63
64 pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree {
65 self.collect_inner_items(within);
66 self.tree
67 }
68
69 fn data(&mut self) -> &mut ItemTreeData {
70 self.tree.data_mut()
71 }
72
73 fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option<ModItems> {
74 assert!(inner || self.inner_items.is_empty());
75
76 // Collect inner items for 1-to-1-lowered items.
77 match item {
78 ast::ModuleItem::StructDef(_)
79 | ast::ModuleItem::UnionDef(_)
80 | ast::ModuleItem::EnumDef(_)
81 | ast::ModuleItem::FnDef(_)
82 | ast::ModuleItem::TypeAliasDef(_)
83 | ast::ModuleItem::ConstDef(_)
84 | ast::ModuleItem::StaticDef(_)
85 | ast::ModuleItem::MacroCall(_) => {
86 // Skip this if we're already collecting inner items. We'll descend into all nodes
87 // already.
88 if !inner {
89 self.collect_inner_items(item.syntax());
90 }
91 }
92
93 // These are handled in their respective `lower_X` method (since we can't just blindly
94 // walk them).
95 ast::ModuleItem::TraitDef(_)
96 | ast::ModuleItem::ImplDef(_)
97 | ast::ModuleItem::ExternBlock(_) => {}
98
99 // These don't have inner items.
100 ast::ModuleItem::Module(_)
101 | ast::ModuleItem::ExternCrateItem(_)
102 | ast::ModuleItem::UseItem(_) => {}
103 };
104
105 let attrs = Attrs::new(item, &self.hygiene);
106 let items = match item {
107 ast::ModuleItem::StructDef(ast) => self.lower_struct(ast).map(Into::into),
108 ast::ModuleItem::UnionDef(ast) => self.lower_union(ast).map(Into::into),
109 ast::ModuleItem::EnumDef(ast) => self.lower_enum(ast).map(Into::into),
110 ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into),
111 ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into),
112 ast::ModuleItem::StaticDef(ast) => self.lower_static(ast).map(Into::into),
113 ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()),
114 ast::ModuleItem::Module(ast) => self.lower_module(ast).map(Into::into),
115 ast::ModuleItem::TraitDef(ast) => self.lower_trait(ast).map(Into::into),
116 ast::ModuleItem::ImplDef(ast) => self.lower_impl(ast).map(Into::into),
117 ast::ModuleItem::UseItem(ast) => Some(ModItems(
118 self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(),
119 )),
120 ast::ModuleItem::ExternCrateItem(ast) => self.lower_extern_crate(ast).map(Into::into),
121 ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
122 ast::ModuleItem::ExternBlock(ast) => {
123 Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
124 }
125 };
126
127 if !attrs.is_empty() {
128 for item in items.iter().flat_map(|items| &items.0) {
129 self.add_attrs(*item, attrs.clone());
130 }
131 }
132
133 items
134 }
135
136 fn add_attrs(&mut self, item: ModItem, attrs: Attrs) {
137 match self.tree.attrs.entry(AttrOwner::ModItem(item)) {
138 Entry::Occupied(mut entry) => {
139 *entry.get_mut() = entry.get().merge(attrs);
140 }
141 Entry::Vacant(entry) => {
142 entry.insert(attrs);
143 }
144 }
145 }
146
147 fn collect_inner_items(&mut self, container: &SyntaxNode) {
148 let forced_vis = self.forced_visibility.take();
149 let mut inner_items = mem::take(&mut self.tree.inner_items);
150 inner_items.extend(
151 container.descendants().skip(1).filter_map(ast::ModuleItem::cast).filter_map(|item| {
152 let ast_id = self.source_ast_id_map.ast_id(&item);
153 Some((ast_id, self.lower_mod_item(&item, true)?.0))
154 }),
155 );
156 self.tree.inner_items = inner_items;
157 self.forced_visibility = forced_vis;
158 }
159
160 fn lower_assoc_item(&mut self, item: &ast::ModuleItem) -> Option<AssocItem> {
161 match item {
162 ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into),
163 ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into),
164 ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()),
165 ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
166 _ => None,
167 }
168 }
169
170 fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option<FileItemTreeId<Struct>> {
171 let visibility = self.lower_visibility(strukt);
172 let name = strukt.name()?.as_name();
173 let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt);
174 let fields = self.lower_fields(&strukt.kind());
175 let ast_id = self.source_ast_id_map.ast_id(strukt);
176 let kind = match strukt.kind() {
177 ast::StructKind::Record(_) => StructDefKind::Record,
178 ast::StructKind::Tuple(_) => StructDefKind::Tuple,
179 ast::StructKind::Unit => StructDefKind::Unit,
180 };
181 let res = Struct { name, visibility, generic_params, fields, ast_id, kind };
182 Some(id(self.data().structs.alloc(res)))
183 }
184
185 fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields {
186 match strukt_kind {
187 ast::StructKind::Record(it) => {
188 let range = self.lower_record_fields(it);
189 Fields::Record(range)
190 }
191 ast::StructKind::Tuple(it) => {
192 let range = self.lower_tuple_fields(it);
193 Fields::Tuple(range)
194 }
195 ast::StructKind::Unit => Fields::Unit,
196 }
197 }
198
199 fn lower_record_fields(&mut self, fields: &ast::RecordFieldDefList) -> Range<Idx<Field>> {
200 let start = self.next_field_idx();
201 for field in fields.fields() {
202 if let Some(data) = self.lower_record_field(&field) {
203 self.data().fields.alloc(data);
204 }
205 }
206 let end = self.next_field_idx();
207 start..end
208 }
209
210 fn lower_record_field(&mut self, field: &ast::RecordFieldDef) -> Option<Field> {
211 let name = field.name()?.as_name();
212 let visibility = self.lower_visibility(field);
213 let type_ref = self.lower_type_ref(&field.ascribed_type()?);
214 let res = Field { name, type_ref, visibility };
215 Some(res)
216 }
217
218 fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldDefList) -> Range<Idx<Field>> {
219 let start = self.next_field_idx();
220 for (i, field) in fields.fields().enumerate() {
221 if let Some(data) = self.lower_tuple_field(i, &field) {
222 self.data().fields.alloc(data);
223 }
224 }
225 let end = self.next_field_idx();
226 start..end
227 }
228
229 fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleFieldDef) -> Option<Field> {
230 let name = Name::new_tuple_field(idx);
231 let visibility = self.lower_visibility(field);
232 let type_ref = self.lower_type_ref(&field.type_ref()?);
233 let res = Field { name, type_ref, visibility };
234 Some(res)
235 }
236
237 fn lower_union(&mut self, union: &ast::UnionDef) -> Option<FileItemTreeId<Union>> {
238 let visibility = self.lower_visibility(union);
239 let name = union.name()?.as_name();
240 let generic_params = self.lower_generic_params(GenericsOwner::Union, union);
241 let fields = match union.record_field_def_list() {
242 Some(record_field_def_list) => {
243 self.lower_fields(&StructKind::Record(record_field_def_list))
244 }
245 None => Fields::Record(self.next_field_idx()..self.next_field_idx()),
246 };
247 let ast_id = self.source_ast_id_map.ast_id(union);
248 let res = Union { name, visibility, generic_params, fields, ast_id };
249 Some(id(self.data().unions.alloc(res)))
250 }
251
252 fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option<FileItemTreeId<Enum>> {
253 let visibility = self.lower_visibility(enum_);
254 let name = enum_.name()?.as_name();
255 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_);
256 let variants = match &enum_.variant_list() {
257 Some(variant_list) => self.lower_variants(variant_list),
258 None => self.next_variant_idx()..self.next_variant_idx(),
259 };
260 let ast_id = self.source_ast_id_map.ast_id(enum_);
261 let res = Enum { name, visibility, generic_params, variants, ast_id };
262 Some(id(self.data().enums.alloc(res)))
263 }
264
265 fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range<Idx<Variant>> {
266 let start = self.next_variant_idx();
267 for variant in variants.variants() {
268 if let Some(data) = self.lower_variant(&variant) {
269 self.data().variants.alloc(data);
270 }
271 }
272 let end = self.next_variant_idx();
273 start..end
274 }
275
276 fn lower_variant(&mut self, variant: &ast::EnumVariant) -> Option<Variant> {
277 let name = variant.name()?.as_name();
278 let fields = self.lower_fields(&variant.kind());
279 let res = Variant { name, fields };
280 Some(res)
281 }
282
283 fn lower_function(&mut self, func: &ast::FnDef) -> Option<FileItemTreeId<Function>> {
284 let visibility = self.lower_visibility(func);
285 let name = func.name()?.as_name();
286
287 let mut params = Vec::new();
288 let mut has_self_param = false;
289 if let Some(param_list) = func.param_list() {
290 if let Some(self_param) = param_list.self_param() {
291 let self_type = match self_param.ascribed_type() {
292 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
293 None => {
294 let self_type = TypeRef::Path(name![Self].into());
295 match self_param.kind() {
296 ast::SelfParamKind::Owned => self_type,
297 ast::SelfParamKind::Ref => {
298 TypeRef::Reference(Box::new(self_type), Mutability::Shared)
299 }
300 ast::SelfParamKind::MutRef => {
301 TypeRef::Reference(Box::new(self_type), Mutability::Mut)
302 }
303 }
304 }
305 };
306 params.push(self_type);
307 has_self_param = true;
308 }
309 for param in param_list.params() {
310 let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ascribed_type());
311 params.push(type_ref);
312 }
313 }
314 let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) {
315 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
316 _ => TypeRef::unit(),
317 };
318
319 let ret_type = if func.async_token().is_some() {
320 let future_impl = desugar_future_path(ret_type);
321 let ty_bound = TypeBound::Path(future_impl);
322 TypeRef::ImplTrait(vec![ty_bound])
323 } else {
324 ret_type
325 };
326
327 let ast_id = self.source_ast_id_map.ast_id(func);
328 let mut res = Function {
329 name,
330 visibility,
331 generic_params: GenericParamsId::EMPTY,
332 has_self_param,
333 is_unsafe: func.unsafe_token().is_some(),
334 params: params.into_boxed_slice(),
335 ret_type,
336 ast_id,
337 };
338 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
339
340 Some(id(self.data().functions.alloc(res)))
341 }
342
343 fn lower_type_alias(
344 &mut self,
345 type_alias: &ast::TypeAliasDef,
346 ) -> Option<FileItemTreeId<TypeAlias>> {
347 let name = type_alias.name()?.as_name();
348 let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it));
349 let visibility = self.lower_visibility(type_alias);
350 let bounds = self.lower_type_bounds(type_alias);
351 let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias);
352 let ast_id = self.source_ast_id_map.ast_id(type_alias);
353 let res = TypeAlias {
354 name,
355 visibility,
356 bounds: bounds.into_boxed_slice(),
357 generic_params,
358 type_ref,
359 ast_id,
360 };
361 Some(id(self.data().type_aliases.alloc(res)))
362 }
363
364 fn lower_static(&mut self, static_: &ast::StaticDef) -> Option<FileItemTreeId<Static>> {
365 let name = static_.name()?.as_name();
366 let type_ref = self.lower_type_ref_opt(static_.ascribed_type());
367 let visibility = self.lower_visibility(static_);
368 let mutable = static_.mut_token().is_some();
369 let ast_id = self.source_ast_id_map.ast_id(static_);
370 let res = Static { name, visibility, mutable, type_ref, ast_id };
371 Some(id(self.data().statics.alloc(res)))
372 }
373
374 fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId<Const> {
375 let name = konst.name().map(|it| it.as_name());
376 let type_ref = self.lower_type_ref_opt(konst.ascribed_type());
377 let visibility = self.lower_visibility(konst);
378 let ast_id = self.source_ast_id_map.ast_id(konst);
379 let res = Const { name, visibility, type_ref, ast_id };
380 id(self.data().consts.alloc(res))
381 }
382
383 fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> {
384 let name = module.name()?.as_name();
385 let visibility = self.lower_visibility(module);
386 let kind = if module.semicolon_token().is_some() {
387 ModKind::Outline {}
388 } else {
389 ModKind::Inline {
390 items: module
391 .item_list()
392 .map(|list| {
393 list.items()
394 .flat_map(|item| self.lower_mod_item(&item, false))
395 .flat_map(|items| items.0)
396 .collect()
397 })
398 .unwrap_or_else(|| {
399 mark::hit!(name_res_works_for_broken_modules);
400 Box::new([]) as Box<[_]>
401 }),
402 }
403 };
404 let ast_id = self.source_ast_id_map.ast_id(module);
405 let res = Mod { name, visibility, kind, ast_id };
406 Some(id(self.data().mods.alloc(res)))
407 }
408
409 fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option<FileItemTreeId<Trait>> {
410 let name = trait_def.name()?.as_name();
411 let visibility = self.lower_visibility(trait_def);
412 let generic_params =
413 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
414 let auto = trait_def.auto_token().is_some();
415 let items = trait_def.item_list().map(|list| {
416 self.with_inherited_visibility(visibility, |this| {
417 list.items()
418 .filter_map(|item| {
419 let attrs = Attrs::new(&item, &this.hygiene);
420 this.collect_inner_items(item.syntax());
421 this.lower_assoc_item(&item).map(|item| {
422 this.add_attrs(item.into(), attrs);
423 item
424 })
425 })
426 .collect()
427 })
428 });
429 let ast_id = self.source_ast_id_map.ast_id(trait_def);
430 let res = Trait {
431 name,
432 visibility,
433 generic_params,
434 auto,
435 items: items.unwrap_or_default(),
436 ast_id,
437 };
438 Some(id(self.data().traits.alloc(res)))
439 }
440
441 fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option<FileItemTreeId<Impl>> {
442 let generic_params =
443 self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def);
444 let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr));
445 let target_type = self.lower_type_ref(&impl_def.target_type()?);
446 let is_negative = impl_def.excl_token().is_some();
447
448 // We cannot use `assoc_items()` here as that does not include macro calls.
449 let items = impl_def
450 .item_list()?
451 .items()
452 .filter_map(|item| {
453 self.collect_inner_items(item.syntax());
454 let assoc = self.lower_assoc_item(&item)?;
455 let attrs = Attrs::new(&item, &self.hygiene);
456 self.add_attrs(assoc.into(), attrs);
457 Some(assoc)
458 })
459 .collect();
460 let ast_id = self.source_ast_id_map.ast_id(impl_def);
461 let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id };
462 Some(id(self.data().impls.alloc(res)))
463 }
464
465 fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec<FileItemTreeId<Import>> {
466 // FIXME: cfg_attr
467 let is_prelude = use_item.has_atom_attr("prelude_import");
468 let visibility = self.lower_visibility(use_item);
469 let ast_id = self.source_ast_id_map.ast_id(use_item);
470
471 // Every use item can expand to many `Import`s.
472 let mut imports = Vec::new();
473 let tree = self.tree.data_mut();
474 ModPath::expand_use_item(
475 InFile::new(self.file, use_item.clone()),
476 &self.hygiene,
477 |path, _tree, is_glob, alias| {
478 imports.push(id(tree.imports.alloc(Import {
479 path,
480 alias,
481 visibility,
482 is_glob,
483 is_prelude,
484 ast_id,
485 })));
486 },
487 );
488
489 imports
490 }
491
492 fn lower_extern_crate(
493 &mut self,
494 extern_crate: &ast::ExternCrateItem,
495 ) -> Option<FileItemTreeId<ExternCrate>> {
496 let path = ModPath::from_name_ref(&extern_crate.name_ref()?);
497 let alias = extern_crate.alias().map(|a| {
498 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
499 });
500 let visibility = self.lower_visibility(extern_crate);
501 let ast_id = self.source_ast_id_map.ast_id(extern_crate);
502 // FIXME: cfg_attr
503 let is_macro_use = extern_crate.has_atom_attr("macro_use");
504
505 let res = ExternCrate { path, alias, visibility, is_macro_use, ast_id };
506 Some(id(self.data().extern_crates.alloc(res)))
507 }
508
509 fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
510 let name = m.name().map(|it| it.as_name());
511 let attrs = Attrs::new(m, &self.hygiene);
512 let path = ModPath::from_src(m.path()?, &self.hygiene)?;
513
514 let ast_id = self.source_ast_id_map.ast_id(m);
515
516 // FIXME: cfg_attr
517 let export_attr = attrs.by_key("macro_export");
518
519 let is_export = export_attr.exists();
520 let is_local_inner = if is_export {
521 export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it {
522 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
523 ident.text.contains("local_inner_macros")
524 }
525 _ => false,
526 })
527 } else {
528 false
529 };
530
531 let is_builtin = attrs.by_key("rustc_builtin_macro").exists();
532 let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id };
533 Some(id(self.data().macro_calls.alloc(res)))
534 }
535
536 fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
537 block.extern_item_list().map_or(Vec::new(), |list| {
538 list.extern_items()
539 .filter_map(|item| {
540 self.collect_inner_items(item.syntax());
541 let attrs = Attrs::new(&item, &self.hygiene);
542 let id = match item {
543 ast::ExternItem::FnDef(ast) => {
544 let func = self.lower_function(&ast)?;
545 func.into()
546 }
547 ast::ExternItem::StaticDef(ast) => {
548 let statik = self.lower_static(&ast)?;
549 statik.into()
550 }
551 };
552 self.add_attrs(id, attrs);
553 Some(id)
554 })
555 .collect()
556 })
557 }
558
559 /// Lowers generics defined on `node` and collects inner items defined within.
560 fn lower_generic_params_and_inner_items(
561 &mut self,
562 owner: GenericsOwner<'_>,
563 node: &impl ast::TypeParamsOwner,
564 ) -> GenericParamsId {
565 // Generics are part of item headers and may contain inner items we need to collect.
566 if let Some(params) = node.type_param_list() {
567 self.collect_inner_items(params.syntax());
568 }
569 if let Some(clause) = node.where_clause() {
570 self.collect_inner_items(clause.syntax());
571 }
572
573 self.lower_generic_params(owner, node)
574 }
575
576 fn lower_generic_params(
577 &mut self,
578 owner: GenericsOwner<'_>,
579 node: &impl ast::TypeParamsOwner,
580 ) -> GenericParamsId {
581 let mut sm = &mut ArenaMap::default();
582 let mut generics = GenericParams::default();
583 match owner {
584 GenericsOwner::Function(func) => {
585 generics.fill(&self.body_ctx, sm, node);
586 // lower `impl Trait` in arguments
587 for param in &*func.params {
588 generics.fill_implicit_impl_trait_args(param);
589 }
590 }
591 GenericsOwner::Struct
592 | GenericsOwner::Enum
593 | GenericsOwner::Union
594 | GenericsOwner::TypeAlias => {
595 generics.fill(&self.body_ctx, sm, node);
596 }
597 GenericsOwner::Trait(trait_def) => {
598 // traits get the Self type as an implicit first type parameter
599 let self_param_id = generics.types.alloc(TypeParamData {
600 name: Some(name![Self]),
601 default: None,
602 provenance: TypeParamProvenance::TraitSelf,
603 });
604 sm.insert(self_param_id, Either::Left(trait_def.clone()));
605 // add super traits as bounds on Self
606 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
607 let self_param = TypeRef::Path(name![Self].into());
608 generics.fill_bounds(&self.body_ctx, trait_def, self_param);
609
610 generics.fill(&self.body_ctx, &mut sm, node);
611 }
612 GenericsOwner::Impl => {
613 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
614 // type-parameter, but rather is a type-alias for impl's target
615 // type, so this is handled by the resolver.
616 generics.fill(&self.body_ctx, &mut sm, node);
617 }
618 }
619
620 self.data().generics.alloc(generics)
621 }
622
623 fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> {
624 match node.type_bound_list() {
625 Some(bound_list) => {
626 bound_list.bounds().map(|it| TypeBound::from_ast(&self.body_ctx, it)).collect()
627 }
628 None => Vec::new(),
629 }
630 }
631
632 fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId {
633 let vis = match self.forced_visibility {
634 Some(vis) => return vis,
635 None => RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene),
636 };
637
638 self.data().vis.alloc(vis)
639 }
640
641 fn lower_type_ref(&self, type_ref: &ast::TypeRef) -> TypeRef {
642 TypeRef::from_ast(&self.body_ctx, type_ref.clone())
643 }
644 fn lower_type_ref_opt(&self, type_ref: Option<ast::TypeRef>) -> TypeRef {
645 type_ref.map(|ty| self.lower_type_ref(&ty)).unwrap_or(TypeRef::Error)
646 }
647
648 /// Forces the visibility `vis` to be used for all items lowered during execution of `f`.
649 fn with_inherited_visibility<R>(
650 &mut self,
651 vis: RawVisibilityId,
652 f: impl FnOnce(&mut Self) -> R,
653 ) -> R {
654 let old = mem::replace(&mut self.forced_visibility, Some(vis));
655 let res = f(self);
656 self.forced_visibility = old;
657 res
658 }
659
660 fn next_field_idx(&self) -> Idx<Field> {
661 Idx::from_raw(RawId::from(
662 self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32),
663 ))
664 }
665 fn next_variant_idx(&self) -> Idx<Variant> {
666 Idx::from_raw(RawId::from(
667 self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
668 ))
669 }
670}
671
672fn desugar_future_path(orig: TypeRef) -> Path {
673 let path = path![core::future::Future];
674 let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect();
675 let mut last = GenericArgs::empty();
676 let binding =
677 AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() };
678 last.bindings.push(binding);
679 generic_args.push(Some(Arc::new(last)));
680
681 Path::from_known_path(path, generic_args)
682}
683
684enum GenericsOwner<'a> {
685 /// We need access to the partially-lowered `Function` for lowering `impl Trait` in argument
686 /// position.
687 Function(&'a Function),
688 Struct,
689 Enum,
690 Union,
691 /// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter.
692 Trait(&'a ast::TraitDef),
693 TypeAlias,
694 Impl,
695}
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..dc035d809
--- /dev/null
+++ b/crates/ra_hir_def/src/item_tree/tests.rs
@@ -0,0 +1,435 @@
1use super::{ItemTree, ModItem, ModKind};
2use crate::{db::DefDatabase, test_db::TestDB};
3use hir_expand::{db::AstDatabase, HirFileId, InFile};
4use insta::assert_snapshot;
5use ra_db::fixture::WithFixture;
6use ra_syntax::{ast, AstNode};
7use rustc_hash::FxHashSet;
8use std::sync::Arc;
9use stdx::format_to;
10
11fn test_inner_items(ra_fixture: &str) {
12 let (db, file_id) = TestDB::with_single_file(ra_fixture);
13 let file_id = HirFileId::from(file_id);
14 let tree = db.item_tree(file_id);
15 let root = db.parse_or_expand(file_id).unwrap();
16 let ast_id_map = db.ast_id_map(file_id);
17
18 // Traverse the item tree and collect all module/impl/trait-level items as AST nodes.
19 let mut outer_items = FxHashSet::default();
20 let mut worklist = tree.top_level_items().to_vec();
21 while let Some(item) = worklist.pop() {
22 let node: ast::ModuleItem = match item {
23 ModItem::Import(it) => tree.source(&db, InFile::new(file_id, it)).into(),
24 ModItem::ExternCrate(it) => tree.source(&db, InFile::new(file_id, it)).into(),
25 ModItem::Function(it) => tree.source(&db, InFile::new(file_id, it)).into(),
26 ModItem::Struct(it) => tree.source(&db, InFile::new(file_id, it)).into(),
27 ModItem::Union(it) => tree.source(&db, InFile::new(file_id, it)).into(),
28 ModItem::Enum(it) => tree.source(&db, InFile::new(file_id, it)).into(),
29 ModItem::Const(it) => tree.source(&db, InFile::new(file_id, it)).into(),
30 ModItem::Static(it) => tree.source(&db, InFile::new(file_id, it)).into(),
31 ModItem::TypeAlias(it) => tree.source(&db, InFile::new(file_id, it)).into(),
32 ModItem::Mod(it) => {
33 if let ModKind::Inline { items } = &tree[it].kind {
34 worklist.extend(&**items);
35 }
36 tree.source(&db, InFile::new(file_id, it)).into()
37 }
38 ModItem::Trait(it) => {
39 worklist.extend(tree[it].items.iter().map(|item| ModItem::from(*item)));
40 tree.source(&db, InFile::new(file_id, it)).into()
41 }
42 ModItem::Impl(it) => {
43 worklist.extend(tree[it].items.iter().map(|item| ModItem::from(*item)));
44 tree.source(&db, InFile::new(file_id, it)).into()
45 }
46 ModItem::MacroCall(_) => continue,
47 };
48
49 outer_items.insert(node);
50 }
51
52 // Now descend the root node and check that all `ast::ModuleItem`s are either recorded above, or
53 // registered as inner items.
54 for item in root.descendants().skip(1).filter_map(ast::ModuleItem::cast) {
55 if outer_items.contains(&item) {
56 continue;
57 }
58
59 let ast_id = ast_id_map.ast_id(&item);
60 assert!(!tree.inner_items(ast_id).is_empty());
61 }
62}
63
64fn item_tree(ra_fixture: &str) -> Arc<ItemTree> {
65 let (db, file_id) = TestDB::with_single_file(ra_fixture);
66 db.item_tree(file_id.into())
67}
68
69fn print_item_tree(ra_fixture: &str) -> String {
70 let tree = item_tree(ra_fixture);
71 let mut out = String::new();
72
73 format_to!(out, "inner attrs: {:?}\n\n", tree.top_level_attrs());
74 format_to!(out, "top-level items:\n");
75 for item in tree.top_level_items() {
76 fmt_mod_item(&mut out, &tree, *item);
77 format_to!(out, "\n");
78 }
79
80 if !tree.inner_items.is_empty() {
81 format_to!(out, "\ninner items:\n\n");
82 for (ast_id, items) in &tree.inner_items {
83 format_to!(out, "for AST {:?}:\n", ast_id);
84 for inner in items {
85 fmt_mod_item(&mut out, &tree, *inner);
86 format_to!(out, "\n\n");
87 }
88 }
89 }
90
91 out
92}
93
94fn fmt_mod_item(out: &mut String, tree: &ItemTree, item: ModItem) {
95 let attrs = tree.attrs(item);
96 if !attrs.is_empty() {
97 format_to!(out, "#[{:?}]\n", attrs);
98 }
99
100 let mut children = String::new();
101 match item {
102 ModItem::ExternCrate(it) => {
103 format_to!(out, "{:?}", tree[it]);
104 }
105 ModItem::Import(it) => {
106 format_to!(out, "{:?}", tree[it]);
107 }
108 ModItem::Function(it) => {
109 format_to!(out, "{:?}", tree[it]);
110 }
111 ModItem::Struct(it) => {
112 format_to!(out, "{:?}", tree[it]);
113 }
114 ModItem::Union(it) => {
115 format_to!(out, "{:?}", tree[it]);
116 }
117 ModItem::Enum(it) => {
118 format_to!(out, "{:?}", tree[it]);
119 }
120 ModItem::Const(it) => {
121 format_to!(out, "{:?}", tree[it]);
122 }
123 ModItem::Static(it) => {
124 format_to!(out, "{:?}", tree[it]);
125 }
126 ModItem::Trait(it) => {
127 format_to!(out, "{:?}", tree[it]);
128 for item in &*tree[it].items {
129 fmt_mod_item(&mut children, tree, ModItem::from(*item));
130 format_to!(children, "\n");
131 }
132 }
133 ModItem::Impl(it) => {
134 format_to!(out, "{:?}", tree[it]);
135 for item in &*tree[it].items {
136 fmt_mod_item(&mut children, tree, ModItem::from(*item));
137 format_to!(children, "\n");
138 }
139 }
140 ModItem::TypeAlias(it) => {
141 format_to!(out, "{:?}", tree[it]);
142 }
143 ModItem::Mod(it) => {
144 format_to!(out, "{:?}", tree[it]);
145 match &tree[it].kind {
146 ModKind::Inline { items } => {
147 for item in &**items {
148 fmt_mod_item(&mut children, tree, *item);
149 format_to!(children, "\n");
150 }
151 }
152 ModKind::Outline {} => {}
153 }
154 }
155 ModItem::MacroCall(it) => {
156 format_to!(out, "{:?}", tree[it]);
157 }
158 }
159
160 for line in children.lines() {
161 format_to!(out, "\n> {}", line);
162 }
163}
164
165#[test]
166fn smoke() {
167 assert_snapshot!(print_item_tree(r"
168 #![attr]
169
170 #[attr_on_use]
171 use {a, b::*};
172
173 #[ext_crate]
174 extern crate krate;
175
176 #[on_trait]
177 trait Tr<U> {
178 #[assoc_ty]
179 type AssocTy: Tr<()>;
180
181 #[assoc_const]
182 const CONST: u8;
183
184 #[assoc_method]
185 fn method(&self);
186
187 #[assoc_dfl_method]
188 fn dfl_method(&mut self) {}
189 }
190
191 #[struct0]
192 struct Struct0<T = ()>;
193
194 #[struct1]
195 struct Struct1<T>(#[struct1fld] u8);
196
197 #[struct2]
198 struct Struct2<T> {
199 #[struct2fld]
200 fld: (T, ),
201 }
202
203 #[en]
204 enum En {
205 #[enum_variant]
206 Variant {
207 #[enum_field]
208 field: u8,
209 },
210 }
211
212 #[un]
213 union Un {
214 #[union_fld]
215 fld: u16,
216 }
217 "), @r###"
218inner attrs: Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr"))] }, input: None }]) }
219
220top-level items:
221#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }]
222Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) }
223#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }]
224Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) }
225#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }]
226ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ExternCrateItem>(1) }
227#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }]
228Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), 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) }
229> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }]
230> TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParamsId(4294967295), type_ref: None, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TypeAliasDef>(8) }
231> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }]
232> Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ConstDef>(9) }
233> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }]
234> Function { name: Name(Text("method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(10) }
235> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_dfl_method"))] }, input: None }]) }]
236> Function { name: Name(Text("dfl_method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(11) }
237#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct0"))] }, input: None }]) }]
238Struct { name: Name(Text("Struct0")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), fields: Unit, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(3), kind: Unit }
239#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct1"))] }, input: None }]) }]
240Struct { name: Name(Text("Struct1")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(2), fields: Tuple(Idx::<Field>(0)..Idx::<Field>(1)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(4), kind: Tuple }
241#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct2"))] }, input: None }]) }]
242Struct { name: Name(Text("Struct2")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(3), fields: Record(Idx::<Field>(1)..Idx::<Field>(2)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(5), kind: Record }
243#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("en"))] }, input: None }]) }]
244Enum { name: Name(Text("En")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), variants: Idx::<Variant>(0)..Idx::<Variant>(1), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::EnumDef>(6) }
245#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("un"))] }, input: None }]) }]
246Union { name: Name(Text("Un")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), fields: Record(Idx::<Field>(3)..Idx::<Field>(4)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UnionDef>(7) }
247 "###);
248}
249
250#[test]
251fn simple_inner_items() {
252 let tree = print_item_tree(
253 r"
254 impl<T:A> D for Response<T> {
255 fn foo() {
256 end();
257 fn end<W: Write>() {
258 let _x: T = loop {};
259 }
260 }
261 }
262 ",
263 );
264
265 assert_snapshot!(tree, @r###"
266inner attrs: Attrs { entries: None }
267
268top-level items:
269Impl { generic_params: GenericParamsId(0), 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) }
270> Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
271
272inner items:
273
274for AST FileAstId::<ra_syntax::ast::generated::nodes::ModuleItem>(2):
275Function { name: Name(Text("end")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
276
277 "###);
278}
279
280#[test]
281fn extern_attrs() {
282 let tree = print_item_tree(
283 r#"
284 #[block_attr]
285 extern "C" {
286 #[attr_a]
287 fn a() {}
288 #[attr_b]
289 fn b() {}
290 }
291 "#,
292 );
293
294 assert_snapshot!(tree, @r###"
295inner attrs: Attrs { entries: None }
296
297top-level items:
298#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }]
299Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
300#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }]
301Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
302 "###);
303}
304
305#[test]
306fn trait_attrs() {
307 let tree = print_item_tree(
308 r#"
309 #[trait_attr]
310 trait Tr {
311 #[attr_a]
312 fn a() {}
313 #[attr_b]
314 fn b() {}
315 }
316 "#,
317 );
318
319 assert_snapshot!(tree, @r###"
320inner attrs: Attrs { entries: None }
321
322top-level items:
323#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("trait_attr"))] }, input: None }]) }]
324Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(0) }
325> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }]
326> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
327> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }]
328> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
329 "###);
330}
331
332#[test]
333fn impl_attrs() {
334 let tree = print_item_tree(
335 r#"
336 #[impl_attr]
337 impl Ty {
338 #[attr_a]
339 fn a() {}
340 #[attr_b]
341 fn b() {}
342 }
343 "#,
344 );
345
346 assert_snapshot!(tree, @r###"
347inner attrs: Attrs { entries: None }
348
349top-level items:
350#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("impl_attr"))] }, input: None }]) }]
351Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) }
352> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }]
353> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
354> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }]
355> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
356 "###);
357}
358
359#[test]
360fn cursed_inner_items() {
361 test_inner_items(
362 r"
363 struct S<T: Trait = [u8; { fn f() {} 0 }]>(T);
364
365 enum En {
366 Var1 {
367 t: [(); { trait Inner {} 0 }],
368 },
369
370 Var2([u16; { enum Inner {} 0 }]),
371 }
372
373 type Ty = [En; { struct Inner; 0 }];
374
375 impl En {
376 fn assoc() {
377 trait InnerTrait<T = [u8; { fn f() {} }]> {}
378 struct InnerStruct<T = [u8; { fn f() {} }]> {}
379 impl<T = [u8; { fn f() {} }]> InnerTrait for InnerStruct {}
380 }
381 }
382
383 trait Tr<T = [u8; { fn f() {} }]> {
384 type AssocTy = [u8; { fn f() {} }];
385
386 const AssocConst: [u8; { fn f() {} }];
387 }
388 ",
389 );
390}
391
392#[test]
393fn inner_item_attrs() {
394 let tree = print_item_tree(
395 r"
396 fn foo() {
397 #[on_inner]
398 fn inner() {}
399 }
400 ",
401 );
402
403 assert_snapshot!(tree, @r###"
404inner attrs: Attrs { entries: None }
405
406top-level items:
407Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(0) }
408
409inner items:
410
411for AST FileAstId::<ra_syntax::ast::generated::nodes::ModuleItem>(1):
412#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_inner"))] }, input: None }]) }]
413Function { name: Name(Text("inner")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
414
415 "###);
416}
417
418#[test]
419fn assoc_item_macros() {
420 let tree = print_item_tree(
421 r"
422 impl S {
423 items!();
424 }
425 ",
426 );
427
428 assert_snapshot!(tree, @r###"
429inner attrs: Attrs { entries: None }
430
431top-level items:
432Impl { generic_params: GenericParamsId(4294967295), 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) }
433> MacroCall { name: None, path: ModPath { kind: Plain, segments: [Name(Text("items"))] }, is_export: false, is_local_inner: false, is_builtin: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::MacroCall>(1) }
434 "###);
435}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index af2a717c9..564434ccc 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -25,6 +25,8 @@ pub mod item_scope;
25pub mod dyn_map; 25pub mod dyn_map;
26pub mod keys; 26pub mod keys;
27 27
28pub mod item_tree;
29
28pub mod adt; 30pub mod adt;
29pub mod data; 31pub mod data;
30pub mod generics; 32pub mod generics;
@@ -48,7 +50,7 @@ pub mod import_map;
48#[cfg(test)] 50#[cfg(test)]
49mod test_db; 51mod test_db;
50 52
51use std::hash::Hash; 53use std::hash::{Hash, Hasher};
52 54
53use hir_expand::{ 55use hir_expand::{
54 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,
@@ -56,10 +58,13 @@ use hir_expand::{
56}; 58};
57use ra_arena::Idx; 59use ra_arena::Idx;
58use ra_db::{impl_intern_key, salsa, CrateId}; 60use ra_db::{impl_intern_key, salsa, CrateId};
59use ra_syntax::{ast, AstNode}; 61use ra_syntax::ast;
60 62
61use crate::body::Expander;
62use crate::builtin_type::BuiltinType; 63use crate::builtin_type::BuiltinType;
64use item_tree::{
65 Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait,
66 TypeAlias, Union,
67};
63 68
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 69#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
65pub struct ModuleId { 70pub struct ModuleId {
@@ -70,16 +75,62 @@ pub struct ModuleId {
70/// An ID of a module, **local** to a specific crate 75/// An ID of a module, **local** to a specific crate
71pub type LocalModuleId = Idx<nameres::ModuleData>; 76pub type LocalModuleId = Idx<nameres::ModuleData>;
72 77
73#[derive(Debug, Clone, PartialEq, Eq, Hash)] 78#[derive(Debug)]
74pub struct ItemLoc<N: AstNode> { 79pub struct ItemLoc<N: ItemTreeNode> {
75 pub container: ContainerId, 80 pub container: ContainerId,
76 pub ast_id: AstId<N>, 81 pub id: ItemTreeId<N>,
82}
83
84impl<N: ItemTreeNode> Clone for ItemLoc<N> {
85 fn clone(&self) -> Self {
86 Self { container: self.container, id: self.id }
87 }
77} 88}
78 89
79#[derive(Debug, Clone, PartialEq, Eq, Hash)] 90impl<N: ItemTreeNode> Copy for ItemLoc<N> {}
80pub struct AssocItemLoc<N: AstNode> { 91
92impl<N: ItemTreeNode> PartialEq for ItemLoc<N> {
93 fn eq(&self, other: &Self) -> bool {
94 self.container == other.container && self.id == other.id
95 }
96}
97
98impl<N: ItemTreeNode> Eq for ItemLoc<N> {}
99
100impl<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)]
108pub struct AssocItemLoc<N: ItemTreeNode> {
81 pub container: AssocContainerId, 109 pub container: AssocContainerId,
82 pub ast_id: AstId<N>, 110 pub id: ItemTreeId<N>,
111}
112
113impl<N: ItemTreeNode> Clone for AssocItemLoc<N> {
114 fn clone(&self) -> Self {
115 Self { container: self.container, id: self.id }
116 }
117}
118
119impl<N: ItemTreeNode> Copy for AssocItemLoc<N> {}
120
121impl<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
127impl<N: ItemTreeNode> Eq for AssocItemLoc<N> {}
128
129impl<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 }
83} 134}
84 135
85macro_rules! impl_intern { 136macro_rules! impl_intern {
@@ -104,22 +155,22 @@ macro_rules! impl_intern {
104 155
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 156#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
106pub struct FunctionId(salsa::InternId); 157pub struct FunctionId(salsa::InternId);
107type FunctionLoc = AssocItemLoc<ast::FnDef>; 158type FunctionLoc = AssocItemLoc<Function>;
108impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); 159impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
109 160
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 161#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
111pub struct StructId(salsa::InternId); 162pub struct StructId(salsa::InternId);
112type StructLoc = ItemLoc<ast::StructDef>; 163type StructLoc = ItemLoc<Struct>;
113impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); 164impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
114 165
115#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 166#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
116pub struct UnionId(salsa::InternId); 167pub struct UnionId(salsa::InternId);
117pub type UnionLoc = ItemLoc<ast::UnionDef>; 168pub type UnionLoc = ItemLoc<Union>;
118impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); 169impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
119 170
120#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 171#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
121pub struct EnumId(salsa::InternId); 172pub struct EnumId(salsa::InternId);
122pub type EnumLoc = ItemLoc<ast::EnumDef>; 173pub type EnumLoc = ItemLoc<Enum>;
123impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); 174impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
124 175
125// FIXME: rename to `VariantId`, only enums can ave variants 176// FIXME: rename to `VariantId`, only enums can ave variants
@@ -141,27 +192,27 @@ pub type LocalFieldId = Idx<adt::FieldData>;
141 192
142#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 193#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
143pub struct ConstId(salsa::InternId); 194pub struct ConstId(salsa::InternId);
144type ConstLoc = AssocItemLoc<ast::ConstDef>; 195type ConstLoc = AssocItemLoc<Const>;
145impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const); 196impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
146 197
147#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 198#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
148pub struct StaticId(salsa::InternId); 199pub struct StaticId(salsa::InternId);
149pub type StaticLoc = ItemLoc<ast::StaticDef>; 200pub type StaticLoc = ItemLoc<Static>;
150impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); 201impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
151 202
152#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 203#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
153pub struct TraitId(salsa::InternId); 204pub struct TraitId(salsa::InternId);
154pub type TraitLoc = ItemLoc<ast::TraitDef>; 205pub type TraitLoc = ItemLoc<Trait>;
155impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); 206impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
156 207
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 208#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
158pub struct TypeAliasId(salsa::InternId); 209pub struct TypeAliasId(salsa::InternId);
159type TypeAliasLoc = AssocItemLoc<ast::TypeAliasDef>; 210type TypeAliasLoc = AssocItemLoc<TypeAlias>;
160impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias); 211impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias);
161 212
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] 213#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
163pub struct ImplId(salsa::InternId); 214pub struct ImplId(salsa::InternId);
164type ImplLoc = ItemLoc<ast::ImplDef>; 215type ImplLoc = ItemLoc<Impl>;
165impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); 216impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
166 217
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 218#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -365,7 +416,7 @@ impl HasModule for AssocContainerId {
365 } 416 }
366} 417}
367 418
368impl<N: AstNode> HasModule for AssocItemLoc<N> { 419impl<N: ItemTreeNode> HasModule for AssocItemLoc<N> {
369 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { 420 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
370 self.container.module(db) 421 self.container.module(db)
371 } 422 }
@@ -392,6 +443,16 @@ impl HasModule for DefWithBodyId {
392 } 443 }
393} 444}
394 445
446impl 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
395impl HasModule for GenericDefId { 456impl HasModule for GenericDefId {
396 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { 457 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
397 match self { 458 match self {
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index 060273db4..b279bdeef 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -47,7 +47,6 @@
47//! path and, upon success, we run macro expansion and "collect module" phase on 47//! path and, upon success, we run macro expansion and "collect module" phase on
48//! the result 48//! the result
49 49
50pub(crate) mod raw;
51mod collector; 50mod collector;
52mod mod_resolution; 51mod mod_resolution;
53mod path_resolution; 52mod path_resolution;
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index cbce04315..94da700ad 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -4,6 +4,7 @@
4//! resolves imports and expands macros. 4//! resolves imports and expands macros.
5 5
6use hir_expand::{ 6use hir_expand::{
7 ast_id_map::FileAstId,
7 builtin_derive::find_builtin_derive, 8 builtin_derive::find_builtin_derive,
8 builtin_macro::find_builtin_macro, 9 builtin_macro::find_builtin_macro,
9 name::{name, AsName, Name}, 10 name::{name, AsName, Name},
@@ -19,13 +20,16 @@ use test_utils::mark;
19use crate::{ 20use crate::{
20 attr::Attrs, 21 attr::Attrs,
21 db::DefDatabase, 22 db::DefDatabase,
23 item_tree::{
24 self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind,
25 },
22 nameres::{ 26 nameres::{
23 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, 27 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
24 raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, 28 BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode,
25 }, 29 },
26 path::{ImportAlias, ModPath, PathKind}, 30 path::{ImportAlias, ModPath, PathKind},
27 per_ns::PerNs, 31 per_ns::PerNs,
28 visibility::Visibility, 32 visibility::{RawVisibility, Visibility},
29 AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId, 33 AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId,
30 FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, 34 FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc,
31 TraitLoc, TypeAliasLoc, UnionLoc, 35 TraitLoc, TypeAliasLoc, UnionLoc,
@@ -102,10 +106,50 @@ impl PartialResolvedImport {
102} 106}
103 107
104#[derive(Clone, Debug, Eq, PartialEq)] 108#[derive(Clone, Debug, Eq, PartialEq)]
109struct Import {
110 pub path: ModPath,
111 pub alias: Option<ImportAlias>,
112 pub visibility: RawVisibility,
113 pub is_glob: bool,
114 pub is_prelude: bool,
115 pub is_extern_crate: bool,
116 pub is_macro_use: bool,
117}
118
119impl Import {
120 fn from_use(tree: &ItemTree, id: FileItemTreeId<item_tree::Import>) -> Self {
121 let it = &tree[id];
122 let visibility = &tree[it.visibility];
123 Self {
124 path: it.path.clone(),
125 alias: it.alias.clone(),
126 visibility: visibility.clone(),
127 is_glob: it.is_glob,
128 is_prelude: it.is_prelude,
129 is_extern_crate: false,
130 is_macro_use: false,
131 }
132 }
133
134 fn from_extern_crate(tree: &ItemTree, id: FileItemTreeId<item_tree::ExternCrate>) -> Self {
135 let it = &tree[id];
136 let visibility = &tree[it.visibility];
137 Self {
138 path: it.path.clone(),
139 alias: it.alias.clone(),
140 visibility: visibility.clone(),
141 is_glob: false,
142 is_prelude: false,
143 is_extern_crate: true,
144 is_macro_use: it.is_macro_use,
145 }
146 }
147}
148
149#[derive(Clone, Debug, Eq, PartialEq)]
105struct ImportDirective { 150struct ImportDirective {
106 module_id: LocalModuleId, 151 module_id: LocalModuleId,
107 import_id: raw::Import, 152 import: Import,
108 import: raw::ImportData,
109 status: PartialResolvedImport, 153 status: PartialResolvedImport,
110} 154}
111 155
@@ -123,6 +167,13 @@ struct DeriveDirective {
123 ast_id: AstIdWithPath<ast::ModuleItem>, 167 ast_id: AstIdWithPath<ast::ModuleItem>,
124} 168}
125 169
170struct DefData<'a> {
171 id: ModuleDefId,
172 name: &'a Name,
173 visibility: &'a RawVisibility,
174 has_constructor: bool,
175}
176
126/// Walks the tree of module recursively 177/// Walks the tree of module recursively
127struct DefCollector<'a> { 178struct DefCollector<'a> {
128 db: &'a dyn DefDatabase, 179 db: &'a dyn DefDatabase,
@@ -140,7 +191,7 @@ struct DefCollector<'a> {
140impl DefCollector<'_> { 191impl DefCollector<'_> {
141 fn collect(&mut self) { 192 fn collect(&mut self) {
142 let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; 193 let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id;
143 let raw_items = self.db.raw_items(file_id.into()); 194 let item_tree = self.db.item_tree(file_id.into());
144 let module_id = self.def_map.root; 195 let module_id = self.def_map.root;
145 self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; 196 self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
146 ModCollector { 197 ModCollector {
@@ -148,10 +199,10 @@ impl DefCollector<'_> {
148 macro_depth: 0, 199 macro_depth: 0,
149 module_id, 200 module_id,
150 file_id: file_id.into(), 201 file_id: file_id.into(),
151 raw_items: &raw_items, 202 item_tree: &item_tree,
152 mod_dir: ModDir::root(), 203 mod_dir: ModDir::root(),
153 } 204 }
154 .collect(raw_items.items()); 205 .collect(item_tree.top_level_items());
155 206
156 // main name resolution fixed-point loop. 207 // main name resolution fixed-point loop.
157 let mut i = 0; 208 let mut i = 0;
@@ -286,7 +337,7 @@ impl DefCollector<'_> {
286 fn import_macros_from_extern_crate( 337 fn import_macros_from_extern_crate(
287 &mut self, 338 &mut self,
288 current_module_id: LocalModuleId, 339 current_module_id: LocalModuleId,
289 import: &raw::ImportData, 340 import: &item_tree::ExternCrate,
290 ) { 341 ) {
291 log::debug!( 342 log::debug!(
292 "importing macros from extern crate: {:?} ({:?})", 343 "importing macros from extern crate: {:?} ({:?})",
@@ -352,11 +403,7 @@ impl DefCollector<'_> {
352 } 403 }
353 } 404 }
354 405
355 fn resolve_import( 406 fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport {
356 &self,
357 module_id: LocalModuleId,
358 import: &raw::ImportData,
359 ) -> PartialResolvedImport {
360 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 407 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
361 if import.is_extern_crate { 408 if import.is_extern_crate {
362 let res = self.def_map.resolve_name_in_extern_prelude( 409 let res = self.def_map.resolve_name_in_extern_prelude(
@@ -649,17 +696,17 @@ impl DefCollector<'_> {
649 depth: usize, 696 depth: usize,
650 ) { 697 ) {
651 let file_id: HirFileId = macro_call_id.as_file(); 698 let file_id: HirFileId = macro_call_id.as_file();
652 let raw_items = self.db.raw_items(file_id); 699 let item_tree = self.db.item_tree(file_id);
653 let mod_dir = self.mod_dirs[&module_id].clone(); 700 let mod_dir = self.mod_dirs[&module_id].clone();
654 ModCollector { 701 ModCollector {
655 def_collector: &mut *self, 702 def_collector: &mut *self,
656 macro_depth: depth, 703 macro_depth: depth,
657 file_id, 704 file_id,
658 module_id, 705 module_id,
659 raw_items: &raw_items, 706 item_tree: &item_tree,
660 mod_dir, 707 mod_dir,
661 } 708 }
662 .collect(raw_items.items()); 709 .collect(item_tree.top_level_items());
663 } 710 }
664 711
665 fn finish(self) -> CrateDefMap { 712 fn finish(self) -> CrateDefMap {
@@ -673,12 +720,12 @@ struct ModCollector<'a, 'b> {
673 macro_depth: usize, 720 macro_depth: usize,
674 module_id: LocalModuleId, 721 module_id: LocalModuleId,
675 file_id: HirFileId, 722 file_id: HirFileId,
676 raw_items: &'a raw::RawItems, 723 item_tree: &'a ItemTree,
677 mod_dir: ModDir, 724 mod_dir: ModDir,
678} 725}
679 726
680impl ModCollector<'_, '_> { 727impl ModCollector<'_, '_> {
681 fn collect(&mut self, items: &[raw::RawItem]) { 728 fn collect(&mut self, items: &[ModItem]) {
682 // Note: don't assert that inserted value is fresh: it's simply not true 729 // Note: don't assert that inserted value is fresh: it's simply not true
683 // for macros. 730 // for macros.
684 self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone()); 731 self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
@@ -695,64 +742,204 @@ impl ModCollector<'_, '_> {
695 // `#[macro_use] extern crate` is hoisted to imports macros before collecting 742 // `#[macro_use] extern crate` is hoisted to imports macros before collecting
696 // any other items. 743 // any other items.
697 for item in items { 744 for item in items {
698 if self.is_cfg_enabled(&item.attrs) { 745 if self.is_cfg_enabled(self.item_tree.attrs(*item)) {
699 if let raw::RawItemKind::Import(import_id) = item.kind { 746 if let ModItem::ExternCrate(id) = item {
700 let import = self.raw_items[import_id].clone(); 747 let import = self.item_tree[*id].clone();
701 if import.is_extern_crate && import.is_macro_use { 748 if import.is_macro_use {
702 self.def_collector.import_macros_from_extern_crate(self.module_id, &import); 749 self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
703 } 750 }
704 } 751 }
705 } 752 }
706 } 753 }
707 754
708 for item in items { 755 for &item in items {
709 if self.is_cfg_enabled(&item.attrs) { 756 let attrs = self.item_tree.attrs(item);
710 match item.kind { 757 if self.is_cfg_enabled(attrs) {
711 raw::RawItemKind::Module(m) => { 758 let module =
712 self.collect_module(&self.raw_items[m], &item.attrs) 759 ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
713 } 760 let container = ContainerId::ModuleId(module);
714 raw::RawItemKind::Import(import_id) => { 761
762 let mut def = None;
763 match item {
764 ModItem::Mod(m) => self.collect_module(&self.item_tree[m], attrs),
765 ModItem::Import(import_id) => {
715 self.def_collector.unresolved_imports.push(ImportDirective { 766 self.def_collector.unresolved_imports.push(ImportDirective {
716 module_id: self.module_id, 767 module_id: self.module_id,
717 import_id, 768 import: Import::from_use(&self.item_tree, import_id),
718 import: self.raw_items[import_id].clone(),
719 status: PartialResolvedImport::Unresolved, 769 status: PartialResolvedImport::Unresolved,
720 }) 770 })
721 } 771 }
722 raw::RawItemKind::Def(def) => { 772 ModItem::ExternCrate(import_id) => {
723 self.define_def(&self.raw_items[def], &item.attrs) 773 self.def_collector.unresolved_imports.push(ImportDirective {
774 module_id: self.module_id,
775 import: Import::from_extern_crate(&self.item_tree, import_id),
776 status: PartialResolvedImport::Unresolved,
777 })
724 } 778 }
725 raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), 779 ModItem::MacroCall(mac) => self.collect_macro(&self.item_tree[mac]),
726 raw::RawItemKind::Impl(imp) => { 780 ModItem::Impl(imp) => {
727 let module = ModuleId { 781 let module = ModuleId {
728 krate: self.def_collector.def_map.krate, 782 krate: self.def_collector.def_map.krate,
729 local_id: self.module_id, 783 local_id: self.module_id,
730 }; 784 };
731 let container = ContainerId::ModuleId(module); 785 let container = ContainerId::ModuleId(module);
732 let ast_id = self.raw_items[imp].ast_id; 786 let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) }
733 let impl_id = 787 .intern(self.def_collector.db);
734 ImplLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
735 .intern(self.def_collector.db);
736 self.def_collector.def_map.modules[self.module_id] 788 self.def_collector.def_map.modules[self.module_id]
737 .scope 789 .scope
738 .define_impl(impl_id) 790 .define_impl(impl_id)
739 } 791 }
792 ModItem::Function(id) => {
793 let func = &self.item_tree[id];
794 def = Some(DefData {
795 id: FunctionLoc {
796 container: container.into(),
797 id: ItemTreeId::new(self.file_id, id),
798 }
799 .intern(self.def_collector.db)
800 .into(),
801 name: &func.name,
802 visibility: &self.item_tree[func.visibility],
803 has_constructor: false,
804 });
805 }
806 ModItem::Struct(id) => {
807 let it = &self.item_tree[id];
808
809 // FIXME: check attrs to see if this is an attribute macro invocation;
810 // in which case we don't add the invocation, just a single attribute
811 // macro invocation
812 self.collect_derives(attrs, it.ast_id.upcast());
813
814 def = Some(DefData {
815 id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) }
816 .intern(self.def_collector.db)
817 .into(),
818 name: &it.name,
819 visibility: &self.item_tree[it.visibility],
820 has_constructor: it.kind != StructDefKind::Record,
821 });
822 }
823 ModItem::Union(id) => {
824 let it = &self.item_tree[id];
825
826 // FIXME: check attrs to see if this is an attribute macro invocation;
827 // in which case we don't add the invocation, just a single attribute
828 // macro invocation
829 self.collect_derives(attrs, it.ast_id.upcast());
830
831 def = Some(DefData {
832 id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) }
833 .intern(self.def_collector.db)
834 .into(),
835 name: &it.name,
836 visibility: &self.item_tree[it.visibility],
837 has_constructor: false,
838 });
839 }
840 ModItem::Enum(id) => {
841 let it = &self.item_tree[id];
842
843 // FIXME: check attrs to see if this is an attribute macro invocation;
844 // in which case we don't add the invocation, just a single attribute
845 // macro invocation
846 self.collect_derives(attrs, it.ast_id.upcast());
847
848 def = Some(DefData {
849 id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) }
850 .intern(self.def_collector.db)
851 .into(),
852 name: &it.name,
853 visibility: &self.item_tree[it.visibility],
854 has_constructor: false,
855 });
856 }
857 ModItem::Const(id) => {
858 let it = &self.item_tree[id];
859
860 if let Some(name) = &it.name {
861 def = Some(DefData {
862 id: ConstLoc {
863 container: container.into(),
864 id: ItemTreeId::new(self.file_id, id),
865 }
866 .intern(self.def_collector.db)
867 .into(),
868 name,
869 visibility: &self.item_tree[it.visibility],
870 has_constructor: false,
871 });
872 }
873 }
874 ModItem::Static(id) => {
875 let it = &self.item_tree[id];
876
877 def = Some(DefData {
878 id: StaticLoc { container, id: ItemTreeId::new(self.file_id, id) }
879 .intern(self.def_collector.db)
880 .into(),
881 name: &it.name,
882 visibility: &self.item_tree[it.visibility],
883 has_constructor: false,
884 });
885 }
886 ModItem::Trait(id) => {
887 let it = &self.item_tree[id];
888
889 def = Some(DefData {
890 id: TraitLoc { container, id: ItemTreeId::new(self.file_id, id) }
891 .intern(self.def_collector.db)
892 .into(),
893 name: &it.name,
894 visibility: &self.item_tree[it.visibility],
895 has_constructor: false,
896 });
897 }
898 ModItem::TypeAlias(id) => {
899 let it = &self.item_tree[id];
900
901 def = Some(DefData {
902 id: TypeAliasLoc {
903 container: container.into(),
904 id: ItemTreeId::new(self.file_id, id),
905 }
906 .intern(self.def_collector.db)
907 .into(),
908 name: &it.name,
909 visibility: &self.item_tree[it.visibility],
910 has_constructor: false,
911 });
912 }
913 }
914
915 if let Some(DefData { id, name, visibility, has_constructor }) = def {
916 self.def_collector.def_map.modules[self.module_id].scope.define_def(id);
917 let vis = self
918 .def_collector
919 .def_map
920 .resolve_visibility(self.def_collector.db, self.module_id, visibility)
921 .unwrap_or(Visibility::Public);
922 self.def_collector.update(
923 self.module_id,
924 &[(name.clone(), PerNs::from_def(id, vis, has_constructor))],
925 vis,
926 )
740 } 927 }
741 } 928 }
742 } 929 }
743 } 930 }
744 931
745 fn collect_module(&mut self, module: &raw::ModuleData, attrs: &Attrs) { 932 fn collect_module(&mut self, module: &Mod, attrs: &Attrs) {
746 let path_attr = attrs.by_key("path").string_value(); 933 let path_attr = attrs.by_key("path").string_value();
747 let is_macro_use = attrs.by_key("macro_use").exists(); 934 let is_macro_use = attrs.by_key("macro_use").exists();
748 match module { 935 match &module.kind {
749 // inline module, just recurse 936 // inline module, just recurse
750 raw::ModuleData::Definition { name, visibility, items, ast_id } => { 937 ModKind::Inline { items } => {
751 let module_id = self.push_child_module( 938 let module_id = self.push_child_module(
752 name.clone(), 939 module.name.clone(),
753 AstId::new(self.file_id, *ast_id), 940 AstId::new(self.file_id, module.ast_id),
754 None, 941 None,
755 &visibility, 942 &self.item_tree[module.visibility],
756 ); 943 );
757 944
758 ModCollector { 945 ModCollector {
@@ -760,8 +947,8 @@ impl ModCollector<'_, '_> {
760 macro_depth: self.macro_depth, 947 macro_depth: self.macro_depth,
761 module_id, 948 module_id,
762 file_id: self.file_id, 949 file_id: self.file_id,
763 raw_items: self.raw_items, 950 item_tree: self.item_tree,
764 mod_dir: self.mod_dir.descend_into_definition(name, path_attr), 951 mod_dir: self.mod_dir.descend_into_definition(&module.name, path_attr),
765 } 952 }
766 .collect(&*items); 953 .collect(&*items);
767 if is_macro_use { 954 if is_macro_use {
@@ -769,31 +956,31 @@ impl ModCollector<'_, '_> {
769 } 956 }
770 } 957 }
771 // out of line module, resolve, parse and recurse 958 // out of line module, resolve, parse and recurse
772 raw::ModuleData::Declaration { name, visibility, ast_id } => { 959 ModKind::Outline {} => {
773 let ast_id = AstId::new(self.file_id, *ast_id); 960 let ast_id = AstId::new(self.file_id, module.ast_id);
774 match self.mod_dir.resolve_declaration( 961 match self.mod_dir.resolve_declaration(
775 self.def_collector.db, 962 self.def_collector.db,
776 self.file_id, 963 self.file_id,
777 name, 964 &module.name,
778 path_attr, 965 path_attr,
779 ) { 966 ) {
780 Ok((file_id, is_mod_rs, mod_dir)) => { 967 Ok((file_id, is_mod_rs, mod_dir)) => {
781 let module_id = self.push_child_module( 968 let module_id = self.push_child_module(
782 name.clone(), 969 module.name.clone(),
783 ast_id, 970 ast_id,
784 Some((file_id, is_mod_rs)), 971 Some((file_id, is_mod_rs)),
785 &visibility, 972 &self.item_tree[module.visibility],
786 ); 973 );
787 let raw_items = self.def_collector.db.raw_items(file_id.into()); 974 let item_tree = self.def_collector.db.item_tree(file_id.into());
788 ModCollector { 975 ModCollector {
789 def_collector: &mut *self.def_collector, 976 def_collector: &mut *self.def_collector,
790 macro_depth: self.macro_depth, 977 macro_depth: self.macro_depth,
791 module_id, 978 module_id,
792 file_id: file_id.into(), 979 file_id: file_id.into(),
793 raw_items: &raw_items, 980 item_tree: &item_tree,
794 mod_dir, 981 mod_dir,
795 } 982 }
796 .collect(raw_items.items()); 983 .collect(item_tree.top_level_items());
797 if is_macro_use { 984 if is_macro_use {
798 self.import_all_legacy_macros(module_id); 985 self.import_all_legacy_macros(module_id);
799 } 986 }
@@ -842,77 +1029,7 @@ impl ModCollector<'_, '_> {
842 res 1029 res
843 } 1030 }
844 1031
845 fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) { 1032 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::ModuleItem>) {
846 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
847 // FIXME: check attrs to see if this is an attribute macro invocation;
848 // in which case we don't add the invocation, just a single attribute
849 // macro invocation
850 self.collect_derives(attrs, def);
851
852 let name = def.name.clone();
853 let container = ContainerId::ModuleId(module);
854 let vis = &def.visibility;
855 let mut has_constructor = false;
856
857 let def: ModuleDefId = match def.kind {
858 raw::DefKind::Function(ast_id) => FunctionLoc {
859 container: container.into(),
860 ast_id: AstId::new(self.file_id, ast_id),
861 }
862 .intern(self.def_collector.db)
863 .into(),
864 raw::DefKind::Struct(ast_id, mode) => {
865 has_constructor = mode != raw::StructDefKind::Record;
866 StructLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
867 .intern(self.def_collector.db)
868 .into()
869 }
870 raw::DefKind::Union(ast_id) => {
871 UnionLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
872 .intern(self.def_collector.db)
873 .into()
874 }
875 raw::DefKind::Enum(ast_id) => {
876 EnumLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
877 .intern(self.def_collector.db)
878 .into()
879 }
880 raw::DefKind::Const(ast_id) => {
881 ConstLoc { container: container.into(), ast_id: AstId::new(self.file_id, ast_id) }
882 .intern(self.def_collector.db)
883 .into()
884 }
885 raw::DefKind::Static(ast_id) => {
886 StaticLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
887 .intern(self.def_collector.db)
888 .into()
889 }
890 raw::DefKind::Trait(ast_id) => {
891 TraitLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
892 .intern(self.def_collector.db)
893 .into()
894 }
895 raw::DefKind::TypeAlias(ast_id) => TypeAliasLoc {
896 container: container.into(),
897 ast_id: AstId::new(self.file_id, ast_id),
898 }
899 .intern(self.def_collector.db)
900 .into(),
901 };
902 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
903 let vis = self
904 .def_collector
905 .def_map
906 .resolve_visibility(self.def_collector.db, self.module_id, vis)
907 .unwrap_or(Visibility::Public);
908 self.def_collector.update(
909 self.module_id,
910 &[(name, PerNs::from_def(def, vis, has_constructor))],
911 vis,
912 )
913 }
914
915 fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) {
916 for derive_subtree in attrs.by_key("derive").tt_values() { 1033 for derive_subtree in attrs.by_key("derive").tt_values() {
917 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree 1034 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
918 for tt in &derive_subtree.token_trees { 1035 for tt in &derive_subtree.token_trees {
@@ -923,7 +1040,7 @@ impl ModCollector<'_, '_> {
923 }; 1040 };
924 let path = ModPath::from_tt_ident(ident); 1041 let path = ModPath::from_tt_ident(ident);
925 1042
926 let ast_id = AstIdWithPath::new(self.file_id, def.kind.ast_id(), path); 1043 let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
927 self.def_collector 1044 self.def_collector
928 .unexpanded_attribute_macros 1045 .unexpanded_attribute_macros
929 .push(DeriveDirective { module_id: self.module_id, ast_id }); 1046 .push(DeriveDirective { module_id: self.module_id, ast_id });
@@ -931,11 +1048,11 @@ impl ModCollector<'_, '_> {
931 } 1048 }
932 } 1049 }
933 1050
934 fn collect_macro(&mut self, mac: &raw::MacroData) { 1051 fn collect_macro(&mut self, mac: &MacroCall) {
935 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); 1052 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
936 1053
937 // Case 0: builtin macros 1054 // Case 0: builtin macros
938 if mac.builtin { 1055 if mac.is_builtin {
939 if let Some(name) = &mac.name { 1056 if let Some(name) = &mac.name {
940 let krate = self.def_collector.def_map.krate; 1057 let krate = self.def_collector.def_map.krate;
941 if let Some(macro_id) = find_builtin_macro(name, krate, ast_id.ast_id) { 1058 if let Some(macro_id) = find_builtin_macro(name, krate, ast_id.ast_id) {
@@ -943,7 +1060,7 @@ impl ModCollector<'_, '_> {
943 self.module_id, 1060 self.module_id,
944 name.clone(), 1061 name.clone(),
945 macro_id, 1062 macro_id,
946 mac.export, 1063 mac.is_export,
947 ); 1064 );
948 return; 1065 return;
949 } 1066 }
@@ -957,9 +1074,14 @@ impl ModCollector<'_, '_> {
957 ast_id: Some(ast_id.ast_id), 1074 ast_id: Some(ast_id.ast_id),
958 krate: Some(self.def_collector.def_map.krate), 1075 krate: Some(self.def_collector.def_map.krate),
959 kind: MacroDefKind::Declarative, 1076 kind: MacroDefKind::Declarative,
960 local_inner: mac.local_inner, 1077 local_inner: mac.is_local_inner,
961 }; 1078 };
962 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); 1079 self.def_collector.define_macro(
1080 self.module_id,
1081 name.clone(),
1082 macro_id,
1083 mac.is_export,
1084 );
963 } 1085 }
964 return; 1086 return;
965 } 1087 }
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
deleted file mode 100644
index f44baa579..000000000
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ /dev/null
@@ -1,482 +0,0 @@
1//! Lowers syntax tree of a rust file into a raw representation of containing
2//! items, *without* attaching them to a module structure.
3//!
4//! That is, raw items don't have semantics, just as syntax, but, unlike syntax,
5//! they don't change with trivial source code edits, making them a great tool
6//! for building salsa recomputation firewalls.
7
8use std::{ops::Index, sync::Arc};
9
10use hir_expand::{
11 ast_id_map::AstIdMap,
12 hygiene::Hygiene,
13 name::{AsName, Name},
14};
15use ra_arena::{Arena, Idx};
16use ra_prof::profile;
17use ra_syntax::{
18 ast::{self, AttrsOwner, NameOwner, VisibilityOwner},
19 AstNode,
20};
21use test_utils::mark;
22
23use crate::{
24 attr::Attrs,
25 db::DefDatabase,
26 path::{ImportAlias, ModPath},
27 visibility::RawVisibility,
28 FileAstId, HirFileId, InFile,
29};
30
31/// `RawItems` is a set of top-level items in a file (except for impls).
32///
33/// It is the input to name resolution algorithm. `RawItems` are not invalidated
34/// on most edits.
35#[derive(Debug, Default, PartialEq, Eq)]
36pub struct RawItems {
37 modules: Arena<ModuleData>,
38 imports: Arena<ImportData>,
39 defs: Arena<DefData>,
40 macros: Arena<MacroData>,
41 impls: Arena<ImplData>,
42 /// items for top-level module
43 items: Vec<RawItem>,
44}
45
46impl RawItems {
47 pub(crate) fn raw_items_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<RawItems> {
48 let _p = profile("raw_items_query");
49 let mut collector = RawItemsCollector {
50 raw_items: RawItems::default(),
51 source_ast_id_map: db.ast_id_map(file_id),
52 file_id,
53 hygiene: Hygiene::new(db.upcast(), file_id),
54 };
55 if let Some(node) = db.parse_or_expand(file_id) {
56 if let Some(source_file) = ast::SourceFile::cast(node.clone()) {
57 collector.process_module(None, source_file);
58 } else if let Some(item_list) = ast::MacroItems::cast(node) {
59 collector.process_module(None, item_list);
60 }
61 }
62 let raw_items = collector.raw_items;
63 Arc::new(raw_items)
64 }
65
66 pub(super) fn items(&self) -> &[RawItem] {
67 &self.items
68 }
69}
70
71impl Index<Idx<ModuleData>> for RawItems {
72 type Output = ModuleData;
73 fn index(&self, idx: Idx<ModuleData>) -> &ModuleData {
74 &self.modules[idx]
75 }
76}
77
78impl Index<Import> for RawItems {
79 type Output = ImportData;
80 fn index(&self, idx: Import) -> &ImportData {
81 &self.imports[idx]
82 }
83}
84
85impl Index<Idx<DefData>> for RawItems {
86 type Output = DefData;
87 fn index(&self, idx: Idx<DefData>) -> &DefData {
88 &self.defs[idx]
89 }
90}
91
92impl Index<Idx<MacroData>> for RawItems {
93 type Output = MacroData;
94 fn index(&self, idx: Idx<MacroData>) -> &MacroData {
95 &self.macros[idx]
96 }
97}
98
99impl Index<Idx<ImplData>> for RawItems {
100 type Output = ImplData;
101 fn index(&self, idx: Idx<ImplData>) -> &ImplData {
102 &self.impls[idx]
103 }
104}
105
106#[derive(Debug, PartialEq, Eq, Clone)]
107pub(super) struct RawItem {
108 pub(super) attrs: Attrs,
109 pub(super) kind: RawItemKind,
110}
111
112#[derive(Debug, PartialEq, Eq, Clone, Copy)]
113pub(super) enum RawItemKind {
114 Module(Idx<ModuleData>),
115 Import(Import),
116 Def(Idx<DefData>),
117 Macro(Idx<MacroData>),
118 Impl(Idx<ImplData>),
119}
120
121#[derive(Debug, PartialEq, Eq)]
122pub(super) enum ModuleData {
123 Declaration {
124 name: Name,
125 visibility: RawVisibility,
126 ast_id: FileAstId<ast::Module>,
127 },
128 Definition {
129 name: Name,
130 visibility: RawVisibility,
131 ast_id: FileAstId<ast::Module>,
132 items: Vec<RawItem>,
133 },
134}
135
136pub(crate) type Import = Idx<ImportData>;
137
138#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct ImportData {
140 pub(super) path: ModPath,
141 pub(super) alias: Option<ImportAlias>,
142 pub(super) is_glob: bool,
143 pub(super) is_prelude: bool,
144 pub(super) is_extern_crate: bool,
145 pub(super) is_macro_use: bool,
146 pub(super) visibility: RawVisibility,
147}
148
149// type Def = Idx<DefData>;
150
151#[derive(Debug, PartialEq, Eq)]
152pub(super) struct DefData {
153 pub(super) name: Name,
154 pub(super) kind: DefKind,
155 pub(super) visibility: RawVisibility,
156}
157
158#[derive(Debug, PartialEq, Eq, Clone, Copy)]
159pub(super) enum StructDefKind {
160 Record,
161 Tuple,
162 Unit,
163}
164
165#[derive(Debug, PartialEq, Eq, Clone, Copy)]
166pub(super) enum DefKind {
167 Function(FileAstId<ast::FnDef>),
168 Struct(FileAstId<ast::StructDef>, StructDefKind),
169 Union(FileAstId<ast::UnionDef>),
170 Enum(FileAstId<ast::EnumDef>),
171 Const(FileAstId<ast::ConstDef>),
172 Static(FileAstId<ast::StaticDef>),
173 Trait(FileAstId<ast::TraitDef>),
174 TypeAlias(FileAstId<ast::TypeAliasDef>),
175}
176
177impl DefKind {
178 pub fn ast_id(self) -> FileAstId<ast::ModuleItem> {
179 match self {
180 DefKind::Function(it) => it.upcast(),
181 DefKind::Struct(it, _) => it.upcast(),
182 DefKind::Union(it) => it.upcast(),
183 DefKind::Enum(it) => it.upcast(),
184 DefKind::Const(it) => it.upcast(),
185 DefKind::Static(it) => it.upcast(),
186 DefKind::Trait(it) => it.upcast(),
187 DefKind::TypeAlias(it) => it.upcast(),
188 }
189 }
190}
191
192#[derive(Debug, PartialEq, Eq)]
193pub(super) struct MacroData {
194 pub(super) ast_id: FileAstId<ast::MacroCall>,
195 pub(super) path: ModPath,
196 pub(super) name: Option<Name>,
197 pub(super) export: bool,
198 pub(super) local_inner: bool,
199 pub(super) builtin: bool,
200}
201
202#[derive(Debug, PartialEq, Eq)]
203pub(super) struct ImplData {
204 pub(super) ast_id: FileAstId<ast::ImplDef>,
205}
206
207struct RawItemsCollector {
208 raw_items: RawItems,
209 source_ast_id_map: Arc<AstIdMap>,
210 file_id: HirFileId,
211 hygiene: Hygiene,
212}
213
214impl RawItemsCollector {
215 fn process_module(
216 &mut self,
217 current_module: Option<Idx<ModuleData>>,
218 body: impl ast::ModuleItemOwner,
219 ) {
220 for item in body.items() {
221 self.add_item(current_module, item)
222 }
223 }
224
225 fn add_item(&mut self, current_module: Option<Idx<ModuleData>>, item: ast::ModuleItem) {
226 let attrs = self.parse_attrs(&item);
227 let visibility = RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene);
228 let (kind, name) = match item {
229 ast::ModuleItem::Module(module) => {
230 self.add_module(current_module, module);
231 return;
232 }
233 ast::ModuleItem::UseItem(use_item) => {
234 self.add_use_item(current_module, use_item);
235 return;
236 }
237 ast::ModuleItem::ExternCrateItem(extern_crate) => {
238 self.add_extern_crate_item(current_module, extern_crate);
239 return;
240 }
241 ast::ModuleItem::ImplDef(it) => {
242 self.add_impl(current_module, it);
243 return;
244 }
245 ast::ModuleItem::StructDef(it) => {
246 let kind = match it.kind() {
247 ast::StructKind::Record(_) => StructDefKind::Record,
248 ast::StructKind::Tuple(_) => StructDefKind::Tuple,
249 ast::StructKind::Unit => StructDefKind::Unit,
250 };
251 let id = self.source_ast_id_map.ast_id(&it);
252 let name = it.name();
253 (DefKind::Struct(id, kind), name)
254 }
255 ast::ModuleItem::UnionDef(it) => {
256 let id = self.source_ast_id_map.ast_id(&it);
257 let name = it.name();
258 (DefKind::Union(id), name)
259 }
260 ast::ModuleItem::EnumDef(it) => {
261 (DefKind::Enum(self.source_ast_id_map.ast_id(&it)), it.name())
262 }
263 ast::ModuleItem::FnDef(it) => {
264 (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name())
265 }
266 ast::ModuleItem::TraitDef(it) => {
267 (DefKind::Trait(self.source_ast_id_map.ast_id(&it)), it.name())
268 }
269 ast::ModuleItem::TypeAliasDef(it) => {
270 (DefKind::TypeAlias(self.source_ast_id_map.ast_id(&it)), it.name())
271 }
272 ast::ModuleItem::ConstDef(it) => {
273 (DefKind::Const(self.source_ast_id_map.ast_id(&it)), it.name())
274 }
275 ast::ModuleItem::StaticDef(it) => {
276 (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name())
277 }
278 ast::ModuleItem::MacroCall(it) => {
279 self.add_macro(current_module, it);
280 return;
281 }
282 ast::ModuleItem::ExternBlock(it) => {
283 self.add_extern_block(current_module, it);
284 return;
285 }
286 };
287 if let Some(name) = name {
288 let name = name.as_name();
289 let def = self.raw_items.defs.alloc(DefData { name, kind, visibility });
290 self.push_item(current_module, attrs, RawItemKind::Def(def));
291 }
292 }
293
294 fn add_extern_block(
295 &mut self,
296 current_module: Option<Idx<ModuleData>>,
297 block: ast::ExternBlock,
298 ) {
299 if let Some(items) = block.extern_item_list() {
300 for item in items.extern_items() {
301 let attrs = self.parse_attrs(&item);
302 let visibility =
303 RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene);
304 let (kind, name) = match item {
305 ast::ExternItem::FnDef(it) => {
306 (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name())
307 }
308 ast::ExternItem::StaticDef(it) => {
309 (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name())
310 }
311 };
312
313 if let Some(name) = name {
314 let name = name.as_name();
315 let def = self.raw_items.defs.alloc(DefData { name, kind, visibility });
316 self.push_item(current_module, attrs, RawItemKind::Def(def));
317 }
318 }
319 }
320 }
321
322 fn add_module(&mut self, current_module: Option<Idx<ModuleData>>, module: ast::Module) {
323 let name = match module.name() {
324 Some(it) => it.as_name(),
325 None => return,
326 };
327 let attrs = self.parse_attrs(&module);
328 let visibility = RawVisibility::from_ast_with_hygiene(module.visibility(), &self.hygiene);
329
330 let ast_id = self.source_ast_id_map.ast_id(&module);
331 if module.semicolon_token().is_some() {
332 let item =
333 self.raw_items.modules.alloc(ModuleData::Declaration { name, visibility, ast_id });
334 self.push_item(current_module, attrs, RawItemKind::Module(item));
335 return;
336 }
337
338 if let Some(item_list) = module.item_list() {
339 let item = self.raw_items.modules.alloc(ModuleData::Definition {
340 name,
341 visibility,
342 ast_id,
343 items: Vec::new(),
344 });
345 self.process_module(Some(item), item_list);
346 self.push_item(current_module, attrs, RawItemKind::Module(item));
347 return;
348 }
349 mark::hit!(name_res_works_for_broken_modules);
350 }
351
352 fn add_use_item(&mut self, current_module: Option<Idx<ModuleData>>, use_item: ast::UseItem) {
353 // FIXME: cfg_attr
354 let is_prelude = use_item.has_atom_attr("prelude_import");
355 let attrs = self.parse_attrs(&use_item);
356 let visibility = RawVisibility::from_ast_with_hygiene(use_item.visibility(), &self.hygiene);
357
358 let mut buf = Vec::new();
359 ModPath::expand_use_item(
360 InFile { value: use_item, file_id: self.file_id },
361 &self.hygiene,
362 |path, _use_tree, is_glob, alias| {
363 let import_data = ImportData {
364 path,
365 alias,
366 is_glob,
367 is_prelude,
368 is_extern_crate: false,
369 is_macro_use: false,
370 visibility: visibility.clone(),
371 };
372 buf.push(import_data);
373 },
374 );
375 for import_data in buf {
376 self.push_import(current_module, attrs.clone(), import_data);
377 }
378 }
379
380 fn add_extern_crate_item(
381 &mut self,
382 current_module: Option<Idx<ModuleData>>,
383 extern_crate: ast::ExternCrateItem,
384 ) {
385 if let Some(name_ref) = extern_crate.name_ref() {
386 let path = ModPath::from_name_ref(&name_ref);
387 let visibility =
388 RawVisibility::from_ast_with_hygiene(extern_crate.visibility(), &self.hygiene);
389 let alias = extern_crate.alias().map(|a| {
390 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
391 });
392 let attrs = self.parse_attrs(&extern_crate);
393 // FIXME: cfg_attr
394 let is_macro_use = extern_crate.has_atom_attr("macro_use");
395 let import_data = ImportData {
396 path,
397 alias,
398 is_glob: false,
399 is_prelude: false,
400 is_extern_crate: true,
401 is_macro_use,
402 visibility,
403 };
404 self.push_import(current_module, attrs, import_data);
405 }
406 }
407
408 fn add_macro(&mut self, current_module: Option<Idx<ModuleData>>, m: ast::MacroCall) {
409 let attrs = self.parse_attrs(&m);
410 let path = match m.path().and_then(|path| ModPath::from_src(path, &self.hygiene)) {
411 Some(it) => it,
412 _ => return,
413 };
414
415 let name = m.name().map(|it| it.as_name());
416 let ast_id = self.source_ast_id_map.ast_id(&m);
417
418 // FIXME: cfg_attr
419 let export_attr = attrs.by_key("macro_export");
420
421 let export = export_attr.exists();
422 let local_inner = if export {
423 export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it {
424 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
425 ident.text.contains("local_inner_macros")
426 }
427 _ => false,
428 })
429 } else {
430 false
431 };
432
433 let builtin = attrs.by_key("rustc_builtin_macro").exists();
434
435 let m = self.raw_items.macros.alloc(MacroData {
436 ast_id,
437 path,
438 name,
439 export,
440 local_inner,
441 builtin,
442 });
443 self.push_item(current_module, attrs, RawItemKind::Macro(m));
444 }
445
446 fn add_impl(&mut self, current_module: Option<Idx<ModuleData>>, imp: ast::ImplDef) {
447 let attrs = self.parse_attrs(&imp);
448 let ast_id = self.source_ast_id_map.ast_id(&imp);
449 let imp = self.raw_items.impls.alloc(ImplData { ast_id });
450 self.push_item(current_module, attrs, RawItemKind::Impl(imp))
451 }
452
453 fn push_import(
454 &mut self,
455 current_module: Option<Idx<ModuleData>>,
456 attrs: Attrs,
457 data: ImportData,
458 ) {
459 let import = self.raw_items.imports.alloc(data);
460 self.push_item(current_module, attrs, RawItemKind::Import(import))
461 }
462
463 fn push_item(
464 &mut self,
465 current_module: Option<Idx<ModuleData>>,
466 attrs: Attrs,
467 kind: RawItemKind,
468 ) {
469 match current_module {
470 Some(module) => match &mut self.raw_items.modules[module] {
471 ModuleData::Definition { items, .. } => items,
472 ModuleData::Declaration { .. } => unreachable!(),
473 },
474 None => &mut self.raw_items.items,
475 }
476 .push(RawItem { attrs, kind })
477 }
478
479 fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs {
480 Attrs::new(item, &self.hygiene)
481 }
482}
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs
index 87165ac33..0c288a108 100644
--- a/crates/ra_hir_def/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs
@@ -58,44 +58,6 @@ fn typing_inside_a_function_should_not_invalidate_def_map() {
58} 58}
59 59
60#[test] 60#[test]
61fn adding_inner_items_should_not_invalidate_def_map() {
62 check_def_map_is_not_recomputed(
63 r"
64 //- /lib.rs
65 struct S { a: i32}
66 enum E { A }
67 trait T {
68 fn a() {}
69 }
70 mod foo;<|>
71 impl S {
72 fn a() {}
73 }
74 use crate::foo::bar::Baz;
75 //- /foo/mod.rs
76 pub mod bar;
77
78 //- /foo/bar.rs
79 pub struct Baz;
80 ",
81 r"
82 struct S { a: i32, b: () }
83 enum E { A, B }
84 trait T {
85 fn a() {}
86 fn b() {}
87 }
88 mod foo;<|>
89 impl S {
90 fn a() {}
91 fn b() {}
92 }
93 use crate::foo::bar::Baz;
94 ",
95 );
96}
97
98#[test]
99fn typing_inside_a_macro_should_not_invalidate_def_map() { 61fn typing_inside_a_macro_should_not_invalidate_def_map() {
100 let (mut db, pos) = TestDB::with_position( 62 let (mut db, pos) = TestDB::with_position(
101 r" 63 r"
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 b43b294ca..e9a5e4cba 100644
--- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
@@ -20,8 +20,11 @@ fn name_res_works_for_broken_modules() {
20 ", 20 ",
21 ); 21 );
22 assert_snapshot!(map, @r###" 22 assert_snapshot!(map, @r###"
23 ⋮crate 23crate
24 ⋮Baz: _ 24Baz: _
25foo: t
26
27crate::foo
25 "###); 28 "###);
26} 29}
27 30
@@ -719,10 +722,7 @@ fn unresolved_module_diagnostics() {
719 ), 722 ),
720 ), 723 ),
721 ), 724 ),
722 value: FileAstId { 725 value: FileAstId::<ra_syntax::ast::generated::nodes::Module>(1),
723 raw: Idx::<SyntaxNodePtr>(1),
724 _ty: PhantomData,
725 },
726 }, 726 },
727 candidate: "bar.rs", 727 candidate: "bar.rs",
728 }, 728 },
diff --git a/crates/ra_hir_def/src/src.rs b/crates/ra_hir_def/src/src.rs
index 46e90da70..043b93fad 100644
--- a/crates/ra_hir_def/src/src.rs
+++ b/crates/ra_hir_def/src/src.rs
@@ -2,30 +2,37 @@
2 2
3use hir_expand::InFile; 3use hir_expand::InFile;
4use ra_arena::map::ArenaMap; 4use ra_arena::map::ArenaMap;
5use ra_syntax::AstNode;
6 5
7use crate::{db::DefDatabase, AssocItemLoc, ItemLoc}; 6use crate::{db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc};
8 7
9pub trait HasSource { 8pub 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
14impl<N: AstNode> HasSource for AssocItemLoc<N> { 13impl<N: ItemTreeNode> 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
23impl<N: AstNode> HasSource for ItemLoc<N> { 26impl<N: ItemTreeNode> 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_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs
index 1482d3be0..8136cb50c 100644
--- a/crates/ra_hir_def/src/visibility.rs
+++ b/crates/ra_hir_def/src/visibility.rs
@@ -6,7 +6,7 @@ use ra_syntax::ast;
6use crate::{ 6use crate::{
7 db::DefDatabase, 7 db::DefDatabase,
8 path::{ModPath, PathKind}, 8 path::{ModPath, PathKind},
9 AssocContainerId, ModuleId, 9 ModuleId,
10}; 10};
11 11
12/// Visibility of an item, not yet resolved. 12/// Visibility of an item, not yet resolved.
@@ -25,25 +25,6 @@ impl RawVisibility {
25 RawVisibility::Module(path) 25 RawVisibility::Module(path)
26 } 26 }
27 27
28 pub(crate) fn default_for_container(container_id: AssocContainerId) -> Self {
29 match container_id {
30 AssocContainerId::TraitId(_) => RawVisibility::Public,
31 _ => RawVisibility::private(),
32 }
33 }
34
35 pub(crate) fn from_ast_with_default(
36 db: &dyn DefDatabase,
37 default: RawVisibility,
38 node: InFile<Option<ast::Visibility>>,
39 ) -> RawVisibility {
40 Self::from_ast_with_hygiene_and_default(
41 node.value,
42 default,
43 &Hygiene::new(db.upcast(), node.file_id),
44 )
45 }
46
47 pub(crate) fn from_ast( 28 pub(crate) fn from_ast(
48 db: &dyn DefDatabase, 29 db: &dyn DefDatabase,
49 node: InFile<Option<ast::Visibility>>, 30 node: InFile<Option<ast::Visibility>>,
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
8use std::{ 8use 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};
14use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; 16use 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)]
18pub struct FileAstId<N: AstNode> { 19pub 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
43impl<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
42impl<N: AstNode> FileAstId<N> { 49impl<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..85ff26a36 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
70fn type_at(content: &str) -> String { 70fn 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).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).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).syntax().text_range().start()
174 } 180 }
175 }); 181 });
176 for def in defs { 182 for def in defs {
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs
index a95f6c13c..b507000f2 100644
--- a/crates/ra_ide_db/src/change.rs
+++ b/crates/ra_ide_db/src/change.rs
@@ -199,7 +199,7 @@ impl RootDatabase {
199 hir::db::InternEagerExpansionQuery 199 hir::db::InternEagerExpansionQuery
200 200
201 // DefDatabase 201 // DefDatabase
202 hir::db::RawItemsQuery 202 hir::db::ItemTreeQuery
203 hir::db::CrateDefMapQueryQuery 203 hir::db::CrateDefMapQueryQuery
204 hir::db::StructDataQuery 204 hir::db::StructDataQuery
205 hir::db::UnionDataQuery 205 hir::db::UnionDataQuery