aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_analysis/src/db.rs1
-rw-r--r--crates/ra_hir/src/db.rs8
-rw-r--r--crates/ra_hir/src/function.rs17
-rw-r--r--crates/ra_hir/src/ids.rs13
-rw-r--r--crates/ra_hir/src/impl_block.rs172
-rw-r--r--crates/ra_hir/src/krate.rs2
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/mock.rs1
-rw-r--r--crates/ra_hir/src/module.rs15
-rw-r--r--crates/ra_syntax/src/ast/generated.rs40
-rw-r--r--crates/ra_syntax/src/grammar.ron6
11 files changed, 269 insertions, 8 deletions
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index d7740f0c4..d7e51a597 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -105,6 +105,7 @@ salsa::database_storage! {
105 fn type_for_field() for hir::db::TypeForFieldQuery; 105 fn type_for_field() for hir::db::TypeForFieldQuery;
106 fn struct_data() for hir::db::StructDataQuery; 106 fn struct_data() for hir::db::StructDataQuery;
107 fn enum_data() for hir::db::EnumDataQuery; 107 fn enum_data() for hir::db::EnumDataQuery;
108 fn impls_in_crate() for hir::db::ImplsInCrateQuery;
108 } 109 }
109 } 110 }
110} 111}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 73a4cdc5c..6d5235ba4 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -4,7 +4,7 @@ use ra_syntax::{SyntaxNode, SourceFileNode};
4use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, Cancelable}; 4use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, Cancelable};
5 5
6use crate::{ 6use crate::{
7 DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId, 7 Crate, DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId,
8 SourceFileItems, SourceItemId, 8 SourceFileItems, SourceItemId,
9 query_definitions, 9 query_definitions,
10 FnScopes, 10 FnScopes,
@@ -13,6 +13,7 @@ use crate::{
13 nameres::{ItemMap, InputModuleItems}}, 13 nameres::{ItemMap, InputModuleItems}},
14 ty::{InferenceResult, Ty}, 14 ty::{InferenceResult, Ty},
15 adt::{StructData, EnumData}, 15 adt::{StructData, EnumData},
16 impl_block::CrateImplBlocks,
16}; 17};
17 18
18salsa::query_group! { 19salsa::query_group! {
@@ -87,6 +88,11 @@ pub trait HirDatabase: SyntaxDatabase
87 type ModuleTreeQuery; 88 type ModuleTreeQuery;
88 use fn crate::module::imp::module_tree; 89 use fn crate::module::imp::module_tree;
89 } 90 }
91
92 fn impls_in_crate(krate: Crate) -> Cancelable<Arc<CrateImplBlocks>> {
93 type ImplsInCrateQuery;
94 use fn crate::impl_block::impls_in_crate;
95 }
90} 96}
91 97
92} 98}
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs
index 5a44132fc..75ef308ae 100644
--- a/crates/ra_hir/src/function.rs
+++ b/crates/ra_hir/src/function.rs
@@ -11,11 +11,11 @@ use ra_syntax::{
11 ast::{self, AstNode, DocCommentsOwner, NameOwner}, 11 ast::{self, AstNode, DocCommentsOwner, NameOwner},
12}; 12};
13 13
14use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module}; 14use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock};
15 15
16pub use self::scope::FnScopes; 16pub use self::scope::FnScopes;
17 17
18#[derive(Debug)] 18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Function { 19pub struct Function {
20 def_id: DefId, 20 def_id: DefId,
21} 21}
@@ -25,6 +25,10 @@ impl Function {
25 Function { def_id } 25 Function { def_id }
26 } 26 }
27 27
28 pub fn def_id(&self) -> DefId {
29 self.def_id
30 }
31
28 pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode { 32 pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode {
29 let def_loc = self.def_id.loc(db); 33 let def_loc = self.def_id.loc(db);
30 assert!(def_loc.kind == DefKind::Function); 34 assert!(def_loc.kind == DefKind::Function);
@@ -48,6 +52,15 @@ impl Function {
48 pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> { 52 pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> {
49 self.def_id.module(db) 53 self.def_id.module(db)
50 } 54 }
55
56 pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
57 self.def_id.krate(db)
58 }
59
60 /// The containing impl block, if this is a method.
61 pub fn impl_block(&self, db: &impl HirDatabase) -> Cancelable<Option<ImplBlock>> {
62 self.def_id.impl_block(db)
63 }
51} 64}
52 65
53#[derive(Debug, Clone)] 66#[derive(Debug, Clone)]
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 66adacc7d..c98be66f9 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -2,7 +2,7 @@ use ra_db::{SourceRootId, LocationIntener, Cancelable, FileId};
2use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast}; 2use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast};
3use ra_arena::{Arena, RawId, impl_arena_id}; 3use ra_arena::{Arena, RawId, impl_arena_id};
4 4
5use crate::{HirDatabase, PerNs, ModuleId, Module, Def, Function, Struct, Enum}; 5use crate::{HirDatabase, PerNs, ModuleId, Module, Def, Function, Struct, Enum, ImplBlock, Crate};
6 6
7/// hir makes a heavy use of ids: integer (u32) handlers to various things. You 7/// hir makes a heavy use of ids: integer (u32) handlers to various things. You
8/// can think of id as a pointer (but without a lifetime) or a file descriptor 8/// can think of id as a pointer (but without a lifetime) or a file descriptor
@@ -177,6 +177,17 @@ impl DefId {
177 let loc = self.loc(db); 177 let loc = self.loc(db);
178 Module::new(db, loc.source_root_id, loc.module_id) 178 Module::new(db, loc.source_root_id, loc.module_id)
179 } 179 }
180
181 /// Returns the containing crate.
182 pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
183 Ok(self.module(db)?.krate(db))
184 }
185
186 /// Returns the containing impl block, if this is an impl item.
187 pub fn impl_block(self, db: &impl HirDatabase) -> Cancelable<Option<ImplBlock>> {
188 let crate_impls = db.impls_in_crate(ctry!(self.krate(db)?))?;
189 Ok(ImplBlock::containing(crate_impls, self))
190 }
180} 191}
181 192
182impl DefLoc { 193impl DefLoc {
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
new file mode 100644
index 000000000..22f0a4461
--- /dev/null
+++ b/crates/ra_hir/src/impl_block.rs
@@ -0,0 +1,172 @@
1use std::sync::Arc;
2use rustc_hash::FxHashMap;
3
4use ra_arena::{Arena, RawId, impl_arena_id};
5use ra_syntax::ast::{self, AstNode};
6use ra_db::{LocationIntener, Cancelable};
7
8use crate::{
9 Crate, DefId, DefLoc, DefKind, SourceItemId, SourceFileItems,
10 Module, Function,
11 db::HirDatabase,
12 type_ref::TypeRef,
13 module::{ModuleSourceNode},
14};
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct ImplBlock {
18 crate_impl_blocks: Arc<CrateImplBlocks>,
19 impl_id: ImplId,
20}
21
22impl ImplBlock {
23 pub(crate) fn containing(
24 crate_impl_blocks: Arc<CrateImplBlocks>,
25 def_id: DefId,
26 ) -> Option<ImplBlock> {
27 let impl_id = *crate_impl_blocks.impls_by_def.get(&def_id)?;
28 Some(ImplBlock {
29 crate_impl_blocks,
30 impl_id,
31 })
32 }
33
34 fn impl_data(&self) -> &ImplData {
35 &self.crate_impl_blocks.impls[self.impl_id]
36 }
37
38 pub fn target(&self) -> &TypeRef {
39 &self.impl_data().impl_for
40 }
41
42 pub fn items(&self) -> &[ImplItem] {
43 &self.impl_data().items
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct ImplData {
49 impl_for: TypeRef,
50 items: Vec<ImplItem>,
51}
52
53impl ImplData {
54 pub(crate) fn from_ast(
55 db: &impl AsRef<LocationIntener<DefLoc, DefId>>,
56 file_items: &SourceFileItems,
57 module: &Module,
58 node: ast::ImplBlock,
59 ) -> Self {
60 let impl_for = TypeRef::from_ast_opt(node.target_type());
61 let file_id = module.source().file_id();
62 let items = if let Some(item_list) = node.item_list() {
63 item_list
64 .impl_items()
65 .map(|item_node| {
66 let kind = match item_node {
67 ast::ImplItem::FnDef(..) => DefKind::Function,
68 ast::ImplItem::ConstDef(..) => DefKind::Item,
69 ast::ImplItem::TypeDef(..) => DefKind::Item,
70 };
71 let item_id = file_items.id_of_unchecked(item_node.syntax());
72 let def_loc = DefLoc {
73 kind,
74 source_root_id: module.source_root_id,
75 module_id: module.module_id,
76 source_item_id: SourceItemId {
77 file_id,
78 item_id: Some(item_id),
79 },
80 };
81 let def_id = def_loc.id(db);
82 match item_node {
83 ast::ImplItem::FnDef(..) => ImplItem::Method(Function::new(def_id)),
84 ast::ImplItem::ConstDef(..) => ImplItem::Const(def_id),
85 ast::ImplItem::TypeDef(..) => ImplItem::Type(def_id),
86 }
87 })
88 .collect()
89 } else {
90 Vec::new()
91 };
92 ImplData { impl_for, items }
93 }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
97pub enum ImplItem {
98 Method(Function),
99 // these don't have their own types yet
100 Const(DefId),
101 Type(DefId),
102 // Existential
103}
104
105impl ImplItem {
106 pub fn def_id(&self) -> DefId {
107 match self {
108 ImplItem::Method(f) => f.def_id(),
109 ImplItem::Const(def_id) => *def_id,
110 ImplItem::Type(def_id) => *def_id,
111 }
112 }
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
116pub struct ImplId(pub RawId);
117impl_arena_id!(ImplId);
118
119/// We have to collect all impl blocks in a crate, to later be able to find
120/// impls for specific types.
121#[derive(Debug, PartialEq, Eq)]
122pub struct CrateImplBlocks {
123 impls: Arena<ImplId, ImplData>,
124 impls_by_def: FxHashMap<DefId, ImplId>,
125}
126
127impl CrateImplBlocks {
128 fn new() -> Self {
129 CrateImplBlocks {
130 impls: Arena::default(),
131 impls_by_def: FxHashMap::default(),
132 }
133 }
134
135 fn collect(&mut self, db: &impl HirDatabase, module: Module) -> Cancelable<()> {
136 let module_source_node = module.source().resolve(db);
137 let node = match &module_source_node {
138 ModuleSourceNode::SourceFile(node) => node.borrowed().syntax(),
139 ModuleSourceNode::Module(node) => node.borrowed().syntax(),
140 };
141
142 let source_file_items = db.file_items(module.source().file_id());
143
144 for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) {
145 let impl_block = ImplData::from_ast(db, &source_file_items, &module, impl_block_ast);
146 let id = self.impls.alloc(impl_block);
147 for impl_item in &self.impls[id].items {
148 self.impls_by_def.insert(impl_item.def_id(), id);
149 }
150 }
151
152 for (_, child) in module.children() {
153 self.collect(db, child)?;
154 }
155
156 Ok(())
157 }
158}
159
160pub(crate) fn impls_in_crate(
161 db: &impl HirDatabase,
162 krate: Crate,
163) -> Cancelable<Arc<CrateImplBlocks>> {
164 let mut result = CrateImplBlocks::new();
165 let root_module = if let Some(root) = krate.root_module(db)? {
166 root
167 } else {
168 return Ok(Arc::new(result));
169 };
170 result.collect(db, root_module)?;
171 Ok(Arc::new(result))
172}
diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs
index a0821d15d..5194e280b 100644
--- a/crates/ra_hir/src/krate.rs
+++ b/crates/ra_hir/src/krate.rs
@@ -5,7 +5,7 @@ use crate::{HirDatabase, Module, Name, AsName, HirFileId};
5/// hir::Crate describes a single crate. It's the main inteface with which 5/// hir::Crate describes a single crate. It's the main inteface with which
6/// crate's dependencies interact. Mostly, it should be just a proxy for the 6/// crate's dependencies interact. Mostly, it should be just a proxy for the
7/// root module. 7/// root module.
8#[derive(Debug)] 8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub struct Crate { 9pub struct Crate {
10 crate_id: CrateId, 10 crate_id: CrateId,
11} 11}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 344b543b6..2abcec441 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -31,6 +31,7 @@ mod function;
31mod adt; 31mod adt;
32mod type_ref; 32mod type_ref;
33mod ty; 33mod ty;
34mod impl_block;
34 35
35use crate::{ 36use crate::{
36 db::HirDatabase, 37 db::HirDatabase,
@@ -48,6 +49,7 @@ pub use self::{
48 function::{Function, FnScopes}, 49 function::{Function, FnScopes},
49 adt::{Struct, Enum}, 50 adt::{Struct, Enum},
50 ty::Ty, 51 ty::Ty,
52 impl_block::{ImplBlock, ImplItem},
51}; 53};
52 54
53pub use self::function::FnSignatureInfo; 55pub use self::function::FnSignatureInfo;
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 89b18194a..ef245ec7a 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -203,6 +203,7 @@ salsa::database_storage! {
203 fn type_for_field() for db::TypeForFieldQuery; 203 fn type_for_field() for db::TypeForFieldQuery;
204 fn struct_data() for db::StructDataQuery; 204 fn struct_data() for db::StructDataQuery;
205 fn enum_data() for db::EnumDataQuery; 205 fn enum_data() for db::EnumDataQuery;
206 fn impls_in_crate() for db::ImplsInCrateQuery;
206 } 207 }
207 } 208 }
208} 209}
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs
index c70dc54dd..b9821115c 100644
--- a/crates/ra_hir/src/module.rs
+++ b/crates/ra_hir/src/module.rs
@@ -71,6 +71,21 @@ impl Module {
71 }) 71 })
72 } 72 }
73 73
74 /// Returns an iterator of all children of this module.
75 pub fn children<'a>(&'a self) -> impl Iterator<Item = (Name, Module)> + 'a {
76 self.module_id
77 .children(&self.tree)
78 .map(move |(name, module_id)| {
79 (
80 name,
81 Module {
82 module_id,
83 ..self.clone()
84 },
85 )
86 })
87 }
88
74 /// Returns the crate this module is part of. 89 /// Returns the crate this module is part of.
75 pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { 90 pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
76 let root_id = self.module_id.crate_root(&self.tree); 91 let root_id = self.module_id.crate_root(&self.tree);
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index c1c63f555..91de17ddf 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -1442,7 +1442,39 @@ impl<R: TreeRoot<RaTypes>> ImplBlockNode<R> {
1442} 1442}
1443 1443
1444 1444
1445impl<'a> ImplBlock<'a> {} 1445impl<'a> ImplBlock<'a> {
1446 pub fn item_list(self) -> Option<ItemList<'a>> {
1447 super::child_opt(self)
1448 }
1449}
1450
1451// ImplItem
1452#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1453pub enum ImplItem<'a> {
1454 FnDef(FnDef<'a>),
1455 TypeDef(TypeDef<'a>),
1456 ConstDef(ConstDef<'a>),
1457}
1458
1459impl<'a> AstNode<'a> for ImplItem<'a> {
1460 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
1461 match syntax.kind() {
1462 FN_DEF => Some(ImplItem::FnDef(FnDef { syntax })),
1463 TYPE_DEF => Some(ImplItem::TypeDef(TypeDef { syntax })),
1464 CONST_DEF => Some(ImplItem::ConstDef(ConstDef { syntax })),
1465 _ => None,
1466 }
1467 }
1468 fn syntax(self) -> SyntaxNodeRef<'a> {
1469 match self {
1470 ImplItem::FnDef(inner) => inner.syntax(),
1471 ImplItem::TypeDef(inner) => inner.syntax(),
1472 ImplItem::ConstDef(inner) => inner.syntax(),
1473 }
1474 }
1475}
1476
1477impl<'a> ImplItem<'a> {}
1446 1478
1447// ImplTraitType 1479// ImplTraitType
1448#[derive(Debug, Clone, Copy,)] 1480#[derive(Debug, Clone, Copy,)]
@@ -1555,7 +1587,11 @@ impl<R: TreeRoot<RaTypes>> ItemListNode<R> {
1555 1587
1556impl<'a> ast::FnDefOwner<'a> for ItemList<'a> {} 1588impl<'a> ast::FnDefOwner<'a> for ItemList<'a> {}
1557impl<'a> ast::ModuleItemOwner<'a> for ItemList<'a> {} 1589impl<'a> ast::ModuleItemOwner<'a> for ItemList<'a> {}
1558impl<'a> ItemList<'a> {} 1590impl<'a> ItemList<'a> {
1591 pub fn impl_items(self) -> impl Iterator<Item = ImplItem<'a>> + 'a {
1592 super::children(self)
1593 }
1594}
1559 1595
1560// Label 1596// Label
1561#[derive(Debug, Clone, Copy,)] 1597#[derive(Debug, Clone, Copy,)]
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 9a4a96fac..688a4af1e 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -284,6 +284,7 @@ Grammar(
284 options: [ "ItemList" ] 284 options: [ "ItemList" ]
285 ), 285 ),
286 "ItemList": ( 286 "ItemList": (
287 collections: [["impl_items", "ImplItem"]],
287 traits: [ "FnDefOwner", "ModuleItemOwner" ], 288 traits: [ "FnDefOwner", "ModuleItemOwner" ],
288 ), 289 ),
289 "ConstDef": ( traits: [ 290 "ConstDef": ( traits: [
@@ -307,7 +308,7 @@ Grammar(
307 "AttrsOwner", 308 "AttrsOwner",
308 "DocCommentsOwner" 309 "DocCommentsOwner"
309 ] ), 310 ] ),
310 "ImplBlock": (collections: []), 311 "ImplBlock": (options: ["ItemList"]),
311 312
312 "ParenType": (options: ["TypeRef"]), 313 "ParenType": (options: ["TypeRef"]),
313 "TupleType": ( collections: [["fields", "TypeRef"]] ), 314 "TupleType": ( collections: [["fields", "TypeRef"]] ),
@@ -351,6 +352,9 @@ Grammar(
351 enum: ["StructDef", "EnumDef", "FnDef", "TraitDef", "TypeDef", "ImplBlock", 352 enum: ["StructDef", "EnumDef", "FnDef", "TraitDef", "TypeDef", "ImplBlock",
352 "UseItem", "ExternCrateItem", "ConstDef", "StaticDef", "Module" ] 353 "UseItem", "ExternCrateItem", "ConstDef", "StaticDef", "Module" ]
353 ), 354 ),
355 "ImplItem": (
356 enum: ["FnDef", "TypeDef", "ConstDef"]
357 ),
354 358
355 "TupleExpr": (), 359 "TupleExpr": (),
356 "ArrayExpr": (), 360 "ArrayExpr": (),